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

type AssistantToolErrorResult = { error: string };

type ResolvedResource = {
  id: string;
};

type RolesAnalyticsDeps = {
  createRoleCaller: (ctx: TRPCContext) => {
    list: (params: Record<string, never>) => Promise<Array<{
      id: string;
      name: string;
      color?: string | null;
    }>>;
    create: (params: z.input<typeof CreateRoleSchema>) => Promise<{
      id: string;
      name: string;
    }>;
    update: (params: {
      id: string;
      data: z.input<typeof UpdateRoleSchema>;
    }) => Promise<{
      id: string;
      name: string;
    }>;
    getById: (params: { id: string }) => Promise<{ name: string }>;
    delete: (params: { id: string }) => Promise<unknown>;
  };
  createResourceCaller: (ctx: TRPCContext) => {
    searchBySkills: (params: {
      rules: Array<{ skill: string; minProficiency: number }>;
      operator: "OR";
    }) => Promise<Array<{
      id: string;
      eid: string;
      displayName: string;
      chapter?: string | null;
      matchedSkills: Array<{
        skill: string;
        proficiency: number;
      }>;
    }>>;
    getChargeabilitySummary: (params: {
      resourceId: string;
      month: string;
    }) => Promise<unknown>;
  };
  createDashboardCaller: (ctx: TRPCContext) => {
    getStatisticsDetail: () => Promise<unknown>;
  };
  createScopedCallerContext: (ctx: ToolContext) => TRPCContext;
  resolveResourceIdentifier: (
    ctx: ToolContext,
    identifier: string,
  ) => Promise<ResolvedResource | AssistantToolErrorResult>;
  toAssistantRoleMutationError: (
    error: unknown,
    action: "create" | "update" | "delete",
  ) => AssistantToolErrorResult | null;
};

export const rolesAnalyticsReadToolDefinitions: ToolDef[] = withToolAccess([
  {
    type: "function",
    function: {
      name: "list_roles",
      description: "List all available roles with their colors.",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "search_by_skill",
      description: "Find resources that have a specific skill. Controller/manager/admin access required.",
      parameters: {
        type: "object",
        properties: {
          skill: { type: "string", description: "Skill name to search for" },
        },
        required: ["skill"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_statistics",
      description: "Get overview statistics: total resources, projects, active allocations, budget summary, projects by status, chapter breakdown.",
      parameters: { type: "object", properties: {} },
    },
  },
  {
    type: "function",
    function: {
      name: "get_chargeability",
      description: "Get chargeability data for a resource in a given month: hours booked vs available, chargeability %, target comparison.",
      parameters: {
        type: "object",
        properties: {
          resourceId: { type: "string", description: "Resource ID, eid, or name" },
          month: { type: "string", description: "Month in YYYY-MM format, e.g. 2026-03. Default: current month" },
        },
        required: ["resourceId"],
      },
    },
  },
], {
  list_roles: {
    requiresPlanningRead: true,
  },
  search_by_skill: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  get_statistics: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER, SystemRole.CONTROLLER],
  },
  get_chargeability: {
    requiresCostView: true,
  },
});

export const rolesAnalyticsMutationToolDefinitions: ToolDef[] = withToolAccess([
  {
    type: "function",
    function: {
      name: "create_role",
      description: "Create a new role. Requires manager or admin role plus manageRoles permission. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          name: { type: "string", description: "Role name" },
          description: { type: "string", description: "Optional role description" },
          color: { type: "string", description: "Hex color (e.g. #3b82f6). Default: #6b7280" },
        },
        required: ["name"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "update_role",
      description: "Update a role. Requires manager or admin role plus manageRoles permission. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          id: { type: "string", description: "Role ID" },
          name: { type: "string", description: "New name" },
          description: { type: "string", description: "New description" },
          color: { type: "string", description: "New hex color" },
          isActive: { type: "boolean", description: "Set active state" },
        },
        required: ["id"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "delete_role",
      description: "Delete a role. Requires manager or admin role plus manageRoles permission. Always confirm first.",
      parameters: {
        type: "object",
        properties: {
          id: { type: "string", description: "Role ID" },
        },
        required: ["id"],
      },
    },
  },
], {
  create_role: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
    requiredPermissions: [PermissionKey.MANAGE_ROLES],
  },
  update_role: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
    requiredPermissions: [PermissionKey.MANAGE_ROLES],
  },
  delete_role: {
    allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
    requiredPermissions: [PermissionKey.MANAGE_ROLES],
  },
});

