/**
 * AI Assistant Tool definitions for OpenAI Function Calling.
 * Each tool has a JSON schema (for the AI) and an execute function (for the server).
 */

import { Prisma, VacationType } from "@capakraken/db";
import {
  CreateAssignmentSchema,
  AllocationStatus,
  PermissionKey,
  SystemRole,
} from "@capakraken/shared";
import type { WeekdayAvailability } from "@capakraken/shared";
import { TRPCError } from "@trpc/server";
import { ZodError } from "zod";
import { fmtEur } from "../lib/format-utils.js";
import { timelineRouter } from "./timeline.js";
import { logger } from "../lib/logger.js";
import { createCallerFactory, type TRPCContext } from "../trpc.js";
import { auditLogRouter } from "./audit-log.js";
import { chargeabilityReportRouter } from "./chargeability-report.js";
import { computationGraphRouter } from "./computation-graph.js";
import { dispoRouter } from "./dispo.js";
import { importExportRouter } from "./import-export.js";
import { resourceRouter } from "./resource.js";
import { settingsRouter } from "./settings.js";
import { systemRoleConfigRouter } from "./system-role-config.js";
import { userRouter } from "./user.js";
import { notificationRouter } from "./notification.js";
import { estimateRouter } from "./estimate.js";
import { webhookRouter } from "./webhook.js";
import { countryRouter } from "./country.js";
import { holidayCalendarRouter } from "./holiday-calendar.js";
import { blueprintRouter } from "./blueprint.js";
import { roleRouter } from "./role.js";
import { clientRouter } from "./client.js";
import { orgUnitRouter } from "./org-unit.js";
import { projectRouter } from "./project.js";
import { rateCardRouter } from "./rate-card.js";
import { reportRouter } from "./report.js";
import { vacationRouter } from "./vacation.js";
import { entitlementRouter } from "./entitlement.js";
import { commentRouter } from "./comment.js";
import { managementLevelRouter } from "./management-level.js";
import { utilizationCategoryRouter } from "./utilization-category.js";
import { calculationRuleRouter } from "./calculation-rules.js";
import { effortRuleRouter } from "./effort-rule.js";
import { experienceMultiplierRouter } from "./experience-multiplier.js";
import { dashboardRouter } from "./dashboard.js";
import { insightsRouter } from "./insights.js";
import { scenarioRouter } from "./scenario.js";
import { allocationRouter } from "./allocation.js";
import { staffingRouter } from "./staffing.js";
import { advancedTimelineToolDefinitions, createAdvancedTimelineExecutors } from "./assistant-tools/advanced-timeline.js";
import {
  allocationPlanningMutationToolDefinitions,
  allocationPlanningReadToolDefinitions,
  createAllocationPlanningExecutors,
} from "./assistant-tools/allocation-planning.js";
import { settingsAdminToolDefinitions, createSettingsAdminExecutors } from "./assistant-tools/settings-admin.js";
import {
  createVacationHolidayExecutors,
  vacationHolidayMutationToolDefinitions,
  vacationHolidayReadToolDefinitions,
} from "./assistant-tools/vacation-holidays.js";
import {
  createRolesAnalyticsExecutors,
  rolesAnalyticsMutationToolDefinitions,
  rolesAnalyticsReadToolDefinitions,
} from "./assistant-tools/roles-analytics.js";
import {
  clientMutationToolDefinitions,
  createClientsOrgUnitsExecutors,
  orgUnitMutationToolDefinitions,
} from "./assistant-tools/clients-org-units.js";
import {
  chargeabilityComputationReadToolDefinitions,
  createChargeabilityComputationExecutors,
} from "./assistant-tools/chargeability-computation.js";
import {
  configReadmodelToolDefinitions,
  createConfigReadmodelExecutors,
} from "./assistant-tools/config-readmodels.js";
import {
  countryMetroAdminToolDefinitions,
  createCountryMetroAdminExecutors,
} from "./assistant-tools/country-metro-admin.js";
import {
  countryReadmodelToolDefinitions,
  createCountryReadmodelExecutors,
} from "./assistant-tools/country-readmodels.js";
import {
  createUserSelfServiceExecutors,
  userSelfServiceToolDefinitions,
} from "./assistant-tools/user-self-service.js";
import {
  createUserAdminExecutors,
  userAdminToolDefinitions,
} from "./assistant-tools/user-admin.js";
import {
  createNotificationsTasksExecutors,
  notificationInboxToolDefinitions,
  notificationTaskToolDefinitions,
} from "./assistant-tools/notifications-tasks.js";
import {
  createEstimateExecutors,
  estimateMutationToolDefinitions,
  estimateReadToolDefinitions,
} from "./assistant-tools/estimates.js";
import {
  createProjectExecutors,
  projectMutationToolDefinitions,
  projectReadToolDefinitions,
} from "./assistant-tools/projects.js";
import {
  createStaffingDemandExecutors,
  staffingDemandMutationToolDefinitions,
  staffingDemandReadToolDefinitions,
} from "./assistant-tools/staffing-demand.js";
import {
  createResourceExecutors,
  resourceMutationToolDefinitions,
  resourceReadToolDefinitions,
} from "./assistant-tools/resources.js";
import {
  blueprintsRateCardsToolDefinitions,
  createBlueprintsRateCardsExecutors,
} from "./assistant-tools/blueprints-rate-cards.js";
import {
  createDashboardInsightsReportsExecutors,
  dashboardInsightsReportsToolDefinitions,
} from "./assistant-tools/dashboard-insights-reports.js";
import {
  createScenarioRateAnalysisExecutors,
  scenarioRateAnalysisToolDefinitions,
} from "./assistant-tools/scenario-rate-analysis.js";
import {
  createImportExportDispoExecutors,
  importExportDispoToolDefinitions,
} from "./assistant-tools/import-export-dispo.js";
import {
  commentMutationToolDefinitions,
  commentReadToolDefinitions,
  createCommentExecutors,
} from "./assistant-tools/comments.js";
import {
  auditHistoryToolDefinitions,
  createAuditHistoryExecutors,
} from "./assistant-tools/audit-history.js";
import {
  createPlanningNavigationExecutors,
  planningNavigationToolDefinitions,
} from "./assistant-tools/planning-navigation.js";
import {
  createVacationEntitlementExecutors,
  vacationEntitlementToolDefinitions,
} from "./assistant-tools/vacation-entitlements.js";
import {
  withToolAccess,
  type ToolAccessRequirements,
  type ToolContext,
  type ToolDef,
  type ToolExecutor,
} from "./assistant-tools/shared.js";

export type { ToolContext } from "./assistant-tools/shared.js";

// ─── Mutation tool set for audit logging (EGAI 4.1.3.1 / IAAI 3.6.26) ──────

export const MUTATION_TOOLS = new Set([
  "import_csv_data",
  "update_system_settings",
  "clear_stored_runtime_secrets",
  "test_ai_connection",
  "test_smtp_connection",
  "test_gemini_connection",
  "update_system_role_config",
  "create_webhook",
  "update_webhook",
  "delete_webhook",
  "test_webhook",
  "stage_dispo_import_batch",
  "cancel_dispo_import_batch",
  "resolve_dispo_staged_record",
  "commit_dispo_import_batch",
  "create_allocation", "cancel_allocation", "update_allocation_status",
  "update_timeline_allocation_inline", "apply_timeline_project_shift",
  "quick_assign_timeline_resource", "batch_quick_assign_timeline_resources",
  "batch_shift_timeline_allocations",
  "update_resource", "deactivate_resource", "create_resource",
  "update_project", "create_project", "delete_project",
  "create_vacation", "approve_vacation", "reject_vacation", "cancel_vacation",
  "set_entitlement", "create_demand", "fill_demand",
  "generate_project_cover", "remove_project_cover",
  "create_role", "update_role", "delete_role",
  "create_client", "update_client", "delete_client",
  "create_org_unit", "update_org_unit",
  "create_country", "update_country",
  "create_metro_city", "update_metro_city", "delete_metro_city",
  "create_holiday_calendar", "update_holiday_calendar", "delete_holiday_calendar",
  "create_holiday_calendar_entry", "update_holiday_calendar_entry", "delete_holiday_calendar_entry",
  "send_broadcast", "create_task_for_user", "create_reminder",
  "update_task_status", "execute_task_action",
  "create_comment", "resolve_comment", "mark_notification_read",
  "save_dashboard_layout", "toggle_favorite_project",
  "set_column_preferences", "generate_totp_secret", "verify_and_enable_totp",
  "create_user", "set_user_password", "update_user_role", "update_user_name",
  "link_user_resource", "auto_link_users_by_email", "set_user_permissions",
  "reset_user_permissions", "disable_user_totp",
  "create_notification", "update_reminder", "delete_reminder",
  "delete_notification", "assign_task",
  "clone_estimate", "update_estimate_draft", "submit_estimate_version",
  "approve_estimate_version", "create_estimate_revision",
  "create_estimate_export", "create_estimate_planning_handoff",
  "generate_estimate_weekly_phasing", "update_estimate_commercial_terms",
]);

