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

type ReportEntity = "resource" | "project" | "assignment" | "resource_month";
type ReportFilterOperator = "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "contains" | "in";

type ReportFilter = {
  field: string;
  op: ReportFilterOperator;
  value: string;
};

type ReportQueryResult = {
  rows: unknown[];
  totalCount: number;
  columns: unknown;
  groups: unknown;
  explainability?: unknown;
};

type DashboardInsightsReportsDeps = {
  assertPermission: (ctx: ToolContext, perm: PermissionKey) => void;
  createDashboardCaller: (ctx: TRPCContext) => {
    getDetail: (params: { section?: string }) => Promise<unknown>;
    getSkillGapSummary: () => Promise<unknown>;
    getProjectHealthDetail: () => Promise<unknown>;
    getBudgetForecastDetail: () => Promise<unknown>;
  };
  createInsightsCaller: (ctx: TRPCContext) => {
    getAnomalyDetail: () => Promise<unknown>;
    getInsightsSummary: () => Promise<unknown>;
  };
  createReportCaller: (ctx: TRPCContext) => {
    getReportData: (params: {
      entity: ReportEntity;
      columns: string[];
      filters: ReportFilter[];
      periodMonth?: string;
      groupBy?: string;
      sortBy?: string;
      sortDir: "asc" | "desc";
      limit: number;
      offset: number;
    }) => Promise<ReportQueryResult>;
  };
  createScopedCallerContext: (ctx: ToolContext) => TRPCContext;
};

const REPORT_ENTITIES: ReportEntity[] = ["resource", "project", "assignment", "resource_month"];

export const dashboardInsightsReportsToolDefinitions: ToolDef[] = withToolAccess([
  {
    type: "function",
    function: {
      name: "get_dashboard_detail",
      description: "Get detailed dashboard data: peak allocation times, top-value resources, demand pipeline, chargeability overview, project health risks, and skill gap staffing pressure.",
      parameters: {
        type: "object",
        properties: {
          section: {
            type: "string",
            description: "Which section: peak_times, top_resources, demand_pipeline, chargeability_overview, project_health, skill_gaps, or all",
          },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "detect_anomalies",
      description: "Detect anomalies across all active projects: budget burn rate issues, staffing gaps, utilization outliers, and timeline overruns.",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "get_skill_gaps",
      description: "Analyze skill supply vs demand across all active projects. Returns which skills are in short supply relative to demand requirements.",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "get_project_health",
      description: "Get health scores for all active projects based on budget utilization, staffing completeness, and timeline status.",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "get_budget_forecast",
      description: "Get budget utilization and burn rate per active project. Shows total budget, spent, remaining, and whether burn is ahead or behind schedule.",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "get_insights_summary",
      description: "Get a summary of anomaly counts by category (budget, staffing, timeline, utilization) plus critical count.",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "run_report",
      description: "Run a dynamic report query on resources, projects, assignments, or resource-month rows with flexible column selection and filtering.",
      parameters: {
        type: "object",
        properties: {
          entity: {
            type: "string",
            enum: ["resource", "project", "assignment", "resource_month"],
            description: "Entity type to query",
          },
          columns: {
            type: "array",
            items: { type: "string" },
            description: "Column keys to include (e.g. 'displayName', 'chapter', 'country.name')",
          },
          filters: {
            type: "array",
            items: {
              type: "object",
              properties: {
                field: { type: "string", description: "Field to filter on" },
                op: { type: "string", enum: ["eq", "neq", "gt", "lt", "gte", "lte", "contains", "in"], description: "Filter operator" },
                value: { type: "string", description: "Filter value (string)" },
              },
              required: ["field", "op", "value"],
            },
            description: "Filters to apply",
          },
          periodMonth: {
            type: "string",
            description: "Required for resource_month reports. Format: YYYY-MM",
          },
          groupBy: {
            type: "string",
            description: "Optional scalar field used to group result rows into labeled sections.",
          },
          sortBy: {
            type: "string",
            description: "Optional scalar field used to sort rows within the grouped result.",
          },
          sortDir: {
            type: "string",
            enum: ["asc", "desc"],
            description: "Sort direction for sortBy. Default: asc",
          },
          limit: { type: "integer", description: "Max results. Default: 50" },
        },
        required: ["entity", "columns"],
      },
    },
  },
], {
  get_dashboard_detail: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  detect_anomalies: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  get_skill_gaps: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  get_project_health: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  get_budget_forecast: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
    requiredPermissions: [PermissionKey.VIEW_COSTS],
  },
  get_insights_summary: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  run_report: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
});

export function createDashboardInsightsReportsExecutors(
  deps: DashboardInsightsReportsDeps,
): Record<string, ToolExecutor> {
  return {
    async get_dashboard_detail(params: { section?: string }, ctx: ToolContext) {
      const caller = deps.createDashboardCaller(deps.createScopedCallerContext(ctx));
      return caller.getDetail({ ...(params.section ? { section: params.section } : {}) });
    },

    async detect_anomalies(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createInsightsCaller(deps.createScopedCallerContext(ctx));
      return caller.getAnomalyDetail();
    },

    async get_skill_gaps(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createDashboardCaller(deps.createScopedCallerContext(ctx));
      return caller.getSkillGapSummary();
    },

    async get_project_health(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createDashboardCaller(deps.createScopedCallerContext(ctx));
      return caller.getProjectHealthDetail();
    },

    async get_budget_forecast(_params: Record<string, never>, ctx: ToolContext) {
      deps.assertPermission(ctx, PermissionKey.VIEW_COSTS);
      const caller = deps.createDashboardCaller(deps.createScopedCallerContext(ctx));
      return caller.getBudgetForecastDetail();
    },

    async get_insights_summary(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createInsightsCaller(deps.createScopedCallerContext(ctx));
      return caller.getInsightsSummary();
    },

    async run_report(params: {
      entity: string;
      columns: string[];
      filters?: ReportFilter[];
      periodMonth?: string;
      groupBy?: string;
      sortBy?: string;
      sortDir?: "asc" | "desc";
      limit?: number;
    }, ctx: ToolContext) {
      const entity = params.entity as ReportEntity;
      if (!REPORT_ENTITIES.includes(entity)) {
        return {
          error:
            `Unknown entity: ${params.entity}. Use resource, project, assignment, or resource_month.`,
        };
      }

      const caller = deps.createReportCaller(deps.createScopedCallerContext(ctx));
      const result = await caller.getReportData({
        entity,
        columns: params.columns,
        filters: params.filters ?? [],
        ...(params.periodMonth !== undefined ? { periodMonth: params.periodMonth } : {}),
        ...(params.groupBy !== undefined ? { groupBy: params.groupBy } : {}),
        ...(params.sortBy !== undefined ? { sortBy: params.sortBy } : {}),
        sortDir: params.sortDir ?? "asc",
        limit: Math.min(params.limit ?? 50, 200),
        offset: 0,
      });

      return {
        rows: result.rows,
        rowCount: result.rows.length,
        totalCount: result.totalCount,
        columns: result.columns,
        groups: result.groups,
        ...(result.explainability ? { explainability: result.explainability } : {}),
      };
    },
  };
}
