import { isAiConfigured } from "../../ai-client.js";
import { resolveSystemSettingsRuntime } from "../../lib/system-settings-runtime.js";
import type { TRPCContext } from "../../trpc.js";
import { SystemRole } from "@capakraken/shared";
import { withToolAccess, type ToolContext, type ToolDef, type ToolExecutor } from "./shared.js";

export const settingsAdminToolDefinitions: ToolDef[] = withToolAccess([
  {
    type: "function",
    function: {
      name: "get_system_settings",
      description: "Get sanitized system settings through the real settings router. Admin role required.",
      parameters: {
        type: "object",
        properties: {},
      },
    },
  },
  {
    type: "function",
    function: {
      name: "update_system_settings",
      description: "Update non-secret system settings through the real settings router. Runtime secrets must be provisioned via deployment environment or secret manager. Admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          aiProvider: { type: "string", enum: ["openai", "azure"] },
          azureOpenAiEndpoint: { type: "string" },
          azureOpenAiDeployment: { type: "string" },
          azureApiVersion: { type: "string" },
          aiMaxCompletionTokens: { type: "integer" },
          aiTemperature: { type: "number" },
          aiSummaryPrompt: { type: "string" },
          scoreWeights: { type: "object" },
          scoreVisibleRoles: { type: "array", items: { type: "string" } },
          smtpHost: { type: "string" },
          smtpPort: { type: "integer" },
          smtpUser: { type: "string" },
          smtpFrom: { type: "string" },
          smtpTls: { type: "boolean" },
          anonymizationEnabled: { type: "boolean" },
          anonymizationDomain: { type: "string" },
          anonymizationMode: { type: "string", enum: ["global"] },
          azureDalleDeployment: { type: "string" },
          azureDalleEndpoint: { type: "string" },
          geminiModel: { type: "string" },
          imageProvider: { type: "string", enum: ["dalle", "gemini"] },
          vacationDefaultDays: { type: "integer" },
          timelineUndoMaxSteps: { type: "integer" },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "clear_stored_runtime_secrets",
      description: "Clear legacy database-stored runtime secrets after they have been migrated to deployment secret management. Admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {},
      },
    },
  },
  {
    type: "function",
    function: {
      name: "test_ai_connection",
      description: "Run the real AI connection test from system settings. Admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {},
      },
    },
  },
  {
    type: "function",
    function: {
      name: "test_smtp_connection",
      description: "Run the real SMTP connection test from system settings. Admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {},
      },
    },
  },
  {
    type: "function",
    function: {
      name: "test_gemini_connection",
      description: "Run the real Gemini connection test from system settings. Admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {},
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_ai_configured",
      description: "Get whether AI is configured for the current system via the real settings router. Admin role required.",
      parameters: {
        type: "object",
        properties: {},
      },
    },
  },
  {
    type: "function",
    function: {
      name: "list_system_role_configs",
      description: "List system role configuration defaults via the real system-role-config router. Admin role required.",
      parameters: {
        type: "object",
        properties: {},
      },
    },
  },
  {
    type: "function",
    function: {
      name: "update_system_role_config",
      description: "Update one system role configuration via the real system-role-config router. Admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          role: { type: "string", description: "System role key." },
          label: { type: "string", description: "Optional role label." },
          description: { type: "string", description: "Optional role description." },
          color: { type: "string", description: "Optional role color." },
          defaultPermissions: { type: "array", items: { type: "string" }, description: "Optional default permission set." },
        },
        required: ["role"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "list_webhooks",
      description: "List webhooks via the real webhook router. Secrets are masked in assistant responses. Admin role required.",
      parameters: {
        type: "object",
        properties: {},
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_webhook",
      description: "Get one webhook via the real webhook router. Secrets are masked in assistant responses. Admin role required.",
      parameters: {
        type: "object",
        properties: {
          id: { type: "string", description: "Webhook ID." },
        },
        required: ["id"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "create_webhook",
      description: "Create a webhook via the real webhook router. Secrets are masked in assistant responses. Admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          name: { type: "string", description: "Webhook name." },
          url: { type: "string", description: "Webhook target URL." },
          secret: { type: "string", description: "Optional webhook signing secret." },
          events: { type: "array", items: { type: "string" }, description: "Subscribed webhook events." },
          isActive: { type: "boolean", description: "Whether the webhook is active. Default: true." },
        },
        required: ["name", "url", "events"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "update_webhook",
      description: "Update a webhook via the real webhook router. Secrets are masked in assistant responses. Admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          id: { type: "string", description: "Webhook ID." },
          data: {
            type: "object",
            properties: {
              name: { type: "string" },
              url: { type: "string" },
              secret: { type: "string" },
              events: { type: "array", items: { type: "string" } },
              isActive: { type: "boolean" },
            },
          },
        },
        required: ["id", "data"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "delete_webhook",
      description: "Delete a webhook via the real webhook router. Admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          id: { type: "string", description: "Webhook ID." },
        },
        required: ["id"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "test_webhook",
      description: "Send a real test payload to a webhook via the real webhook router. Admin role required. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          id: { type: "string", description: "Webhook ID." },
        },
        required: ["id"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "list_audit_log_entries",
      description: "List audit log entries with full audit-router filters and cursor pagination. Controller/manager/admin roles only.",
      parameters: {
        type: "object",
        properties: {
          entityType: { type: "string", description: "Optional entity type filter." },
          entityId: { type: "string", description: "Optional entity ID filter." },
          userId: { type: "string", description: "Optional user ID filter." },
          action: { type: "string", description: "Optional action filter such as CREATE, UPDATE, DELETE, SHIFT, IMPORT." },
          source: { type: "string", description: "Optional source filter such as ui or assistant." },
          startDate: { type: "string", description: "Optional start date in YYYY-MM-DD." },
          endDate: { type: "string", description: "Optional end date in YYYY-MM-DD." },
          search: { type: "string", description: "Optional case-insensitive search across entity name, summary, and entity type." },
          limit: { type: "integer", description: "Max results. Default: 50, max: 100." },
          cursor: { type: "string", description: "Optional pagination cursor (last seen audit entry ID)." },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_audit_log_entry",
      description: "Get one audit log entry including the full changes payload. Controller/manager/admin roles only.",
      parameters: {
        type: "object",
        properties: {
          id: { type: "string", description: "Audit log entry ID." },
        },
        required: ["id"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_audit_log_timeline",
      description: "Get audit log entries grouped by day for a time window. Controller/manager/admin roles only.",
      parameters: {
        type: "object",
        properties: {
          startDate: { type: "string", description: "Optional start date in YYYY-MM-DD." },
          endDate: { type: "string", description: "Optional end date in YYYY-MM-DD." },
          limit: { type: "integer", description: "Max entries. Default: 200, max: 500." },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_audit_activity_summary",
      description: "Get audit activity totals by entity type, action, and user for a date range. Controller/manager/admin roles only.",
      parameters: {
        type: "object",
        properties: {
          startDate: { type: "string", description: "Optional start date in YYYY-MM-DD." },
          endDate: { type: "string", description: "Optional end date in YYYY-MM-DD." },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_shoring_ratio",
      description: "Get the onshore/offshore staffing ratio for a project. Higher offshore is better (cost-efficient). The threshold is the MINIMUM offshore target. Shows country breakdown and whether the target is met.",
      parameters: {
        type: "object",
        properties: {
          projectId: { type: "string", description: "Project ID or short code" },
        },
        required: ["projectId"],
      },
    },
  },
], {
  get_system_settings: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  update_system_settings: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  clear_stored_runtime_secrets: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  test_ai_connection: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  test_smtp_connection: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  test_gemini_connection: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  get_ai_configured: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  list_system_role_configs: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  update_system_role_config: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  list_webhooks: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  get_webhook: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  create_webhook: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  update_webhook: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  delete_webhook: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  test_webhook: {
    allowedSystemRoles: [SystemRole.ADMIN],
  },
  list_audit_log_entries: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  get_audit_log_entry: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  get_audit_log_timeline: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  get_audit_activity_summary: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  get_shoring_ratio: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
});

type SettingsAdminDeps = {
  createSettingsCaller: (ctx: TRPCContext) => {
    getSystemSettings: () => Promise<unknown>;
    updateSystemSettings: (params: {
      aiProvider?: "openai" | "azure";
      azureOpenAiEndpoint?: string;
      azureOpenAiDeployment?: string;
      azureApiVersion?: string;
      aiMaxCompletionTokens?: number;
      aiTemperature?: number;
      aiSummaryPrompt?: string;
      scoreWeights?: {
        skillDepth: number;
        skillBreadth: number;
        costEfficiency: number;
        chargeability: number;
        experience: number;
      };
      scoreVisibleRoles?: SystemRole[];
      smtpHost?: string;
      smtpPort?: number;
      smtpUser?: string;
      smtpFrom?: string;
      smtpTls?: boolean;
      anonymizationEnabled?: boolean;
      anonymizationDomain?: string;
      anonymizationMode?: "global";
      azureDalleDeployment?: string;
      azureDalleEndpoint?: string;
      geminiModel?: string;
      imageProvider?: "dalle" | "gemini";
      vacationDefaultDays?: number;
      timelineUndoMaxSteps?: number;
    }) => Promise<unknown>;
    clearStoredRuntimeSecrets: () => Promise<unknown>;
    testAiConnection: () => Promise<unknown>;
    testSmtpConnection: () => Promise<unknown>;
    testGeminiConnection: () => Promise<unknown>;
  };
  createSystemRoleConfigCaller: (ctx: TRPCContext) => {
    list: () => Promise<unknown>;
    update: (params: {
      role: string;
      label?: string;
      description?: string | null;
      color?: string | null;
      defaultPermissions?: string[];
    }) => Promise<unknown>;
  };
  createWebhookCaller: (ctx: TRPCContext) => {
    list: () => Promise<Array<{ secret?: string | null }>>;
    getById: (params: { id: string }) => Promise<{ secret?: string | null }>;
    create: (params: {
      name: string;
      url: string;
      secret?: string;
      events: [string, ...string[]];
      isActive?: boolean;
    }) => Promise<{ secret?: string | null }>;
    update: (params: {
      id: string;
      data: {
        name?: string;
        url?: string;
        secret?: string | null;
        events?: [string, ...string[]];
        isActive?: boolean;
      };
    }) => Promise<{ secret?: string | null }>;
    delete: (params: { id: string }) => Promise<unknown>;
    test: (params: { id: string }) => Promise<unknown>;
  };
  createAuditLogCaller: (ctx: TRPCContext) => {
    listDetail: (params: {
      entityType?: string;
      entityId?: string;
      userId?: string;
      action?: string;
      source?: string;
      startDate?: Date;
      endDate?: Date;
      search?: string;
      limit?: number;
      cursor?: string;
    }) => Promise<{ items: unknown[]; nextCursor?: string | null }>;
    getByIdDetail: (params: { id: string }) => Promise<unknown>;
    getTimelineDetail: (params: {
      startDate?: Date;
      endDate?: Date;
      limit?: number;
    }) => Promise<unknown>;
    getActivitySummary: (params: {
      startDate?: Date;
      endDate?: Date;
    }) => Promise<unknown>;
  };
  createProjectCaller: (ctx: TRPCContext) => {
    getShoringRatio: (params: { projectId: string }) => Promise<{
      totalHours: number;
      byCountry: Record<string, { pct: number; resourceCount: number }>;
      offshoreRatio: number;
      threshold: number;
      onshoreRatio: number;
      onshoreCountryCode: string;
      unknownCount: number;
    }>;
  };
  createScopedCallerContext: (ctx: ToolContext) => TRPCContext;
  parseIsoDate: (value: string, fieldName: string) => Date;
  resolveProjectIdentifier: (
    ctx: ToolContext,
    identifier: string,
  ) => Promise<{ id: string; name: string; shortCode: string } | { error: string }>;
  sanitizeWebhook: <T extends { secret?: string | null }>(webhook: T) => Omit<T, "secret"> & { hasSecret: boolean };
  sanitizeWebhookList: <T extends { secret?: string | null }>(webhooks: T[]) => Array<Omit<T, "secret"> & { hasSecret: boolean }>;
  toAssistantWebhookNotFoundError: (error: unknown) => unknown;
  toAssistantWebhookMutationError: (error: unknown, action?: "create" | "update") => unknown;
  toAssistantAuditLogEntryNotFoundError: (error: unknown) => unknown;
};

export function createSettingsAdminExecutors(deps: SettingsAdminDeps): Record<string, ToolExecutor> {
  return {
    async get_system_settings(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createSettingsCaller(deps.createScopedCallerContext(ctx));
      return caller.getSystemSettings();
    },

    async update_system_settings(params: {
      aiProvider?: "openai" | "azure";
      azureOpenAiEndpoint?: string;
      azureOpenAiDeployment?: string;
      azureApiVersion?: string;
      aiMaxCompletionTokens?: number;
      aiTemperature?: number;
      aiSummaryPrompt?: string;
      scoreWeights?: {
        skillDepth: number;
        skillBreadth: number;
        costEfficiency: number;
        chargeability: number;
        experience: number;
      };
      scoreVisibleRoles?: SystemRole[];
      smtpHost?: string;
      smtpPort?: number;
      smtpUser?: string;
      smtpFrom?: string;
      smtpTls?: boolean;
      anonymizationEnabled?: boolean;
      anonymizationDomain?: string;
      anonymizationMode?: "global";
      azureDalleDeployment?: string;
      azureDalleEndpoint?: string;
      geminiModel?: string;
      imageProvider?: "dalle" | "gemini";
      vacationDefaultDays?: number;
      timelineUndoMaxSteps?: number;
    }, ctx: ToolContext) {
      const caller = deps.createSettingsCaller(deps.createScopedCallerContext(ctx));
      return caller.updateSystemSettings(params);
    },

    async clear_stored_runtime_secrets(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createSettingsCaller(deps.createScopedCallerContext(ctx));
      return caller.clearStoredRuntimeSecrets();
    },

    async test_ai_connection(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createSettingsCaller(deps.createScopedCallerContext(ctx));
      return caller.testAiConnection();
    },

    async test_smtp_connection(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createSettingsCaller(deps.createScopedCallerContext(ctx));
      return caller.testSmtpConnection();
    },

    async test_gemini_connection(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createSettingsCaller(deps.createScopedCallerContext(ctx));
      return caller.testGeminiConnection();
    },

    async get_ai_configured(_params: Record<string, never>, ctx: ToolContext) {
      const settings = resolveSystemSettingsRuntime(await ctx.db.systemSettings.findUnique({
        where: { id: "singleton" },
        select: {
          aiProvider: true,
          azureOpenAiEndpoint: true,
          azureOpenAiDeployment: true,
          azureOpenAiApiKey: true,
        },
      }));
      return { configured: isAiConfigured(settings) };
    },

    async list_system_role_configs(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createSystemRoleConfigCaller(deps.createScopedCallerContext(ctx));
      return caller.list();
    },

    async update_system_role_config(params: {
      role: string;
      label?: string;
      description?: string | null;
      color?: string | null;
      defaultPermissions?: string[];
    }, ctx: ToolContext) {
      const caller = deps.createSystemRoleConfigCaller(deps.createScopedCallerContext(ctx));
      return caller.update(params);
    },

    async list_webhooks(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createWebhookCaller(deps.createScopedCallerContext(ctx));
      const webhooks = await caller.list();
      return deps.sanitizeWebhookList(webhooks);
    },

    async get_webhook(params: {
      id: string;
    }, ctx: ToolContext) {
      const caller = deps.createWebhookCaller(deps.createScopedCallerContext(ctx));
      let webhook;
      try {
        webhook = await caller.getById({ id: params.id });
      } catch (error) {
        const mapped = deps.toAssistantWebhookNotFoundError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }
      return deps.sanitizeWebhook(webhook);
    },

    async create_webhook(params: {
      name: string;
      url: string;
      secret?: string;
      events: string[];
      isActive?: boolean;
    }, ctx: ToolContext) {
      const caller = deps.createWebhookCaller(deps.createScopedCallerContext(ctx));
      let webhook;
      try {
        webhook = await caller.create({
          name: params.name,
          url: params.url,
          events: params.events as [string, ...string[]],
          ...(params.secret !== undefined ? { secret: params.secret } : {}),
          ...(params.isActive !== undefined ? { isActive: params.isActive } : {}),
        });
      } catch (error) {
        const mapped = deps.toAssistantWebhookMutationError(error, "create");
        if (mapped) {
          return mapped;
        }
        throw error;
      }
      return deps.sanitizeWebhook(webhook);
    },

    async update_webhook(params: {
      id: string;
      data: {
        name?: string;
        url?: string;
        secret?: string | null;
        events?: string[];
        isActive?: boolean;
      };
    }, ctx: ToolContext) {
      const caller = deps.createWebhookCaller(deps.createScopedCallerContext(ctx));
      let webhook;
      try {
        webhook = await caller.update({
          id: params.id,
          data: {
            ...(params.data.name !== undefined ? { name: params.data.name } : {}),
            ...(params.data.url !== undefined ? { url: params.data.url } : {}),
            ...(params.data.secret !== undefined ? { secret: params.data.secret } : {}),
            ...(params.data.events !== undefined ? { events: params.data.events as [string, ...string[]] } : {}),
            ...(params.data.isActive !== undefined ? { isActive: params.data.isActive } : {}),
          },
        });
      } catch (error) {
        const mapped = deps.toAssistantWebhookMutationError(error, "update");
        if (mapped) {
          return mapped;
        }
        throw error;
      }
      return deps.sanitizeWebhook(webhook);
    },

    async delete_webhook(params: {
      id: string;
    }, ctx: ToolContext) {
      const caller = deps.createWebhookCaller(deps.createScopedCallerContext(ctx));
      try {
        await caller.delete({ id: params.id });
      } catch (error) {
        const mapped = deps.toAssistantWebhookNotFoundError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }
      return { ok: true, id: params.id };
    },

    async test_webhook(params: {
      id: string;
    }, ctx: ToolContext) {
      const caller = deps.createWebhookCaller(deps.createScopedCallerContext(ctx));
      try {
        return await caller.test({ id: params.id });
      } catch (error) {
        const mapped = deps.toAssistantWebhookNotFoundError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }
    },

    async list_audit_log_entries(params: {
      entityType?: string;
      entityId?: string;
      userId?: string;
      action?: string;
      source?: string;
      startDate?: string;
      endDate?: string;
      search?: string;
      limit?: number;
      cursor?: string;
    }, ctx: ToolContext) {
      const caller = deps.createAuditLogCaller(deps.createScopedCallerContext(ctx));
      const result = await caller.listDetail({
        ...(params.entityType ? { entityType: params.entityType } : {}),
        ...(params.entityId ? { entityId: params.entityId } : {}),
        ...(params.userId ? { userId: params.userId } : {}),
        ...(params.action ? { action: params.action } : {}),
        ...(params.source ? { source: params.source } : {}),
        ...(params.startDate ? { startDate: deps.parseIsoDate(params.startDate, "startDate") } : {}),
        ...(params.endDate ? { endDate: deps.parseIsoDate(params.endDate, "endDate") } : {}),
        ...(params.search ? { search: params.search } : {}),
        ...(params.cursor ? { cursor: params.cursor } : {}),
        ...(params.limit !== undefined ? { limit: Math.min(Math.max(params.limit, 1), 100) } : {}),
      });

      return {
        filters: {
          entityType: params.entityType ?? null,
          entityId: params.entityId ?? null,
          userId: params.userId ?? null,
          action: params.action ?? null,
          source: params.source ?? null,
          startDate: params.startDate ?? null,
          endDate: params.endDate ?? null,
          search: params.search ?? null,
        },
        itemCount: result.items.length,
        nextCursor: result.nextCursor ?? null,
        items: result.items,
      };
    },

    async get_audit_log_entry(params: {
      id: string;
    }, ctx: ToolContext) {
      const caller = deps.createAuditLogCaller(deps.createScopedCallerContext(ctx));
      try {
        return await caller.getByIdDetail({ id: params.id });
      } catch (error) {
        const mapped = deps.toAssistantAuditLogEntryNotFoundError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }
    },

    async get_audit_log_timeline(params: {
      startDate?: string;
      endDate?: string;
      limit?: number;
    }, ctx: ToolContext) {
      const caller = deps.createAuditLogCaller(deps.createScopedCallerContext(ctx));
      return caller.getTimelineDetail({
        ...(params.startDate ? { startDate: deps.parseIsoDate(params.startDate, "startDate") } : {}),
        ...(params.endDate ? { endDate: deps.parseIsoDate(params.endDate, "endDate") } : {}),
        ...(params.limit !== undefined ? { limit: Math.min(Math.max(params.limit, 1), 500) } : {}),
      });
    },

    async get_audit_activity_summary(params: {
      startDate?: string;
      endDate?: string;
    }, ctx: ToolContext) {
      const caller = deps.createAuditLogCaller(deps.createScopedCallerContext(ctx));
      return caller.getActivitySummary({
        ...(params.startDate ? { startDate: deps.parseIsoDate(params.startDate, "startDate") } : {}),
        ...(params.endDate ? { endDate: deps.parseIsoDate(params.endDate, "endDate") } : {}),
      });
    },

    async get_shoring_ratio(params: { projectId: string }, ctx: ToolContext) {
      const project = await deps.resolveProjectIdentifier(ctx, params.projectId);
      if ("error" in project) {
        return project;
      }

      const caller = deps.createProjectCaller(deps.createScopedCallerContext(ctx));
      const result = await caller.getShoringRatio({ projectId: project.id });

      if (result.totalHours <= 0) {
        return `Project "${project.name}" (${project.shortCode}): No active assignments — shoring ratio not available.`;
      }

      const countryParts = Object.entries(result.byCountry)
        .sort((a, b) => b[1].pct - a[1].pct)
        .map(([code, info]) => `${code} ${info.pct}% (${info.resourceCount} people)`)
        .join(", ");

      const status = result.offshoreRatio >= result.threshold
        ? `Target met (>=${result.threshold}% offshore)`
        : result.offshoreRatio >= result.threshold - 10
          ? `Close to target (${result.threshold}% offshore needed)`
          : `Below target — only ${result.offshoreRatio}% offshore, need ${result.threshold}%`;

      return `Project "${project.name}" (${project.shortCode}): ${result.onshoreRatio}% onshore (${result.onshoreCountryCode}), ${result.offshoreRatio}% offshore. ${status}. Breakdown: ${countryParts}.${result.unknownCount > 0 ? ` (${result.unknownCount} resource(s) without country)` : ""}`;
    },
  };
}