export const ADVANCED_ASSISTANT_TOOLS = new Set([
  "find_best_project_resource",
  "get_timeline_entries_view",
  "get_timeline_holiday_overlays",
  "get_project_timeline_context",
  "preview_project_shift",
  "update_timeline_allocation_inline",
  "apply_timeline_project_shift",
  "quick_assign_timeline_resource",
  "batch_quick_assign_timeline_resources",
  "batch_shift_timeline_allocations",
  "get_chargeability_report",
  "get_resource_computation_graph",
  "get_project_computation_graph",
]);

const createChargeabilityReportCaller = createCallerFactory(chargeabilityReportRouter);
const createComputationGraphCaller = createCallerFactory(computationGraphRouter);
const createTimelineCaller = createCallerFactory(timelineRouter);
const createAuditLogCaller = createCallerFactory(auditLogRouter);
const createImportExportCaller = createCallerFactory(importExportRouter);
const createDispoCaller = createCallerFactory(dispoRouter);
const createResourceCaller = createCallerFactory(resourceRouter);
const createSettingsCaller = createCallerFactory(settingsRouter);
const createSystemRoleConfigCaller = createCallerFactory(systemRoleConfigRouter);
const createUserCaller = createCallerFactory(userRouter);
const createNotificationCaller = createCallerFactory(notificationRouter);
const createEstimateCaller = createCallerFactory(estimateRouter);
const createWebhookCaller = createCallerFactory(webhookRouter);
const createCountryCaller = createCallerFactory(countryRouter);
const createHolidayCalendarCaller = createCallerFactory(holidayCalendarRouter);
const createBlueprintCaller = createCallerFactory(blueprintRouter);
const createRoleCaller = createCallerFactory(roleRouter);
const createClientCaller = createCallerFactory(clientRouter);
const createOrgUnitCaller = createCallerFactory(orgUnitRouter);
const createProjectCaller = createCallerFactory(projectRouter);
const createRateCardCaller = createCallerFactory(rateCardRouter);
const createReportCaller = createCallerFactory(reportRouter);
const createVacationCaller = createCallerFactory(vacationRouter);
const createEntitlementCaller = createCallerFactory(entitlementRouter);
const createCommentCaller = createCallerFactory(commentRouter);
const createManagementLevelCaller = createCallerFactory(managementLevelRouter);
const createUtilizationCategoryCaller = createCallerFactory(utilizationCategoryRouter);
const createCalculationRuleCaller = createCallerFactory(calculationRuleRouter);
const createEffortRuleCaller = createCallerFactory(effortRuleRouter);
const createExperienceMultiplierCaller = createCallerFactory(experienceMultiplierRouter);
const createDashboardCaller = createCallerFactory(dashboardRouter);
const createInsightsCaller = createCallerFactory(insightsRouter);
const createScenarioCaller = createCallerFactory(scenarioRouter);
const createAllocationCaller = createCallerFactory(allocationRouter);
const createStaffingCaller = createCallerFactory(staffingRouter);

// ─── Helpers ────────────────────────────────────────────────────────────────

function fmtDate(d: Date | null | undefined): string | null {
  return d ? d.toISOString().slice(0, 10) : null;
}

class AssistantVisibleError extends Error {
  constructor(message: string) {
    super(message);
    this.name = "AssistantVisibleError";
  }
}

function assertPermission(ctx: ToolContext, perm: PermissionKey): void {
  if (!ctx.permissions.has(perm)) {
    throw new AssistantVisibleError(`Permission denied: you need the "${perm}" permission to perform this action.`);
  }
}

function assertAdminRole(ctx: ToolContext): void {
  if (ctx.userRole !== SystemRole.ADMIN) {
    throw new AssistantVisibleError("Admin role required to perform this action.");
  }
}

function formatHolidayCalendarEntry(entry: {
  id: string;
  date: Date;
  name: string;
  isRecurringAnnual?: boolean | null;
  source?: string | null;
}) {
  return {
    id: entry.id,
    date: fmtDate(entry.date),
    name: entry.name,
    isRecurringAnnual: entry.isRecurringAnnual ?? false,
    source: entry.source ?? null,
  };
}

function formatHolidayCalendar(calendar: {
  id: string;
  name: string;
  scopeType: string;
  stateCode?: string | null;
  isActive?: boolean | null;
  priority?: number | null;
  country?: { id: string; code: string; name: string } | null;
  metroCity?: { id: string; name: string } | null;
  _count?: { entries?: number | null } | null;
  entries?: Array<{
    id: string;
    date: Date;
    name: string;
    isRecurringAnnual?: boolean | null;
    source?: string | null;
  }> | null;
}) {
  const entries = calendar.entries?.map(formatHolidayCalendarEntry) ?? [];

  return {
    id: calendar.id,
    name: calendar.name,
    scopeType: calendar.scopeType,
    stateCode: calendar.stateCode ?? null,
    isActive: calendar.isActive ?? true,
    priority: calendar.priority ?? 0,
    country: calendar.country
      ? {
          id: calendar.country.id,
          code: calendar.country.code,
          name: calendar.country.name,
        }
      : null,
    metroCity: calendar.metroCity
      ? {
          id: calendar.metroCity.id,
          name: calendar.metroCity.name,
        }
      : null,
    entryCount: calendar._count?.entries ?? entries.length,
    entries,
  };
}

function formatCountry(country: {
  id: string;
  code: string;
  name: string;
  dailyWorkingHours: number;
  scheduleRules?: Prisma.JsonValue | null;
  isActive?: boolean | null;
  metroCities?: Array<{ id: string; name: string }> | null;
  _count?: { resources?: number | null } | null;
}) {
  return {
    id: country.id,
    code: country.code,
    name: country.name,
    dailyWorkingHours: country.dailyWorkingHours,
    scheduleRules: country.scheduleRules ?? null,
    isActive: country.isActive ?? true,
    resourceCount: country._count?.resources ?? null,
    metroCities: (country.metroCities ?? []).map((city) => ({
      id: city.id,
      name: city.name,
    })),
    cities: (country.metroCities ?? []).map((city) => city.name),
  };
}

function createUtcDate(year: number, monthIndex: number, day: number): Date {
  return new Date(Date.UTC(year, monthIndex, day));
}

function resolveHolidayPeriod(input: {
  year?: number;
  periodStart?: string;
  periodEnd?: string;
}): { year: number | null; periodStart: Date; periodEnd: Date } {
  if (input.periodStart || input.periodEnd) {
    if (!input.periodStart || !input.periodEnd) {
      throw new AssistantVisibleError("periodStart and periodEnd must both be provided when using a custom holiday range.");
    }

    const periodStart = new Date(`${input.periodStart}T00:00:00.000Z`);
    const periodEnd = new Date(`${input.periodEnd}T00:00:00.000Z`);
    if (Number.isNaN(periodStart.getTime())) {
      throw new AssistantVisibleError(`Invalid periodStart: ${input.periodStart}`);
    }
    if (Number.isNaN(periodEnd.getTime())) {
      throw new AssistantVisibleError(`Invalid periodEnd: ${input.periodEnd}`);
    }
    if (periodEnd < periodStart) {
      throw new AssistantVisibleError("periodEnd must be on or after periodStart.");
    }

    return { year: null, periodStart, periodEnd };
  }

  const year = input.year ?? new Date().getUTCFullYear();
  return {
    year,
    periodStart: createUtcDate(year, 0, 1),
    periodEnd: createUtcDate(year, 11, 31),
  };
}

const CONTROLLER_ASSISTANT_ROLES = [
  SystemRole.ADMIN,
  SystemRole.MANAGER,
  SystemRole.CONTROLLER,
] as const;

const LEGACY_MONOLITHIC_TOOL_ACCESS: Partial<Record<string, ToolAccessRequirements>> = {
  search_projects: { allowedSystemRoles: [...CONTROLLER_ASSISTANT_ROLES] },
  get_project: { allowedSystemRoles: [...CONTROLLER_ASSISTANT_ROLES] },
  update_project: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
  create_project: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
  delete_project: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
  generate_project_cover: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
  remove_project_cover: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
};

const ASSISTANT_VACATION_REQUEST_TYPES = [
  VacationType.ANNUAL,
  VacationType.SICK,
  VacationType.OTHER,
] as const;

function parseAssistantVacationRequestType(input: string): VacationType {
  const normalized = input.trim().toUpperCase();
  if (normalized === VacationType.PUBLIC_HOLIDAY) {
    throw new AssistantVisibleError("PUBLIC_HOLIDAY requests cannot be created manually. Manage public holidays through holiday calendars instead.");
  }

  if ((ASSISTANT_VACATION_REQUEST_TYPES as readonly string[]).includes(normalized)) {
    return normalized as VacationType;
  }

  throw new AssistantVisibleError(`Invalid vacation type: ${input}. Valid types: ${ASSISTANT_VACATION_REQUEST_TYPES.join(", ")}.`);
}

