import {
  CreateUtilizationCategorySchema,
  UpdateUtilizationCategorySchema,
} from "@capakraken/shared";
import { z } from "zod";
import { findUniqueOrThrow } from "../db/helpers.js";
import { createAuditEntry } from "../lib/audit.js";
import { adminProcedure, createTRPCRouter, planningReadProcedure } from "../trpc.js";
import {
  assertUtilizationCategoryCodeAvailable,
  buildUtilizationCategoryCreateData,
  buildUtilizationCategoryListWhere,
  buildUtilizationCategoryUpdateData,
  unsetDefaultUtilizationCategory,
} from "./utilization-category-support.js";

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

  getById: planningReadProcedure
    .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 }) => {
      await assertUtilizationCategoryCodeAvailable(ctx.db, input.code);

      // If setting as default, unset the current default first
      if (input.isDefault) {
        await unsetDefaultUtilizationCategory(ctx.db);
      }

      const created = await ctx.db.utilizationCategory.create({
        data: buildUtilizationCategoryCreateData(input),
      });

      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) {
        await assertUtilizationCategoryCodeAvailable(ctx.db, input.data.code, existing.id);
      }

      // If setting as default, unset others
      if (input.data.isDefault) {
        await unsetDefaultUtilizationCategory(ctx.db, input.id);
      }

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

      const updated = await ctx.db.utilizationCategory.update({
        where: { id: input.id },
        data: buildUtilizationCategoryUpdateData(input.data),
      });

      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;
    }),
});
