import { PermissionKey, SkillEntrySchema } from "@capakraken/shared";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { findUniqueOrThrow } from "../db/helpers.js";
import { adminProcedure, managerProcedure, protectedProcedure, requirePermission } from "../trpc.js";

const employeeInfoSchema = z
  .object({
    roleId: z.string().optional(),
    yearsOfExperience: z.number().optional(),
    portfolioUrl: z.string().url().optional().or(z.literal("")),
  })
  .optional();

export const resourceSkillImportProcedures = {
  importSkillMatrix: protectedProcedure
    .input(
      z.object({
        skills: z.array(SkillEntrySchema),
        employeeInfo: employeeInfoSchema,
      }),
    )
    .mutation(async ({ ctx, input }) => {
      const user = await findUniqueOrThrow(
        ctx.db.user.findUnique({
          where: { id: ctx.dbUser!.id },
          include: { resource: true },
        }),
        "User",
      );
      if (!user.resource) {
        throw new TRPCError({ code: "NOT_FOUND", message: "No resource linked to your account" });
      }

      await ctx.db.resource.update({
        where: { id: user.resource.id },
        data: {
          skills: input.skills as unknown as import("@capakraken/db").Prisma.InputJsonValue,
          skillMatrixUpdatedAt: new Date(),
          ...(input.employeeInfo?.portfolioUrl !== undefined
            ? { portfolioUrl: input.employeeInfo.portfolioUrl || null }
            : {}),
          ...(input.employeeInfo?.roleId !== undefined ? { roleId: input.employeeInfo.roleId } : {}),
        },
      });

      return { count: input.skills.length };
    }),

  importSkillMatrixForResource: managerProcedure
    .input(
      z.object({
        resourceId: z.string(),
        skills: z.array(SkillEntrySchema),
        employeeInfo: employeeInfoSchema,
      }),
    )
    .mutation(async ({ ctx, input }) => {
      requirePermission(ctx, PermissionKey.MANAGE_RESOURCES);
      await findUniqueOrThrow(
        ctx.db.resource.findUnique({ where: { id: input.resourceId } }),
        "Resource",
      );

      await ctx.db.resource.update({
        where: { id: input.resourceId },
        data: {
          skills: input.skills as unknown as import("@capakraken/db").Prisma.InputJsonValue,
          skillMatrixUpdatedAt: new Date(),
          ...(input.employeeInfo?.portfolioUrl !== undefined
            ? { portfolioUrl: input.employeeInfo.portfolioUrl || null }
            : {}),
          ...(input.employeeInfo?.roleId !== undefined ? { roleId: input.employeeInfo.roleId } : {}),
        },
      });

      return { count: input.skills.length };
    }),

  batchImportSkillMatrices: adminProcedure
    .input(
      z.object({
        entries: z.array(
          z.object({
            eid: z.string(),
            skills: z.array(SkillEntrySchema),
            employeeInfo: employeeInfoSchema,
          }),
        ),
      }),
    )
    .mutation(async ({ ctx, input }) => {
      const eids = input.entries.map((entry) => entry.eid);
      const existing = await ctx.db.resource.findMany({
        where: { eid: { in: eids } },
        select: { id: true, eid: true },
      });
      const eidToId = new Map(existing.map((resource) => [resource.eid, resource.id]));
      const notFound = input.entries.length - existing.length;

      const now = new Date();
      const updates = input.entries
        .filter((entry) => eidToId.has(entry.eid))
        .map((entry) =>
          ctx.db.resource.update({
            where: { id: eidToId.get(entry.eid)! },
            data: {
              skills: entry.skills as unknown as import("@capakraken/db").Prisma.InputJsonValue,
              skillMatrixUpdatedAt: now,
              ...(entry.employeeInfo?.portfolioUrl !== undefined
                ? { portfolioUrl: entry.employeeInfo.portfolioUrl || null }
                : {}),
              ...(entry.employeeInfo?.roleId !== undefined ? { roleId: entry.employeeInfo.roleId } : {}),
            },
          }),
        );

      await ctx.db.$transaction(updates);
      return { updated: updates.length, notFound };
    }),
};
