import {
  CreateCalculationRuleSchema,
  UpdateCalculationRuleSchema,
} from "@capakraken/shared";
import { z } from "zod";
import { findUniqueOrThrow } from "../db/helpers.js";
import { PROJECT_BRIEF_SELECT } from "../db/selects.js";
import { createTRPCRouter, controllerProcedure, managerProcedure } from "../trpc.js";
import { createAuditEntry } from "../lib/audit.js";

export const calculationRuleRouter = createTRPCRouter({
  list: controllerProcedure.query(async ({ ctx }) => {
    return ctx.db.calculationRule.findMany({
      orderBy: [{ priority: "desc" }, { name: "asc" }],
      include: { project: { select: PROJECT_BRIEF_SELECT } },
    });
  }),

  getById: controllerProcedure
    .input(z.object({ id: z.string() }))
    .query(async ({ ctx, input }) => {
      return findUniqueOrThrow(
        ctx.db.calculationRule.findUnique({
          where: { id: input.id },
          include: { project: { select: PROJECT_BRIEF_SELECT } },
        }),
        "CalculationRule",
      );
    }),

  /** Get all active rules (optimized for engine use — no project include) */
  getActive: controllerProcedure.query(async ({ ctx }) => {
    return ctx.db.calculationRule.findMany({
      where: { isActive: true },
      orderBy: [{ priority: "desc" }],
    });
  }),

  create: managerProcedure
    .input(CreateCalculationRuleSchema)
    .mutation(async ({ ctx, input }) => {
      const rule = await ctx.db.calculationRule.create({
        data: {
          name: input.name,
          triggerType: input.triggerType,
          costEffect: input.costEffect,
          chargeabilityEffect: input.chargeabilityEffect,
          ...(input.description !== undefined ? { description: input.description } : {}),
          ...(input.projectId !== undefined ? { projectId: input.projectId } : {}),
          ...(input.orderType !== undefined ? { orderType: input.orderType as never } : {}),
          ...(input.costReductionPercent !== undefined ? { costReductionPercent: input.costReductionPercent } : {}),
          priority: input.priority,
          isActive: input.isActive,
        },
      });

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

      return rule;
    }),

  update: managerProcedure
    .input(UpdateCalculationRuleSchema)
    .mutation(async ({ ctx, input }) => {
      const { id, ...data } = input;
      const before = await findUniqueOrThrow(
        ctx.db.calculationRule.findUnique({ where: { id } }),
        "CalculationRule",
      );

      // Build update data using exactOptionalPropertyTypes pattern
      const updateData: Record<string, unknown> = {};
      if (data.name !== undefined) updateData.name = data.name;
      if (data.description !== undefined) updateData.description = data.description;
      if (data.triggerType !== undefined) updateData.triggerType = data.triggerType;
      if (data.projectId !== undefined) updateData.projectId = data.projectId;
      if (data.orderType !== undefined) updateData.orderType = data.orderType;
      if (data.costEffect !== undefined) updateData.costEffect = data.costEffect;
      if (data.costReductionPercent !== undefined) updateData.costReductionPercent = data.costReductionPercent;
      if (data.chargeabilityEffect !== undefined) updateData.chargeabilityEffect = data.chargeabilityEffect;
      if (data.priority !== undefined) updateData.priority = data.priority;
      if (data.isActive !== undefined) updateData.isActive = data.isActive;

      const updated = await ctx.db.calculationRule.update({
        where: { id },
        data: updateData,
      });

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

      return updated;
    }),

  delete: managerProcedure
    .input(z.object({ id: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const rule = await findUniqueOrThrow(
        ctx.db.calculationRule.findUnique({ where: { id: input.id } }),
        "CalculationRule",
      );
      await ctx.db.calculationRule.delete({ where: { id: input.id } });

      void createAuditEntry({
        db: ctx.db,
        entityType: "CalculationRule",
        entityId: input.id,
        entityName: rule.name,
        action: "DELETE",
        userId: ctx.dbUser?.id,
        before: rule as unknown as Record<string, unknown>,
        source: "ui",
      });

      return { success: true };
    }),
});
