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

type ConfigReadmodelsDeps = {
  createManagementLevelCaller: (ctx: TRPCContext) => {
    listGroups: () => Promise<Array<{
      id: string;
      name: string;
      targetPercentage: number | null;
      levels: Array<{ id: string; name: string }>;
    }>>;
  };
  createUtilizationCategoryCaller: (ctx: TRPCContext) => {
    list: () => Promise<Array<{
      id: string;
      code: string;
      name: string;
      description: string | null;
    }>>;
    getById: (params: { id: string }) => Promise<{
      _count: { projects: number };
    }>;
  };
  createCalculationRuleCaller: (ctx: TRPCContext) => {
    list: () => Promise<Array<{
      id: string;
      name: string;
      description: string | null;
      isActive: boolean;
      triggerType: string;
      orderType: string | null;
      costEffect: string;
      costReductionPercent: number | null;
      chargeabilityEffect: string;
      priority: number;
      project: {
        id: string;
        name: string;
        shortCode: string;
      } | null;
    }>>;
  };
  createEffortRuleCaller: (ctx: TRPCContext) => {
    list: () => Promise<Array<{
      name: string;
      isDefault: boolean;
      rules: Array<{
        id: string;
        description: string | null;
        scopeType: string;
        discipline: string;
        chapter: string | null;
        unitMode: string;
        hoursPerUnit: number;
        sortOrder: number;
      }>;
    }>>;
  };
  createExperienceMultiplierCaller: (ctx: TRPCContext) => {
    list: () => Promise<Array<{
      name: string;
      isDefault: boolean;
      rules: Array<{
        id: string;
        description: string | null;
        chapter: string | null;
        location: string | null;
        level: string | null;
        costMultiplier: number;
        billMultiplier: number;
        shoringRatio: number | null;
        additionalEffortRatio: number | null;
        sortOrder: number;
      }>;
    }>>;
  };
  createScopedCallerContext: (ctx: ToolContext) => TRPCContext;
};

export const configReadmodelToolDefinitions: ToolDef[] = withToolAccess([
  {
    type: "function",
    function: {
      name: "list_management_levels",
      description: "List management level groups and their levels with target percentages.",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "list_utilization_categories",
      description: "List utilization categories (cost classification for projects).",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "list_calculation_rules",
      description: "List calculation rules for cost attribution and chargeability.",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "list_effort_rules",
      description: "List effort estimation rules with their formulas and conditions.",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "list_experience_multipliers",
      description: "List experience multipliers that adjust effort estimates based on seniority.",
      parameters: { type: "object", properties: {} },
    },
  },
], {
  list_management_levels: {
    requiresPlanningRead: true,
  },
  list_utilization_categories: {
    requiresPlanningRead: true,
  },
  list_calculation_rules: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  list_effort_rules: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  list_experience_multipliers: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
});

export function createConfigReadmodelExecutors(
  deps: ConfigReadmodelsDeps,
): Record<string, ToolExecutor> {
  return {
    async list_management_levels(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createManagementLevelCaller(deps.createScopedCallerContext(ctx));
      const groups = await caller.listGroups();
      return groups.map((group) => ({
        id: group.id,
        name: group.name,
        target: group.targetPercentage ? `${group.targetPercentage}%` : null,
        levels: group.levels.map((level) => ({ id: level.id, name: level.name })),
      }));
    },

    async list_utilization_categories(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createUtilizationCategoryCaller(deps.createScopedCallerContext(ctx));
      const categories = await caller.list();
      const categoriesWithCounts = await Promise.all(
        categories.map(async (category) => ({
          category,
          projectCount: (await caller.getById({ id: category.id }))._count.projects,
        })),
      );

      return categoriesWithCounts.map(({ category, projectCount }) => ({
        id: category.id,
        code: category.code,
        name: category.name,
        description: category.description,
        projectCount,
      }));
    },

    async list_calculation_rules(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createCalculationRuleCaller(deps.createScopedCallerContext(ctx));
      const rules = await caller.list();
      return rules.map((rule) => ({
        id: rule.id,
        name: rule.name,
        description: rule.description,
        isActive: rule.isActive,
        triggerType: rule.triggerType,
        orderType: rule.orderType,
        costEffect: rule.costEffect,
        costReductionPercent: rule.costReductionPercent,
        chargeabilityEffect: rule.chargeabilityEffect,
        priority: rule.priority,
        project: rule.project
          ? {
              id: rule.project.id,
              name: rule.project.name,
              shortCode: rule.project.shortCode,
            }
          : null,
      }));
    },

    async list_effort_rules(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createEffortRuleCaller(deps.createScopedCallerContext(ctx));
      const ruleSets = await caller.list();
      return ruleSets.flatMap((ruleSet) => ruleSet.rules.map((rule) => ({
        id: rule.id,
        description: rule.description,
        scopeType: rule.scopeType,
        discipline: rule.discipline,
        chapter: rule.chapter,
        unitMode: rule.unitMode,
        hoursPerUnit: rule.hoursPerUnit,
        sortOrder: rule.sortOrder,
        ruleSet: {
          name: ruleSet.name,
          isDefault: ruleSet.isDefault,
        },
      })));
    },

    async list_experience_multipliers(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createExperienceMultiplierCaller(deps.createScopedCallerContext(ctx));
      const multiplierSets = await caller.list();
      return multiplierSets.flatMap((multiplierSet) => multiplierSet.rules.map((rule) => ({
        id: rule.id,
        description: rule.description,
        chapter: rule.chapter,
        location: rule.location,
        level: rule.level,
        costMultiplier: rule.costMultiplier,
        billMultiplier: rule.billMultiplier,
        shoringRatio: rule.shoringRatio,
        additionalEffortRatio: rule.additionalEffortRatio,
        sortOrder: rule.sortOrder,
        multiplierSet: {
          name: multiplierSet.name,
          isDefault: multiplierSet.isDefault,
        },
      })));
    },
  };
}