function parseIsoDate(value: string, fieldName: string): Date {
  const parsed = new Date(`${value}T00:00:00.000Z`);
  if (Number.isNaN(parsed.getTime())) {
    throw new AssistantVisibleError(`Invalid ${fieldName}: ${value}`);
  }
  return parsed;
}

function parseOptionalIsoDate(
  value: string | undefined,
  fieldName: string,
): Date | undefined {
  return value ? parseIsoDate(value, fieldName) : undefined;
}

function parseDateTime(value: string, fieldName: string): Date {
  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) {
    throw new AssistantVisibleError(`Invalid ${fieldName}: ${value}`);
  }
  return parsed;
}

function parseOptionalDateTime(
  value: string | undefined,
  fieldName: string,
): Date | undefined {
  return value ? parseDateTime(value, fieldName) : undefined;
}

function toDate(value: Date | string): Date {
  return value instanceof Date ? value : new Date(value);
}

type AssistantToolErrorResult = { error: string };
type AssistantIndexedFieldErrorResult = AssistantToolErrorResult & {
  field: string;
  index: number;
};
type BatchQuickAssignmentInput = {
  resourceId: string;
  projectId: string;
  startDate: Date;
  endDate: Date;
  hoursPerDay?: number;
  role?: string;
  status?: AllocationStatus;
};

function toAssistantNotFoundError(
  error: unknown,
  message: string,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    return { error: message };
  }
  return null;
}

function toAssistantAllocationNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError) {
    if (error.code === "NOT_FOUND") {
      return { error: "Allocation not found with the given criteria." };
    }
    if (error.message === "Record not found" || error.message.includes("Assignment not found")) {
      return { error: "Allocation not found with the given criteria." };
    }
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (prismaError?.code === "P2025") {
    return { error: "Allocation not found with the given criteria." };
  }

  return null;
}

function toAssistantProjectNotFoundError(
  error: unknown,
  identifier: string,
): AssistantToolErrorResult | null {
  return toAssistantNotFoundError(
    error,
    `Project not found: ${identifier}`,
  );
}

function toAssistantTimelineMutationError(
  error: unknown,
  context: "updateInline" | "applyShift" | "quickAssign" | "batchShift",
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError) {
    if (error.code === "NOT_FOUND") {
      if (error.message.includes("Resource not found")) {
        return { error: "Resource not found with the given criteria." };
      }
      if (error.message.includes("Project not found")) {
        return { error: "Project not found with the given criteria." };
      }
      if (error.message.includes("Demand requirement not found")) {
        return { error: "Demand requirement not found with the given criteria." };
      }
      if (error.message.includes("No allocations found")) {
        return { error: "Allocation not found with the given criteria." };
      }
    }

    if (error.code === "BAD_REQUEST" || error.code === "CONFLICT") {
      return { error: error.message };
    }
  }

  const allocationNotFound = toAssistantAllocationNotFoundError(error);
  if (allocationNotFound && (context === "updateInline" || context === "batchShift")) {
    return allocationNotFound;
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
  if (errorText.includes("resource")) {
    return { error: "Resource not found with the given criteria." };
  }
  if (errorText.includes("project")) {
    return { error: "Project not found with the given criteria." };
  }
  if (errorText.includes("demand")) {
    return { error: "Demand requirement not found with the given criteria." };
  }
  if (prismaError.code === "P2025" && (context === "updateInline" || context === "batchShift")) {
    return { error: "Allocation not found with the given criteria." };
  }

  return null;
}

function toAssistantVacationNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  return toAssistantNotFoundError(
    error,
    "Vacation not found with the given criteria.",
  );
}

function toAssistantVacationMutationError(
  error: unknown,
  action: "approve" | "reject" | "cancel",
): AssistantToolErrorResult | null {
  const notFound = toAssistantVacationNotFoundError(error);
  if (notFound) {
    return notFound;
  }

  if (error instanceof TRPCError && error.code === "BAD_REQUEST") {
    if (action === "approve") {
      return { error: "Vacation cannot be approved in its current status." };
    }
    if (action === "reject") {
      return { error: "Vacation cannot be rejected in its current status." };
    }
    return { error: "Vacation cannot be cancelled in its current status." };
  }

  return null;
}

function toAssistantProjectCreationError(
  error: unknown,
  shortCode: string,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError) {
    if (error.code === "CONFLICT") {
      return { error: `A project with short code "${shortCode}" already exists.` };
    }

    if (error.code === "NOT_FOUND") {
      if (error.message.includes("Blueprint")) {
        return { error: "Blueprint not found with the given criteria." };
      }
      if (error.message.includes("Client")) {
        return { error: "Client not found with the given criteria." };
      }
    }

    if (error.code === "BAD_REQUEST" || error.code === "UNPROCESSABLE_CONTENT") {
      return { error: error.message };
    }
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  if (prismaError.code !== "P2003" && prismaError.code !== "P2025") {
    return null;
  }

  const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
  if (errorText.includes("blueprint")) {
    return { error: "Blueprint not found with the given criteria." };
  }
  if (errorText.includes("client")) {
    return { error: "Client not found with the given criteria." };
  }

  return null;
}

function toAssistantDemandNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  return toAssistantNotFoundError(
    error,
    "Demand not found with the given criteria.",
  );
}

function toAssistantDemandFillError(
  error: unknown,
): AssistantToolErrorResult | null {
  const notFound = toAssistantDemandNotFoundError(error);
  if (notFound) {
    return notFound;
  }

  if (error instanceof TRPCError && error.code === "BAD_REQUEST") {
    return { error: "Demand cannot be filled in its current status." };
  }

  return null;
}

function toAssistantEstimateNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    if (error.message.includes("version")) {
      return { error: "Estimate version not found with the given criteria." };
    }
    return { error: "Estimate not found with the given criteria." };
  }

  return null;
}

function toAssistantEstimateReadError(
  error: unknown,
  context: "weeklyPhasing" | "commercialTerms",
): AssistantToolErrorResult | null {
  const notFound = toAssistantEstimateNotFoundError(error);
  if (notFound) {
    return notFound;
  }

  if (
    context === "weeklyPhasing"
    && error instanceof TRPCError
    && error.code === "PRECONDITION_FAILED"
    && error.message === "Estimate has no versions"
  ) {
    return { error: "Estimate version not found with the given criteria." };
  }

  return null;
}

function toAssistantHolidayCalendarNotFoundError(
  error: unknown,
  identifier?: string,
): AssistantToolErrorResult | null {
  return toAssistantNotFoundError(
    error,
    identifier
      ? `Holiday calendar not found: ${identifier}`
      : "Holiday calendar not found with the given criteria.",
  );
}

function toAssistantHolidayCalendarMutationError(
  error: unknown,
): AssistantToolErrorResult | null {
  const notFound = toAssistantHolidayCalendarNotFoundError(error);
  if (notFound) {
    return notFound;
  }

  if (error instanceof TRPCError && error.code === "BAD_REQUEST") {
    return { error: "Holiday calendar scope is invalid." };
  }

  if (error instanceof TRPCError && error.code === "CONFLICT") {
    return { error: "A holiday calendar for this scope already exists." };
  }

  return null;
}

function toAssistantHolidayEntryNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  return toAssistantNotFoundError(
    error,
    "Holiday calendar entry not found with the given criteria.",
  );
}

function toAssistantHolidayEntryMutationError(
  error: unknown,
): AssistantToolErrorResult | null {
  const calendarNotFound = toAssistantHolidayCalendarNotFoundError(error);
  if (calendarNotFound) {
    return calendarNotFound;
  }

  const entryNotFound = toAssistantHolidayEntryNotFoundError(error);
  if (entryNotFound) {
    return entryNotFound;
  }

  if (error instanceof TRPCError && error.code === "CONFLICT") {
    return { error: "A holiday entry for this calendar and date already exists." };
  }

  return null;
}

function toAssistantRoleNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  return toAssistantNotFoundError(
    error,
    "Role not found with the given criteria.",
  );
}

function toAssistantRoleMutationError(
  error: unknown,
  action: "create" | "update" | "delete",
): AssistantToolErrorResult | null {
  const notFound = toAssistantRoleNotFoundError(error);
  if (notFound) {
    return notFound;
  }

  if (error instanceof TRPCError && error.code === "CONFLICT") {
    return { error: "A role with this name already exists." };
  }

  if (action === "delete" && error instanceof TRPCError && error.code === "PRECONDITION_FAILED") {
    return { error: "Role cannot be deleted while it is still assigned. Deactivate it instead." };
  }

  return null;
}

function toAssistantClientMutationError(
  error: unknown,
  action: "create" | "update" | "delete" = "update",
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    if (error.message.includes("Parent client")) {
      return { error: "Parent client not found with the given criteria." };
    }
    return { error: "Client not found with the given criteria." };
  }

  if (error instanceof TRPCError && error.code === "CONFLICT") {
    return { error: "A client with this code already exists." };
  }

  if (action === "delete" && error instanceof TRPCError && error.code === "PRECONDITION_FAILED") {
    if (error.message.includes("project")) {
      return { error: "Client cannot be deleted while it still has projects. Deactivate it instead." };
    }
    if (error.message.includes("child client")) {
      return { error: "Client cannot be deleted while it still has child clients. Remove or reassign them first." };
    }
  }

  return null;
}

function toAssistantOrgUnitNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    if (error.message.includes("Parent org unit")) {
      return { error: "Parent org unit not found with the given criteria." };
    }
    return { error: "Org unit not found with the given criteria." };
  }

  return null;
}

function toAssistantOrgUnitMutationError(
  error: unknown,
): AssistantToolErrorResult | null {
  const notFound = toAssistantOrgUnitNotFoundError(error);
  if (notFound) {
    return notFound;
  }

  if (error instanceof TRPCError && error.code === "BAD_REQUEST") {
    if (error.message.includes("must be greater than parent level")) {
      return { error: "Org unit level must be greater than the parent org unit level." };
    }
  }

  return null;
}

function toAssistantCountryNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    return { error: "Country not found with the given criteria." };
  }

  return null;
}

function toAssistantCountryMutationError(
  error: unknown,
): AssistantToolErrorResult | null {
  const notFound = toAssistantCountryNotFoundError(error);
  if (notFound) {
    return notFound;
  }

  if (error instanceof TRPCError && error.code === "CONFLICT") {
    return { error: "A country with this code already exists." };
  }

  return null;
}

function toAssistantResourceCreationError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError) {
    if (error.code === "CONFLICT") {
      return { error: "A resource with this EID or email already exists." };
    }

    if (error.code === "BAD_REQUEST" || error.code === "UNPROCESSABLE_CONTENT") {
      return { error: error.message };
    }

    if (error.code === "NOT_FOUND") {
      if (error.message.includes("Role")) {
        return { error: "Role not found with the given criteria." };
      }
      if (error.message.includes("Country")) {
        return { error: "Country not found with the given criteria." };
      }
      if (error.message.includes("Org unit")) {
        return { error: "Org unit not found with the given criteria." };
      }
    }
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  if (prismaError.code !== "P2003" && prismaError.code !== "P2025") {
    return null;
  }

  const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
  if (errorText.includes("role")) {
    return { error: "Role not found with the given criteria." };
  }
  if (errorText.includes("country")) {
    return { error: "Country not found with the given criteria." };
  }
  if (errorText.includes("orgunit") || errorText.includes("org_unit") || errorText.includes("org unit")) {
    return { error: "Org unit not found with the given criteria." };
  }

  return { error: "The selected role, country, or org unit no longer exists." };
}

function toAssistantResourceMutationError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    return { error: "Resource not found with the given criteria." };
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  if (prismaError.code === "P2025") {
    return { error: "Resource not found with the given criteria." };
  }

  if (prismaError.code !== "P2003") {
    return null;
  }

  const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
  if (errorText.includes("role")) {
    return { error: "Role not found with the given criteria." };
  }
  if (errorText.includes("country")) {
    return { error: "Country not found with the given criteria." };
  }
  if (errorText.includes("orgunit") || errorText.includes("org_unit") || errorText.includes("org unit")) {
    return { error: "Org unit not found with the given criteria." };
  }

  return { error: "Resource not found with the given criteria." };
}

function toAssistantProjectMutationError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    return { error: "Project not found with the given criteria." };
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  if (prismaError.code === "P2025") {
    return { error: "Project not found with the given criteria." };
  }

  if (prismaError.code !== "P2003") {
    return null;
  }

  const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
  if (errorText.includes("blueprint")) {
    return { error: "Blueprint not found with the given criteria." };
  }
  if (errorText.includes("client")) {
    return { error: "Client not found with the given criteria." };
  }

  return { error: "Project not found with the given criteria." };
}

function toAssistantMetroCityMutationError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    if (error.message.includes("Country")) {
      return { error: "Country not found with the given criteria." };
    }
    return { error: "Metro city not found with the given criteria." };
  }

  if (error instanceof TRPCError && error.code === "PRECONDITION_FAILED") {
    return { error: "Metro city cannot be deleted while it is still assigned to resources." };
  }

  return null;
}

function toAssistantDemandCreationError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    if (error.message.includes("Role")) {
      return { error: "Role not found with the given criteria." };
    }
    return { error: "Project not found with the given criteria." };
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  if (prismaError.code !== "P2003" && prismaError.code !== "P2025") {
    return null;
  }

  const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
  if (errorText.includes("role")) {
    return { error: "Role not found with the given criteria." };
  }
  if (errorText.includes("project")) {
    return { error: "Project not found with the given criteria." };
  }

  return null;
}

function toAssistantVacationCreationError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError) {
    if (error.code === "FORBIDDEN") {
      return { error: "You can only create vacation requests for your own resource." };
    }

    if (error.code === "BAD_REQUEST") {
      return { error: error.message };
    }
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  if (prismaError.code === "P2025") {
    return { error: "Resource not found with the given criteria." };
  }

  if (prismaError.code !== "P2003") {
    return null;
  }

  const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
  if (errorText.includes("resource")) {
    return { error: "Resource not found with the given criteria." };
  }

  return { error: "Resource not found with the given criteria." };
}

function toAssistantEntitlementMutationError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    return { error: "Resource not found with the given criteria." };
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  if (prismaError.code === "P2025") {
    return { error: "Resource not found with the given criteria." };
  }

  if (prismaError.code !== "P2003") {
    return null;
  }

  return { error: "Resource not found with the given criteria." };
}

function toAssistantEstimateCreationError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    return { error: "Project not found with the given criteria." };
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  if (prismaError.code !== "P2003" && prismaError.code !== "P2025") {
    return null;
  }

  const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
  if (errorText.includes("project")) {
    return { error: "Project not found with the given criteria." };
  }
  if (errorText.includes("role")) {
    return { error: "Role not found with the given criteria." };
  }
  if (errorText.includes("resource")) {
    return { error: "Resource not found with the given criteria." };
  }
  if (errorText.includes("scopeitem") || errorText.includes("scope_item") || errorText.includes("scope item")) {
    return { error: "Estimate scope item not found with the given criteria." };
  }

  return { error: "One of the referenced project, role, resource, or scope items no longer exists." };
}

function toAssistantEstimateMutationError(
  error: unknown,
  action:
    | "clone"
    | "updateDraft"
    | "submitVersion"
    | "approveVersion"
    | "createRevision"
    | "createExport"
    | "createPlanningHandoff"
    | "generateWeeklyPhasing"
    | "updateCommercialTerms",
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError) {
    if (error.code === "NOT_FOUND") {
      if (error.message.includes("Linked project")) {
        return { error: "Project not found with the given criteria." };
      }
      if (action === "clone" && error.message === "Source estimate has no versions") {
        return { error: "Source estimate has no versions and cannot be cloned." };
      }
      if (error.message.includes("version") || error.message.includes("versions")) {
        return { error: "Estimate version not found with the given criteria." };
      }
      return { error: "Estimate not found with the given criteria." };
    }

    if (error.code === "PRECONDITION_FAILED") {
      switch (error.message) {
        case "Estimate has no working version":
          return { error: "Estimate has no working version." };
        case "Only working versions can be submitted":
          return { error: "Only working versions can be submitted." };
        case "Estimate has no submitted version":
          return { error: "Estimate has no submitted version." };
        case "Only submitted versions can be approved":
          return { error: "Only submitted versions can be approved." };
        case "Estimate already has a working version":
          return { error: "Estimate already has a working version." };
        case "Estimate has no locked version to revise":
          return { error: "Estimate has no locked version to revise." };
        case "Source version must be locked before creating a revision":
          return { error: "Source version must be locked before creating a revision." };
        case "Estimate has no approved version":
          return { error: "Estimate has no approved version." };
        case "Only approved versions can be handed off to planning":
          return { error: "Only approved versions can be handed off to planning." };
        case "Estimate must be linked to a project before planning handoff":
          return { error: "Estimate must be linked to a project before planning handoff." };
        case "Planning handoff already exists for this approved version":
          return { error: "Planning handoff already exists for this approved version." };
        case "Linked project has an invalid date range":
          return { error: "The linked project has an invalid date range for planning handoff." };
        case "Commercial terms can only be edited on working versions":
          return { error: "Commercial terms can only be edited on working versions." };
        default:
          if (error.message.startsWith("Project window has no working days for demand line")) {
            return { error: "The linked project window has no working days for at least one demand line." };
          }
      }
    }

    if (error.code === "BAD_REQUEST" && action === "updateCommercialTerms") {
      return { error: "Commercial terms input is invalid." };
    }
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  if (prismaError.code === "P2003") {
    const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
    if (errorText.includes("project")) {
      return { error: "Project not found with the given criteria." };
    }
    if (errorText.includes("role")) {
      return { error: "Role not found with the given criteria." };
    }
    if (errorText.includes("resource")) {
      return { error: "Resource not found with the given criteria." };
    }
    if (errorText.includes("scopeitem") || errorText.includes("scope_item") || errorText.includes("scope item")) {
      return { error: "Estimate scope item not found with the given criteria." };
    }
    return { error: "One of the referenced project, role, resource, or scope items no longer exists." };
  }

  if (prismaError.code === "P2025") {
    const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
    if (errorText.includes("estimatedemandline") || errorText.includes("estimate_demand_line") || errorText.includes("estimate demand line")) {
      return { error: "Estimate demand line not found with the given criteria." };
    }
    if (errorText.includes("estimateversion") || errorText.includes("estimate_version") || errorText.includes("estimate version")) {
      return { error: "Estimate version not found with the given criteria." };
    }
    if (errorText.includes("estimate")) {
      return { error: "Estimate not found with the given criteria." };
    }
    switch (action) {
      case "generateWeeklyPhasing":
        return { error: "Estimate demand line not found with the given criteria." };
      case "updateCommercialTerms":
      case "submitVersion":
      case "approveVersion":
      case "createRevision":
      case "createExport":
        return { error: "Estimate version not found with the given criteria." };
      default:
        return { error: "Estimate not found with the given criteria." };
    }
  }

  return null;
}

