import { PermissionKey, SystemRole } from "@capakraken/shared";
import type { TRPCContext } from "../../trpc.js";
import { withToolAccess, type ToolContext, type ToolDef, type ToolExecutor } from "./shared.js";

type RateLookupCandidate = {
  rateCardName: string;
  clientId: string | null;
  clientName: string | null;
  lineId: string;
  chapter: string | null;
  seniority: string | null;
  roleName: string | null;
  costRateCents: number;
  billRateCents: number | null;
  score: number;
};

type ScenarioSimulationResult = {
  baseline: {
    totalCostCents: number;
    totalHours: number;
    headcount: number;
    skillCount: number;
  };
  scenario: {
    totalCostCents: number;
    totalHours: number;
    headcount: number;
    skillCount: number;
  };
  delta: {
    costCents: number;
    hours: number;
    headcount: number;
    skillCoveragePct: number;
  };
  resourceImpacts: unknown[];
  warnings: string[];
  budgetCents: number;
};

type ScenarioRateAnalysisDeps = {
  assertPermission: (ctx: ToolContext, perm: PermissionKey) => void;
  createRateCardCaller: (ctx: TRPCContext) => {
    lookupBestMatch: (params: {
      clientId?: string;
      chapter?: string;
      managementLevelId?: string;
      roleName?: string;
      seniority?: string;
    }) => Promise<{
      message?: string;
      bestMatch: RateLookupCandidate | null;
      alternatives: RateLookupCandidate[];
      totalCandidates: number;
    }>;
  };
  createScenarioCaller: (ctx: TRPCContext) => {
    simulate: (params: {
      projectId: string;
      changes: Array<{
        assignmentId?: string;
        resourceId?: string;
        roleId?: string;
        startDate: Date;
        endDate: Date;
        hoursPerDay: number;
        remove?: boolean;
      }>;
    }) => Promise<ScenarioSimulationResult>;
  };
  createInsightsCaller: (ctx: TRPCContext) => {
    generateProjectNarrative: (params: { projectId: string }) => Promise<unknown>;
  };
  createScopedCallerContext: (ctx: ToolContext) => TRPCContext;
  fmtEur: (value: number) => string;
};

export const scenarioRateAnalysisToolDefinitions: ToolDef[] = withToolAccess([
  {
    type: "function",
    function: {
      name: "lookup_rate",
      description: "Find the best matching rate card line for given criteria (client, chapter, management level, role, seniority).",
      parameters: {
        type: "object",
        properties: {
          clientId: { type: "string", description: "Client ID to find rate card for" },
          chapter: { type: "string", description: "Chapter to match" },
          managementLevelId: { type: "string", description: "Management level ID to match" },
          roleName: { type: "string", description: "Role name to match" },
          seniority: { type: "string", description: "Seniority level to match" },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "simulate_scenario",
      description: "Run a read-only what-if staffing simulation for a project. Shows cost/hours/utilization impact of adding, removing, or changing resource assignments without persisting changes.",
      parameters: {
        type: "object",
        properties: {
          projectId: { type: "string", description: "Project ID" },
          changes: {
            type: "array",
            items: {
              type: "object",
              properties: {
                assignmentId: { type: "string", description: "Existing assignment ID to modify (omit for new)" },
                resourceId: { type: "string", description: "Resource ID" },
                roleId: { type: "string", description: "Role ID" },
                startDate: { type: "string", description: "Start date YYYY-MM-DD" },
                endDate: { type: "string", description: "End date YYYY-MM-DD" },
                hoursPerDay: { type: "number", description: "Hours per day" },
                remove: { type: "boolean", description: "Set true to remove an existing assignment" },
              },
              required: ["startDate", "endDate", "hoursPerDay"],
            },
            description: "Array of staffing changes to simulate",
          },
        },
        required: ["projectId", "changes"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "generate_project_narrative",
      description: "Generate an AI-powered executive narrative for a project covering budget, staffing, timeline risk, and action items. Requires AI to be configured.",
      parameters: {
        type: "object",
        properties: {
          projectId: { type: "string", description: "Project ID" },
        },
        required: ["projectId"],
      },
    },
  },
], {
  lookup_rate: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
    requiredPermissions: [PermissionKey.VIEW_COSTS],
  },
  simulate_scenario: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  generate_project_narrative: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
});

export function createScenarioRateAnalysisExecutors(
  deps: ScenarioRateAnalysisDeps,
): Record<string, ToolExecutor> {
  return {
    async lookup_rate(
      params: {
        clientId?: string;
        chapter?: string;
        managementLevelId?: string;
        roleName?: string;
        seniority?: string;
      },
      ctx: ToolContext,
    ) {
      deps.assertPermission(ctx, PermissionKey.VIEW_COSTS);
      const caller = deps.createRateCardCaller(deps.createScopedCallerContext(ctx));
      const result = await caller.lookupBestMatch(params);

      return {
        ...(result.message ? { message: result.message } : {}),
        bestMatch: result.bestMatch
          ? {
              ...result.bestMatch,
              costRate: deps.fmtEur(result.bestMatch.costRateCents),
              billRate: result.bestMatch.billRateCents ? deps.fmtEur(result.bestMatch.billRateCents) : null,
            }
          : null,
        alternatives: result.alternatives.map((alternative) => ({
          ...alternative,
          costRate: deps.fmtEur(alternative.costRateCents),
          billRate: alternative.billRateCents ? deps.fmtEur(alternative.billRateCents) : null,
        })),
        totalCandidates: result.totalCandidates,
      };
    },

    async simulate_scenario(
      params: {
        projectId: string;
        changes: Array<{
          assignmentId?: string;
          resourceId?: string;
          roleId?: string;
          startDate: string;
          endDate: string;
          hoursPerDay: number;
          remove?: boolean;
        }>;
      },
      ctx: ToolContext,
    ) {
      const caller = deps.createScenarioCaller(deps.createScopedCallerContext(ctx));
      const result = await caller.simulate({
        projectId: params.projectId,
        changes: params.changes.map((change) => ({
          ...change,
          startDate: new Date(change.startDate),
          endDate: new Date(change.endDate),
        })),
      });

      return {
        baseline: {
          ...result.baseline,
          totalCost: deps.fmtEur(result.baseline.totalCostCents),
        },
        scenario: {
          ...result.scenario,
          totalCost: deps.fmtEur(result.scenario.totalCostCents),
        },
        delta: {
          ...result.delta,
          cost: deps.fmtEur(result.delta.costCents),
        },
        resourceImpacts: result.resourceImpacts,
        warnings: result.warnings,
        budgetCents: result.budgetCents,
      };
    },

    async generate_project_narrative(
      params: { projectId: string },
      ctx: ToolContext,
    ) {
      const caller = deps.createInsightsCaller(deps.createScopedCallerContext(ctx));
      return caller.generateProjectNarrative({ projectId: params.projectId });
    },
  };
}
