/**
 * AI Assistant Tool definitions for OpenAI Function Calling.
 * Each tool has a JSON schema (for the AI) and an execute function (for the server).
 *
 * Helpers, callers, and access control are extracted into:
 *   - ./assistant-tools/helpers.ts    (~1,400 lines of formatters, error converters, parsers)
 *   - ./assistant-tools/callers.ts    (35 tRPC caller factory bindings)
 *   - ./assistant-tools/access-control.ts (role/permission gating logic)
 */

import { PermissionKey } from "@nexus/shared";
import { createReadOnlyProxy } from "../lib/read-only-prisma.js";
import { logger } from "../lib/logger.js";

// ─── Extracted modules ──────────────────────────────────────────────────────
import {
  createChargeabilityReportCaller,
  createComputationGraphCaller,
  createTimelineCaller,
  createAuditLogCaller,
  createImportExportCaller,
  createDispoCaller,
  createResourceCaller,
  createSettingsCaller,
  createSystemRoleConfigCaller,
  createUserCaller,
  createNotificationCaller,
  createEstimateCaller,
  createWebhookCaller,
  createCountryCaller,
  createHolidayCalendarCaller,
  createBlueprintCaller,
  createRoleCaller,
  createClientCaller,
  createOrgUnitCaller,
  createProjectCaller,
  createRateCardCaller,
  createReportCaller,
  createVacationCaller,
  createEntitlementCaller,
  createCommentCaller,
  createManagementLevelCaller,
  createUtilizationCategoryCaller,
  createCalculationRuleCaller,
  createEffortRuleCaller,
  createExperienceMultiplierCaller,
  createDashboardCaller,
  createInsightsCaller,
  createScenarioCaller,
  createAllocationCaller,
  createStaffingCaller,
} from "./assistant-tools/callers.js";
import {
  assertPermission,
  assertAdminRole,
  fmtDate,
  formatHolidayCalendarEntry,
  formatHolidayCalendar,
  formatCountry,
  resolveHolidayPeriod,
  parseIsoDate,
  parseOptionalIsoDate,
  parseDateTime,
  parseOptionalDateTime,
  isAssistantToolErrorResult,
  toAssistantIndexedFieldError,
  toAssistantNotFoundError,
  toAssistantAllocationNotFoundError,
  toAssistantProjectNotFoundError,
  toAssistantTimelineMutationError,
  toAssistantVacationMutationError,
  toAssistantProjectCreationError,
  toAssistantDemandCreationError,
  toAssistantDemandFillError,
  toAssistantEstimateNotFoundError,
  toAssistantEstimateReadError,
  toAssistantEstimateMutationError,
  toAssistantEstimateCreationError,
  toAssistantHolidayCalendarNotFoundError,
  toAssistantHolidayCalendarMutationError,
  toAssistantHolidayEntryMutationError,
  toAssistantHolidayEntryNotFoundError,
  toAssistantRoleMutationError,
  toAssistantClientMutationError,
  toAssistantOrgUnitMutationError,
  toAssistantCountryMutationError,
  toAssistantResourceCreationError,
  toAssistantResourceMutationError,
  toAssistantProjectMutationError,
  toAssistantMetroCityMutationError,
  toAssistantVacationCreationError,
  toAssistantEntitlementMutationError,
  toAssistantUserMutationError,
  toAssistantUserResourceLinkError,
  toAssistantTotpEnableError,
  toAssistantWebhookNotFoundError,
  toAssistantWebhookMutationError,
  toAssistantAuditLogEntryNotFoundError,
  toAssistantTaskActionError,
  toAssistantTaskAssignmentError,
  toAssistantBroadcastNotFoundError,
  toAssistantDispoImportBatchNotFoundError,
  toAssistantReminderNotFoundError,
  toAssistantNotificationReadError,
  toAssistantNotificationDeletionError,
  toAssistantReminderCreationError,
  toAssistantCommentResolveError,
  toAssistantCommentCreationError,
  toAssistantNotificationCreationError,
  toAssistantCountryNotFoundError,
  toAssistantTaskNotFoundError,
  fmtEur,
  normalizeAssistantExecutionError,
  resolveEntityOrAssistantError,
  resolveProjectIdentifier,
  resolveResourceIdentifier,
  resolveResponsiblePerson,
  createScopedCallerContext,
  sanitizeWebhook,
  sanitizeWebhookList,
  parseAssistantVacationRequestType,
} from "./assistant-tools/helpers.js";
import {
  LEGACY_MONOLITHIC_TOOL_ACCESS,
  getAssistantToolAccessFailure,
  toAssistantToolAccessError,
  getAvailableAssistantToolsForContext as getAvailableToolsForCtx_,
} from "./assistant-tools/access-control.js";
export { canAccessAssistantTool } from "./assistant-tools/access-control.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",
  "create_estimate",
  "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",
]);

// Callers imported from ./assistant-tools/callers.ts

// Helpers imported from ./assistant-tools/helpers.ts

// ─── 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]),
);

// Access control imported from ./assistant-tools/access-control.ts

export function getAvailableAssistantToolsForContext(
  permissions: Set<PermissionKey>,
  userRole: string,
): ToolDef[] {
  return getAvailableToolsForCtx_(TOOL_DEFINITIONS, permissions, userRole);
}

// ─── 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);

    // EGAI 4.1.1.2 / IAAI 3.6.22 — read-only tools get a DB proxy that blocks writes
    const isMutation = MUTATION_TOOLS.has(name);
    const effectiveCtx = isMutation ? ctx : { ...ctx, db: createReadOnlyProxy(ctx.db) };

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

    const result = await executor(params, effectiveCtx);

    // EGAI 4.3.1.2 — validate tool result against schema if defined
    if (toolDefinition?.resultSchema && result != null) {
      const validation = toolDefinition.resultSchema.safeParse(result);
      if (!validation.success) {
        logger.warn(
          { tool: name, errors: validation.error.issues },
          "Tool result failed schema validation — proceeding with unvalidated result",
        );
      }
    }

    // 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 };
  }
}