function toAssistantUserMutationError(
  error: unknown,
  action: "create" | "update" | "password" = "update",
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "CONFLICT" && action === "create") {
    return { error: "User with this email already exists." };
  }

  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    return { error: "User not found with the given criteria." };
  }

  if (error instanceof TRPCError && error.code === "BAD_REQUEST") {
    const validationIssues = getTrpcValidationIssues(error);
    for (const issue of validationIssues) {
      const field = issue.path[0];
      if (field === "password" && issue.code === "too_small") {
        return { error: "Password must be at least 8 characters." };
      }

      if (field === "name" && issue.code === "too_small") {
        return { error: "Name is required." };
      }

      if (field === "name" && issue.code === "too_big") {
        return { error: "Name must be at most 200 characters." };
      }
    }

    if (error.message.includes("Password must be at least 8 characters")) {
      return { error: "Password must be at least 8 characters." };
    }

    if (error.message.includes("Name is required")) {
      return { error: "Name is required." };
    }
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (prismaError?.code === "P2025") {
    return { error: "User not found with the given criteria." };
  }

  return null;
}

function getTrpcValidationIssues(error: TRPCError): Array<{
  code?: string;
  path: string[];
}> {
  if (error.cause instanceof ZodError) {
    return error.cause.issues.map((issue) => ({
      code: issue.code,
      path: issue.path.map((segment) => String(segment)),
    }));
  }

  try {
    const parsed = JSON.parse(error.message);
    if (!Array.isArray(parsed)) {
      return [];
    }

    return parsed
      .filter((issue): issue is { code?: unknown; path?: unknown } => issue !== null && typeof issue === "object")
      .map((issue) => (
        typeof issue.code === "string"
          ? {
            code: issue.code,
            path: Array.isArray(issue.path) ? issue.path.map((segment) => String(segment)) : [],
          }
          : {
            path: Array.isArray(issue.path) ? issue.path.map((segment) => String(segment)) : [],
          }
      ));
  } catch {
    return [];
  }
}

function toAssistantUserResourceLinkError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "CONFLICT") {
    if (error.message.includes("already linked")) {
      return { error: "Resource is already linked to another user." };
    }
    if (error.message.includes("changed during update")) {
      return { error: "Resource link changed during update. Please retry." };
    }
  }

  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    if (error.message.includes("Resource")) {
      return { error: "Resource not found with the given criteria." };
    }
    return { error: "User not found with the given criteria." };
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
  const pointsToUser =
    errorText.includes("userid")
    || errorText.includes("user_id")
    || errorText.includes(" user ");
  const pointsToResource =
    errorText.includes("resourceid")
    || errorText.includes("resource_id")
    || errorText.includes(" resource ");

  if (prismaError.code === "P2025") {
    return { error: "Resource not found with the given criteria." };
  }

  if (prismaError.code === "P2003") {
    if (pointsToUser) {
      return { error: "User not found with the given criteria." };
    }
    if (pointsToResource || errorText.includes("resource")) {
      return { error: "Resource not found with the given criteria." };
    }
    return { error: "User not found with the given criteria." };
  }

  return null;
}

function toAssistantTotpEnableError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "BAD_REQUEST") {
    if (error.message.includes("No TOTP secret generated")) {
      return { error: "No TOTP secret generated. Call generate_totp_secret first." };
    }
    if (error.message.includes("already enabled")) {
      return { error: "TOTP is already enabled." };
    }
    if (error.message.includes("Invalid TOTP token")) {
      return { error: "Invalid TOTP token." };
    }
  }

  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    return { error: "User not found with the given criteria." };
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (prismaError?.code === "P2025") {
    return { error: "User not found with the given criteria." };
  }

  return null;
}

function toAssistantWebhookNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  return toAssistantNotFoundError(
    error,
    "Webhook not found with the given criteria.",
  );
}

function toAssistantWebhookMutationError(
  error: unknown,
  action: "create" | "update" = "update",
): AssistantToolErrorResult | null {
  const notFound = toAssistantWebhookNotFoundError(error);
  if (notFound) {
    return notFound;
  }

  if (error instanceof TRPCError && error.code === "BAD_REQUEST") {
    return {
      error: action === "create"
        ? "Webhook input is invalid."
        : "Webhook update input is invalid.",
    };
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (prismaError?.code === "P2025") {
    return { error: "Webhook not found with the given criteria." };
  }

  return null;
}

function toAssistantAuditLogEntryNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  return toAssistantNotFoundError(
    error,
    "Audit log entry not found with the given criteria.",
  );
}

function toAssistantTaskNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  return toAssistantNotFoundError(
    error,
    "Task not found with the given criteria.",
  );
}

function toAssistantTaskActionError(
  error: unknown,
): AssistantToolErrorResult | null {
  const notFound = toAssistantTaskNotFoundError(error);
  if (notFound) {
    return notFound;
  }

  if (error instanceof TRPCError && error.code === "PRECONDITION_FAILED") {
    if (error.message.includes("no executable action")) {
      return { error: "Task has no executable action." };
    }
    if (error.message.includes("already completed")) {
      return { error: "Task is already completed." };
    }
    if (error.message.includes("dismissed")) {
      return { error: "Task has been dismissed and cannot be executed." };
    }
  }

  if (error instanceof TRPCError && error.code === "BAD_REQUEST") {
    if (error.message.includes("Invalid taskAction format") || error.message.includes("Unknown action")) {
      return { error: "Task action is invalid and cannot be executed." };
    }
    if (error.message === "Vacation not found") {
      return { error: "Vacation not found with the given criteria." };
    }
    if (error.message.startsWith("Vacation is ") && error.message.includes(", not PENDING")) {
      return { error: "Vacation is not pending and cannot be approved or rejected via this task action." };
    }
    if (error.message === "Assignment not found") {
      return { error: "Assignment not found with the given criteria." };
    }
    if (error.message === "Assignment is already CONFIRMED") {
      return { error: "Assignment is already confirmed." };
    }
    return { error: error.message };
  }

  if (error instanceof TRPCError && error.code === "FORBIDDEN") {
    return { error: "You do not have permission to execute this task action." };
  }

  return null;
}

function toAssistantTaskAssignmentError(
  error: unknown,
): AssistantToolErrorResult | null {
  const notFound = toAssistantTaskNotFoundError(error);
  if (notFound) {
    return notFound;
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (prismaError && (prismaError.code === "P2003" || prismaError.code === "P2025")) {
    const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
    if (errorText.includes("assignee")) {
      return { error: "Assignee user not found with the given criteria." };
    }
  }

  if (error instanceof TRPCError && error.code === "BAD_REQUEST") {
    return { error: "Only tasks and approvals can be assigned." };
  }

  return null;
}

function toAssistantBroadcastNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  return toAssistantNotFoundError(
    error,
    "Broadcast not found with the given criteria.",
  );
}

function toAssistantDispoImportBatchNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  return toAssistantNotFoundError(
    error,
    "Import batch not found with the given criteria.",
  );
}

function toAssistantReminderNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  return toAssistantNotFoundError(
    error,
    "Reminder not found with the given criteria.",
  );
}

function toAssistantNotificationNotFoundError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    return { error: "Notification not found with the given criteria." };
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (prismaError?.code === "P2025") {
    return { error: "Notification not found with the given criteria." };
  }

  return null;
}

function toAssistantNotificationReadError(
  error: unknown,
): AssistantToolErrorResult | null {
  return toAssistantNotificationNotFoundError(error);
}

function toAssistantNotificationDeletionError(
  error: unknown,
): AssistantToolErrorResult | null {
  const notFound = toAssistantNotificationNotFoundError(error);
  if (notFound) {
    return notFound;
  }

  if (error instanceof TRPCError && error.code === "FORBIDDEN") {
    return { error: "Tasks created by other users cannot be deleted." };
  }

  return null;
}