export function createRolesAnalyticsExecutors(
  deps: RolesAnalyticsDeps,
): Record<string, ToolExecutor> {
  return {
    async list_roles(_params: Record<string, never>, ctx: ToolContext) {
      const caller = deps.createRoleCaller(deps.createScopedCallerContext(ctx));
      const roles = await caller.list({});
      return roles.map((role) => ({
        id: role.id,
        name: role.name,
        color: role.color ?? null,
      }));
    },

    async search_by_skill(params: { skill: string }, ctx: ToolContext) {
      const caller = deps.createResourceCaller(deps.createScopedCallerContext(ctx));
      const matched = await caller.searchBySkills({
        rules: [{ skill: params.skill, minProficiency: 1 }],
        operator: "OR",
      });

      return matched.slice(0, 20).map((resource) => ({
        id: resource.id,
        eid: resource.eid,
        name: resource.displayName,
        matchedSkill: resource.matchedSkills[0]?.skill ?? null,
        level: resource.matchedSkills[0]?.proficiency ?? null,
        chapter: resource.chapter ?? null,
      }));
    },

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

    async get_chargeability(params: { resourceId: string; month?: string }, ctx: ToolContext) {
      const now = new Date();
      const month = params.month ?? `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
      const resource = await deps.resolveResourceIdentifier(ctx, params.resourceId);
      if ("error" in resource) {
        return resource;
      }

      const caller = deps.createResourceCaller(deps.createScopedCallerContext(ctx));
      return caller.getChargeabilitySummary({
        resourceId: resource.id,
        month,
      });
    },

    async create_role(params: {
      name: string;
      description?: string;
      color?: string;
    }, ctx: ToolContext) {
      const caller = deps.createRoleCaller(deps.createScopedCallerContext(ctx));

      let role;
      try {
        role = await caller.create(CreateRoleSchema.parse(params));
      } catch (error) {
        const mapped = deps.toAssistantRoleMutationError(error, "create");
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["role"],
        success: true,
        message: `Created role: ${role.name}`,
        roleId: role.id,
        role,
      };
    },

    async update_role(params: {
      id: string;
      name?: string;
      description?: string;
      color?: string;
      isActive?: boolean;
    }, ctx: ToolContext) {
      const caller = deps.createRoleCaller(deps.createScopedCallerContext(ctx));
      const data = UpdateRoleSchema.parse({
        ...(params.name !== undefined ? { name: params.name } : {}),
        ...(params.description !== undefined ? { description: params.description } : {}),
        ...(params.color !== undefined ? { color: params.color } : {}),
        ...(params.isActive !== undefined ? { isActive: params.isActive } : {}),
      });
      if (Object.keys(data).length === 0) {
        return { error: "No fields to update" };
      }

      let role;
      try {
        role = await caller.update({ id: params.id, data });
      } catch (error) {
        const mapped = deps.toAssistantRoleMutationError(error, "update");
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["role"],
        success: true,
        message: `Updated role: ${role.name}`,
        roleId: role.id,
        role,
      };
    },

    async delete_role(params: { id: string }, ctx: ToolContext) {
      const caller = deps.createRoleCaller(deps.createScopedCallerContext(ctx));

      let role;
      try {
        role = await caller.getById({ id: params.id });
        await caller.delete({ id: params.id });
      } catch (error) {
        const mapped = deps.toAssistantRoleMutationError(error, "delete");
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return {
        __action: "invalidate" as const,
        scope: ["role"],
        success: true,
        message: `Deleted role: ${role.name}`,
      };
    },
  };
}
