import {
  CreateUtilizationCategorySchema,
  UpdateUtilizationCategorySchema,
} from "@capakraken/shared";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { findUniqueOrThrow } from "../db/helpers.js";
import { createAuditEntry } from "../lib/audit.js";
import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc.js";

export const utilizationCategoryRouter = createTRPCRouter({
  list: protectedProcedure
    .input(z.object({ isActive: z.boolean().optional() }).optional())
    .query(async ({ ctx, input }) => {
      return ctx.db.utilizationCategory.findMany({
        where: {
          ...(input?.isActive !== undefined ? { isActive: input.isActive } : {}),
        },
        orderBy: { sortOrder: "asc" },
      });
    }),

  getById: protectedProcedure
    .input(z.object({ id: z.string() }))
    .query(async ({ ctx, input }) => {
      const cat = await findUniqueOrThrow(
        ctx.db.utilizationCategory.findUnique({
          where: { id: input.id },
          include: { _count: { select: { projects: true } } },
        }),
        "Utilization category",
      );
      return cat;
    }),

  create: adminProcedure
    .input(CreateUtilizationCategorySchema)
    .mutation(async ({ ctx, input }) => {
      const existing = await ctx.db.utilizationCategory.findUnique({ where: { code: input.code } });
      if (existing) {
        throw new TRPCError({ code: "CONFLICT", message: `Code "${input.code}" already exists` });
      }

      // If setting as default, unset the current default first
      if (input.isDefault) {
        await ctx.db.utilizationCategory.updateMany({
          where: { isDefault: true },
          data: { isDefault: false },
        });
      }

      const created = await ctx.db.utilizationCategory.create({
        data: {
          code: input.code,
          name: input.name,
          ...(input.description !== undefined ? { description: input.description } : {}),
          sortOrder: input.sortOrder,
          isDefault: input.isDefault,
        },
      });

      void createAuditEntry({
        db: ctx.db,
        entityType: "UtilizationCategory",
        entityId: created.id,
        entityName: created.name,
        action: "CREATE",
        userId: ctx.dbUser?.id,
        after: created as unknown as Record<string, unknown>,
        source: "ui",
      });

      return created;
    }),

  update: adminProcedure
    .input(z.object({ id: z.string(), data: UpdateUtilizationCategorySchema }))
    .mutation(async ({ ctx, input }) => {
      const existing = await findUniqueOrThrow(
        ctx.db.utilizationCategory.findUnique({ where: { id: input.id } }),
        "Utilization category",
      );

      if (input.data.code && input.data.code !== existing.code) {
        const conflict = await ctx.db.utilizationCategory.findUnique({ where: { code: input.data.code } });
        if (conflict) {
          throw new TRPCError({ code: "CONFLICT", message: `Code "${input.data.code}" already exists` });
        }
      }

      // If setting as default, unset others
      if (input.data.isDefault) {
        await ctx.db.utilizationCategory.updateMany({
          where: { isDefault: true, id: { not: input.id } },
          data: { isDefault: false },
        });
      }

      const before = existing as unknown as Record<string, unknown>;

      const updated = await ctx.db.utilizationCategory.update({
        where: { id: input.id },
        data: {
          ...(input.data.code !== undefined ? { code: input.data.code } : {}),
          ...(input.data.name !== undefined ? { name: input.data.name } : {}),
          ...(input.data.description !== undefined ? { description: input.data.description } : {}),
          ...(input.data.sortOrder !== undefined ? { sortOrder: input.data.sortOrder } : {}),
          ...(input.data.isActive !== undefined ? { isActive: input.data.isActive } : {}),
          ...(input.data.isDefault !== undefined ? { isDefault: input.data.isDefault } : {}),
        },
      });

      void createAuditEntry({
        db: ctx.db,
        entityType: "UtilizationCategory",
        entityId: updated.id,
        entityName: updated.name,
        action: "UPDATE",
        userId: ctx.dbUser?.id,
        before,
        after: updated as unknown as Record<string, unknown>,
        source: "ui",
      });

      return updated;
    }),
});