function toAssistantReminderCreationError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "BAD_REQUEST") {
    return { error: "Reminder input is invalid." };
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  if (prismaError.code !== "P2003" && prismaError.code !== "P2025") {
    return null;
  }

  const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
  if (errorText.includes("user")) {
    return { error: "Authenticated user not found with the given criteria." };
  }

  return null;
}

function toAssistantCommentResolveError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "NOT_FOUND") {
    return { error: "Comment not found with the given criteria." };
  }

  if (error instanceof TRPCError && error.code === "FORBIDDEN") {
    return { error: "Only the comment author or an admin can resolve comments." };
  }

  return null;
}

function toAssistantCommentCreationError(
  error: unknown,
): AssistantToolErrorResult | null {
  if (error instanceof TRPCError && error.code === "BAD_REQUEST") {
    if (error.message.includes("at least 1 character")) {
      return { error: "Comment body is required." };
    }

    if (error.message.includes("at most 10000")) {
      return { error: "Comment body must be at most 10000 characters." };
    }
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  if (prismaError.code !== "P2003" && prismaError.code !== "P2025") {
    return null;
  }

  const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();
  if (errorText.includes("author") || errorText.includes("sender")) {
    return { error: "Comment author not found with the given criteria." };
  }

  if (errorText.includes("user") || errorText.includes("recipient")) {
    return { error: "Mentioned user not found with the given criteria." };
  }

  return null;
}

function getPrismaRequestErrorMetadata(error: unknown): {
  code: string;
  message: string;
  metaText: string;
} | null {
  const collectMetaStrings = (value: unknown): string[] => {
    if (typeof value === "string") {
      return [value];
    }
    if (Array.isArray(value)) {
      return value.flatMap((entry) => collectMetaStrings(entry));
    }
    if (value && typeof value === "object") {
      return Object.values(value).flatMap((entry) => collectMetaStrings(entry));
    }
    return [];
  };

  const queue: unknown[] = [error];
  const visited = new Set<unknown>();

  while (queue.length > 0) {
    const current = queue.shift();
    if (current === undefined || current === null || visited.has(current)) {
      continue;
    }
    visited.add(current);

    if (current instanceof Prisma.PrismaClientKnownRequestError) {
      const metaText = Object.values(current.meta ?? {})
        .flatMap((value) => collectMetaStrings(value))
        .join(" ");
      return {
        code: current.code,
        message: current.message,
        metaText,
      };
    }

    if (typeof current !== "object") {
      continue;
    }

    const candidate = current as {
      code?: unknown;
      message?: unknown;
      meta?: Record<string, unknown>;
      cause?: unknown;
    };

    if (typeof candidate.code === "string" && /^P\d{4}$/.test(candidate.code)) {
      const metaText = Object.values(candidate.meta ?? {})
        .flatMap((value) => collectMetaStrings(value))
        .join(" ");

      return {
        code: candidate.code,
        message: typeof candidate.message === "string" ? candidate.message : "",
        metaText,
      };
    }

    if ("cause" in candidate) {
      queue.push(candidate.cause);
    }
  }

  return null;
}

function getTrpcErrorMetadata(error: unknown): {
  code: string;
  message: string;
} | null {
  const queue: unknown[] = [error];
  const visited = new Set<unknown>();

  while (queue.length > 0) {
    const current = queue.shift();
    if (current === undefined || current === null || visited.has(current)) {
      continue;
    }
    visited.add(current);

    if (current instanceof TRPCError) {
      return {
        code: current.code,
        message: current.message,
      };
    }

    if (typeof current !== "object") {
      continue;
    }

    const candidate = current as {
      code?: unknown;
      message?: unknown;
      cause?: unknown;
      data?: { code?: unknown };
      shape?: { code?: unknown; message?: unknown; data?: { cause?: unknown } };
    };

    const candidateCode = typeof candidate.code === "string"
      ? candidate.code
      : typeof candidate.data?.code === "string"
        ? candidate.data.code
        : typeof candidate.shape?.code === "string"
          ? candidate.shape.code
          : null;
    const candidateMessage = typeof candidate.message === "string"
      ? candidate.message
      : typeof candidate.shape?.message === "string"
        ? candidate.shape.message
        : "";

    if (candidateCode && /^[A-Z_]+$/.test(candidateCode)) {
      return {
        code: candidateCode,
        message: candidateMessage,
      };
    }

    if ("cause" in candidate) {
      queue.push(candidate.cause);
    }
    if (candidate.shape?.data?.cause) {
      queue.push(candidate.shape.data.cause);
    }
  }

  return null;
}

function toAssistantNotificationCreationError(
  error: unknown,
  context: "notification" | "task" | "broadcast",
): AssistantToolErrorResult | null {
  const trpcError = getTrpcErrorMetadata(error);

  if (
    context === "broadcast"
    && trpcError?.code === "BAD_REQUEST"
    && trpcError.message === "No recipients matched the broadcast target."
  ) {
    return { error: "No recipients matched the broadcast target." };
  }

  if (
    context === "broadcast"
    && trpcError?.code === "BAD_REQUEST"
    && trpcError.message === "Scheduled broadcasts with task metadata are not supported yet."
  ) {
    return { error: "Scheduled broadcasts with task metadata are not supported yet." };
  }

  if (trpcError?.code === "NOT_FOUND") {
    if (trpcError.message.includes("broadcast")) {
      return { error: "Broadcast not found with the given criteria." };
    }
    if (trpcError.message.includes("Sender user not found")) {
      return { error: "Sender user not found with the given criteria." };
    }
    if (trpcError.message.includes("Assignee user not found")) {
      return { error: "Assignee user not found with the given criteria." };
    }
    if (trpcError.message.includes("recipient")) {
      return context === "broadcast"
        ? { error: "Broadcast recipient user not found with the given criteria." }
        : context === "task"
          ? { error: "Task recipient user not found with the given criteria." }
          : { error: "Notification recipient user not found with the given criteria." };
    }
  }

  const prismaError = getPrismaRequestErrorMetadata(error);
  if (!prismaError) {
    return null;
  }

  if (prismaError.code !== "P2003" && prismaError.code !== "P2025") {
    return null;
  }

  const errorText = `${prismaError.message} ${prismaError.metaText}`.toLowerCase();

  if (errorText.includes("assignee")) {
    return { error: "Assignee user not found with the given criteria." };
  }

  if (errorText.includes("sender")) {
    return { error: "Sender user not found with the given criteria." };
  }

  if (context === "broadcast" && (errorText.includes("notificationbroadcast") || errorText.includes("broadcast"))) {
    return { error: "Broadcast not found with the given criteria." };
  }

  if (context === "broadcast" && prismaError.code === "P2025") {
    return { error: "Broadcast not found with the given criteria." };
  }

  if (context === "task") {
    return { error: "Task recipient user not found with the given criteria." };
  }

  if (context === "broadcast") {
    return { error: "Broadcast recipient user not found with the given criteria." };
  }

  return { error: "Notification recipient user not found with the given criteria." };
}

function normalizeAssistantExecutionError(
  error: unknown,
): AssistantToolErrorResult {
  if (error instanceof AssistantVisibleError) {
    return { error: error.message };
  }

  const trpcError = getTrpcErrorMetadata(error);
  if (trpcError) {
    if (trpcError.code === "INTERNAL_SERVER_ERROR") {
      return {
        error: "The tool could not complete due to an internal error.",
      };
    }

    if (trpcError.code === "UNAUTHORIZED") {
      return {
        error: "Authentication is required to use this tool.",
      };
    }

    if (trpcError.code === "FORBIDDEN") {
      return {
        error: "You do not have permission to perform this action.",
      };
    }

    return { error: "The tool could not complete due to a request error." };
  }

  if (error instanceof Error) {
    return { error: "The tool could not complete due to an unexpected error." };
  }

  return { error: "The tool could not complete due to an unexpected error." };
}

function isAssistantToolErrorResult(
  value: unknown,
): value is AssistantToolErrorResult {
  return value !== null && typeof value === "object" && "error" in value;
}

function toAssistantIndexedFieldError(
  index: number,
  field: string,
  message: string,
): AssistantIndexedFieldErrorResult {
  return {
    error: `assignments[${index}].${field}: ${message}`,
    field: `assignments[${index}].${field}`,
    index,
  };
}

async function resolveEntityOrAssistantError<T>(
  resolve: () => Promise<T>,
  notFoundMessage: string,
): Promise<T | AssistantToolErrorResult> {
  try {
    return await resolve();
  } catch (error) {
    const mapped = toAssistantNotFoundError(error, notFoundMessage);
    if (mapped) {
      return mapped;
    }
    if (error instanceof TRPCError && error.code === "INTERNAL_SERVER_ERROR") {
      return normalizeAssistantExecutionError(error);
    }
    throw error;
  }
}

async function resolveProjectIdentifier(
  ctx: ToolContext,
  identifier: string,
) {
  const caller = createProjectCaller(createScopedCallerContext(ctx));
  return resolveEntityOrAssistantError(
    () => caller.resolveByIdentifier({ identifier }),
    `Project not found: ${identifier}`,
  );
}

async function resolveResourceIdentifier(
  ctx: ToolContext,
  identifier: string,
) {
  const caller = createResourceCaller(createScopedCallerContext(ctx));
  return resolveEntityOrAssistantError(
    () => caller.resolveByIdentifier({ identifier }),
    `Resource not found: ${identifier}`,
  );
}

function createScopedCallerContext(ctx: ToolContext): TRPCContext {
  if (!ctx.session?.user || !ctx.dbUser) {
    throw new AssistantVisibleError("Authenticated assistant context is required for this tool.");
  }

  return {
    session: ctx.session,
    db: ctx.db,
    dbUser: ctx.dbUser,
    roleDefaults: ctx.roleDefaults ?? null,
  };
}

function sanitizeWebhook<T extends { secret?: string | null }>(webhook: T) {
  const { secret: _secret, ...rest } = webhook;
  return {
    ...rest,
    hasSecret: Boolean(webhook.secret),
  };
}

function sanitizeWebhookList<T extends { secret?: string | null }>(webhooks: T[]) {
  return webhooks.map((webhook) => sanitizeWebhook(webhook));
}

// ─── Tool Definitions ───────────────────────────────────────────────────────

export const TOOL_DEFINITIONS: ToolDef[] = withToolAccess([
  // ── READ TOOLS ──
  ...resourceReadToolDefinitions,
  ...projectReadToolDefinitions,
  ...advancedTimelineToolDefinitions,
  ...allocationPlanningReadToolDefinitions,
  ...vacationHolidayReadToolDefinitions,
  ...vacationHolidayMutationToolDefinitions,
  ...rolesAnalyticsReadToolDefinitions,
  ...chargeabilityComputationReadToolDefinitions,
  ...planningNavigationToolDefinitions,

  // ── WRITE TOOLS ──
  ...allocationPlanningMutationToolDefinitions,
  ...resourceMutationToolDefinitions,
  ...projectMutationToolDefinitions,
  ...vacationEntitlementToolDefinitions,

  // ── DEMAND / STAFFING ──
  ...staffingDemandReadToolDefinitions,
  ...staffingDemandMutationToolDefinitions,

  // ── BLUEPRINT ──
  ...blueprintsRateCardsToolDefinitions,

  // ── ESTIMATES ──
  ...estimateReadToolDefinitions,
  ...estimateMutationToolDefinitions,

  // ── ROLES ──
  ...rolesAnalyticsMutationToolDefinitions,

  // ── CLIENTS ──
  ...clientMutationToolDefinitions,

  // ── ADMIN / CONFIG READ TOOLS ──
  ...countryReadmodelToolDefinitions,
  ...countryMetroAdminToolDefinitions,
  ...configReadmodelToolDefinitions,
  ...userAdminToolDefinitions,
  ...userSelfServiceToolDefinitions,
  ...notificationInboxToolDefinitions,
  ...dashboardInsightsReportsToolDefinitions,

  // ── ORG UNIT MANAGEMENT ──
  ...orgUnitMutationToolDefinitions,

  // ── TASK MANAGEMENT ──
  ...notificationTaskToolDefinitions,
  ...commentReadToolDefinitions,
  ...scenarioRateAnalysisToolDefinitions,
  ...commentMutationToolDefinitions,
  ...auditHistoryToolDefinitions,
  ...importExportDispoToolDefinitions,
  ...settingsAdminToolDefinitions,
], LEGACY_MONOLITHIC_TOOL_ACCESS);

const TOOL_DEFINITIONS_BY_NAME = new Map(
  TOOL_DEFINITIONS.map((tool) => [tool.function.name, tool]),
);

type AssistantToolAccessEvaluationContext = Pick<ToolContext, "permissions" | "userRole">;

type AssistantToolAccessFailure =
  | { type: "role" }
  | {
      type: "permission";
      permission?: PermissionKey;
      message?: string;
    };

function hasAssistantResourceOverviewAccess(
  permissions: Set<PermissionKey>,
): boolean {
  return permissions.has(PermissionKey.VIEW_ALL_RESOURCES)
    || permissions.has(PermissionKey.MANAGE_RESOURCES);
}

function getAssistantToolAccessRequirements(
  tool: ToolDef,
): ToolAccessRequirements | undefined {
  return tool.access ?? LEGACY_MONOLITHIC_TOOL_ACCESS[tool.function.name];
}

function getAssistantToolAccessFailure(
  tool: ToolDef,
  ctx: AssistantToolAccessEvaluationContext,
): AssistantToolAccessFailure | null {
  const access = getAssistantToolAccessRequirements(tool);
  if (!access) {
    return null;
  }

  if (
    access.allowedSystemRoles
    && !access.allowedSystemRoles.includes(ctx.userRole as SystemRole)
  ) {
    return { type: "role" };
  }

  const missingRequiredPermission = access.requiredPermissions?.find(
    (permission) => !ctx.permissions.has(permission),
  );
  if (missingRequiredPermission) {
    return {
      type: "permission",
      permission: missingRequiredPermission,
    };
  }

  if (access.requiresPlanningRead && !ctx.permissions.has(PermissionKey.VIEW_PLANNING)) {
    return {
      type: "permission",
      permission: PermissionKey.VIEW_PLANNING,
    };
  }

  if (access.requiresCostView && !ctx.permissions.has(PermissionKey.VIEW_COSTS)) {
    return {
      type: "permission",
      permission: PermissionKey.VIEW_COSTS,
    };
  }

  if (
    access.requiresAdvancedAssistant
    && !ctx.permissions.has(PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS)
  ) {
    return {
      type: "permission",
      permission: PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS,
    };
  }

  if (
    access.requiresResourceOverview
    && !hasAssistantResourceOverviewAccess(ctx.permissions)
  ) {
    return {
      type: "permission",
      message: "Permission denied: you need resource overview access to perform this action.",
    };
  }

  return null;
}

function toAssistantToolAccessError(
  failure: AssistantToolAccessFailure,
): AssistantVisibleError {
  if (failure.type === "role") {
    return new AssistantVisibleError("You do not have permission to perform this action.");
  }

  if (failure.permission) {
    return new AssistantVisibleError(
      `Permission denied: you need the "${failure.permission}" permission to perform this action.`,
    );
  }

  return new AssistantVisibleError(
    failure.message ?? "You do not have permission to perform this action.",
  );
}

export function canAccessAssistantTool(
  tool: ToolDef,
  ctx: AssistantToolAccessEvaluationContext,
): boolean {
  return getAssistantToolAccessFailure(tool, ctx) === null;
}

export function getAvailableAssistantToolsForContext(
  permissions: Set<PermissionKey>,
  userRole: string,
): ToolDef[] {
  return TOOL_DEFINITIONS.filter((tool) => canAccessAssistantTool(tool, { permissions, userRole }));
}

// ─── Helpers ────────────────────────────────────────────────────────────────

/** Resolve a responsible person name against existing resources. Returns the exact displayName or an error object. */
async function resolveResponsiblePerson(
  name: string,
  ctx: ToolContext,
): Promise<{ displayName: string } | { error: string }> {
  const caller = createResourceCaller(createScopedCallerContext(ctx));
  const result = await caller.resolveResponsiblePersonName({ name });

  if (result.status === "resolved") {
    return { displayName: result.displayName };
  }

  if (result.status === "ambiguous" || result.status === "missing") {
    return { error: result.message };
  }

  return { error: `Unable to resolve responsible person: ${name}` };
}

// ─── Tool Executors ─────────────────────────────────────────────────────────

const executors = {
  ...createResourceExecutors({
    assertPermission,
    createResourceCaller,
    createRoleCaller,
    createCountryCaller,
    createOrgUnitCaller,
    createScopedCallerContext,
    resolveResourceIdentifier,
    resolveEntityOrAssistantError,
    toAssistantResourceMutationError,
    toAssistantResourceCreationError,
  }),

  ...createProjectExecutors({
    assertPermission,
    createProjectCaller,
    createBlueprintCaller,
    createClientCaller,
    createScopedCallerContext,
    resolveProjectIdentifier,
    resolveResponsiblePerson,
    resolveEntityOrAssistantError,
    toAssistantNotFoundError,
    toAssistantProjectMutationError,
    toAssistantProjectCreationError,
    toAssistantProjectNotFoundError,
  }),
  ...createStaffingDemandExecutors({
    assertPermission,
    createAllocationCaller,
    createStaffingCaller,
    createRoleCaller,
    createScopedCallerContext,
    resolveProjectIdentifier,
    resolveResourceIdentifier,
    resolveEntityOrAssistantError,
    parseIsoDate,
    parseOptionalIsoDate,
    fmtDate,
    toAssistantDemandCreationError,
    toAssistantDemandFillError,
  }),

  ...createAdvancedTimelineExecutors({
    assertPermission,
    createStaffingCaller,
    createTimelineCaller,
    createScopedCallerContext,
    resolveProjectIdentifier,
    resolveResourceIdentifier,
    parseIsoDate,
    fmtDate,
    isAssistantToolErrorResult,
    toAssistantIndexedFieldError,
    toAssistantTimelineMutationError,
  }),
  ...createAllocationPlanningExecutors({
    assertPermission,
    createAllocationCaller,
    createTimelineCaller,
    createScopedCallerContext,
    resolveProjectIdentifier,
    resolveResourceIdentifier,
    parseIsoDate,
    parseOptionalIsoDate,
    fmtDate,
    toAssistantAllocationNotFoundError,
  }),
  ...createVacationHolidayExecutors({
    createEntitlementCaller,
    createVacationCaller,
    createHolidayCalendarCaller,
    createScopedCallerContext,
    resolveResourceIdentifier,
    resolveHolidayPeriod,
    resolveEntityOrAssistantError,
    assertAdminRole,
    fmtDate,
    formatHolidayCalendar,
    formatHolidayCalendarEntry,
    toAssistantHolidayCalendarMutationError,
    toAssistantHolidayCalendarNotFoundError,
    toAssistantHolidayEntryMutationError,
    toAssistantHolidayEntryNotFoundError,
  }),
  ...createRolesAnalyticsExecutors({
    createRoleCaller,
    createResourceCaller,
    createDashboardCaller,
    createScopedCallerContext,
    resolveResourceIdentifier,
    toAssistantRoleMutationError,
  }),
  ...createClientsOrgUnitsExecutors({
    createClientCaller,
    createOrgUnitCaller,
    createScopedCallerContext,
    toAssistantClientMutationError,
    toAssistantOrgUnitMutationError,
  }),
  ...createChargeabilityComputationExecutors({
    assertPermission,
    createChargeabilityReportCaller,
    createComputationGraphCaller,
    createScopedCallerContext,
    resolveResourceIdentifier,
    resolveProjectIdentifier,
  }),
  ...createBlueprintsRateCardsExecutors({
    createBlueprintCaller,
    createRateCardCaller,
    createScopedCallerContext,
    resolveResourceIdentifier,
    resolveEntityOrAssistantError,
    parseOptionalIsoDate,
    fmtDate,
  }),
  ...createDashboardInsightsReportsExecutors({
    assertPermission,
    createDashboardCaller,
    createInsightsCaller,
    createReportCaller,
    createScopedCallerContext,
  }),
  ...createPlanningNavigationExecutors({
    createEstimateCaller,
    createClientCaller,
    createOrgUnitCaller,
    createTimelineCaller,
    createScopedCallerContext,
    resolveProjectIdentifier,
    parseIsoDate,
  }),
  ...createScenarioRateAnalysisExecutors({
    assertPermission,
    createRateCardCaller,
    createScenarioCaller,
    createInsightsCaller,
    createScopedCallerContext,
    fmtEur,
  }),
  ...createCommentExecutors({
    createCommentCaller,
    createScopedCallerContext,
    toAssistantCommentCreationError,
    toAssistantCommentResolveError,
  }),
  ...createAuditHistoryExecutors({
    createAuditLogCaller,
    createScopedCallerContext,
  }),
  ...createVacationEntitlementExecutors({
    createVacationCaller,
    createEntitlementCaller,
    createScopedCallerContext,
    resolveResourceIdentifier,
    parseIsoDate,
    fmtDate,
    parseAssistantVacationRequestType,
    toAssistantVacationCreationError,
    toAssistantVacationMutationError,
    toAssistantEntitlementMutationError,
  }),

  // ── ESTIMATES ──
  ...createEstimateExecutors({
    assertPermission,
    createEstimateCaller,
    createScopedCallerContext,
    resolveProjectIdentifier,
    toAssistantEstimateNotFoundError,
    toAssistantEstimateReadError,
    toAssistantEstimateCreationError,
    toAssistantEstimateMutationError,
  }),

  // ── ROLES ──

  // ── CLIENTS ──

  // ── ADMIN / CONFIG ──

  ...createCountryReadmodelExecutors({
    createCountryCaller,
    createScopedCallerContext,
    formatCountry,
    toAssistantCountryNotFoundError,
  }),
  ...createCountryMetroAdminExecutors({
    createCountryCaller,
    createScopedCallerContext,
    assertAdminRole,
    formatCountry,
    toAssistantCountryMutationError,
    toAssistantMetroCityMutationError,
  }),
  ...createConfigReadmodelExecutors({
    createManagementLevelCaller,
    createUtilizationCategoryCaller,
    createCalculationRuleCaller,
    createEffortRuleCaller,
    createExperienceMultiplierCaller,
    createScopedCallerContext,
  }),
  ...createUserAdminExecutors({
    createUserCaller,
    createScopedCallerContext,
    toAssistantUserMutationError,
    toAssistantUserResourceLinkError,
  }),
  ...createUserSelfServiceExecutors({
    createUserCaller,
    createScopedCallerContext,
    toAssistantCurrentUserError: toAssistantUserMutationError,
    toAssistantTotpEnableError,
  }),
  ...createNotificationsTasksExecutors({
    createNotificationCaller,
    createScopedCallerContext,
    parseDateTime,
    parseOptionalDateTime,
    toAssistantTaskNotFoundError,
    toAssistantTaskActionError,
    toAssistantTaskAssignmentError,
    toAssistantBroadcastNotFoundError,
    toAssistantReminderNotFoundError,
    toAssistantNotificationReadError,
    toAssistantNotificationDeletionError,
    toAssistantReminderCreationError,
    toAssistantNotificationCreationError,
  }),

  ...createImportExportDispoExecutors({
    assertPermission,
    createImportExportCaller,
    createDispoCaller,
    createScopedCallerContext,
    toAssistantDispoImportBatchNotFoundError,
  }),

  ...createSettingsAdminExecutors({
    createSettingsCaller,
    createSystemRoleConfigCaller,
    createWebhookCaller,
    createAuditLogCaller,
    createProjectCaller,
    createScopedCallerContext,
    parseIsoDate,
    resolveProjectIdentifier,
    sanitizeWebhook,
    sanitizeWebhookList,
    toAssistantWebhookNotFoundError,
    toAssistantWebhookMutationError,
    toAssistantAuditLogEntryNotFoundError,
  }),
};

// ─── Executor ───────────────────────────────────────────────────────────────

export interface ToolAction {
  type: string;
  url?: string;
  scope?: string[];
  description?: string;
}

export interface ToolResult {
  content: string;
  action?: ToolAction;
  data?: unknown;
}

export async function executeTool(
  name: string,
  args: string,
  ctx: ToolContext,
): Promise<ToolResult> {
  const executor = executors[name as keyof typeof executors];
  if (!executor) return { content: JSON.stringify({ error: `Unknown tool: ${name}` }) };

  try {
    const toolDefinition = TOOL_DEFINITIONS_BY_NAME.get(name);
    const accessFailure = toolDefinition
      ? getAssistantToolAccessFailure(toolDefinition, ctx)
      : null;
    if (accessFailure) {
      throw toAssistantToolAccessError(accessFailure);
    }

    const params = JSON.parse(args);

    // Audit-log all mutation tool executions (EGAI 4.1.3.1 / IAAI 3.6.26)
    if (MUTATION_TOOLS.has(name)) {
      logger.info(
        { tool: name, params, userId: ctx.userId, userRole: ctx.userRole },
        "AI assistant mutation tool executed",
      );
    }

    const result = await executor(params, ctx);

    // Detect action payloads (e.g. navigation, invalidation)
    if (result && typeof result === "object" && "__action" in (result as Record<string, unknown>)) {
      const actionResult = result as Record<string, unknown>;
      const actionType = actionResult.__action as string;

      if (actionType === "navigate") {
        const url = actionResult.url as string;
        const desc = (actionResult.description as string | undefined) ?? url;
        return {
          content: JSON.stringify({ description: desc }),
          data: { description: desc },
          action: { type: "navigate", url, description: desc },
        };
      }

      if (actionType === "invalidate") {
        const scope = actionResult.scope as string[];
        // Strip __action, scope, and large data from the result sent back to the AI
        const { __action: _, scope: _s, coverImageUrl: _img, ...rest } = actionResult;
        const content = JSON.stringify(rest);
        return {
          content: content.length > 4000 ? content.slice(0, 4000) + '..."' : content,
          data: rest,
          action: { type: "invalidate", scope },
        };
      }
    }

    // Cap tool result size to prevent oversized OpenAI conversation payloads
    const content = typeof result === "string" ? result : JSON.stringify(result);
    return {
      content: content.length > 8000 ? content.slice(0, 8000) + '..."' : content,
      ...(typeof result === "string" ? {} : { data: result }),
    };
  } catch (err) {
    const normalizedError = normalizeAssistantExecutionError(err);
    logger.error(
      {
        tool: name,
        userId: ctx.userId,
        userRole: ctx.userRole,
        error: err instanceof Error ? { message: err.message, stack: err.stack } : err,
      },
      "AI assistant tool execution failed",
    );
    return { content: JSON.stringify(normalizedError), data: normalizedError };
  }
}
