import {
  approveEstimateVersion,
  createEstimateRevision,
  submitEstimateVersion,
} from "@capakraken/application";
import type { Prisma } from "@capakraken/db";
import {
  ApproveEstimateVersionSchema,
  CreateEstimateRevisionSchema,
  PermissionKey,
  SubmitEstimateVersionSchema,
} from "@capakraken/shared";
import { managerProcedure, requirePermission } from "../trpc.js";
import { rethrowEstimateRouterError } from "./estimate-procedure-support.js";

export const estimateVersionWorkflowProcedures = {
  submitVersion: managerProcedure
    .input(SubmitEstimateVersionSchema)
    .mutation(async ({ ctx, input }) => {
      requirePermission(ctx, PermissionKey.MANAGE_PROJECTS);

      let estimate;
      try {
        estimate = await submitEstimateVersion(
          ctx.db as unknown as Parameters<typeof submitEstimateVersion>[0],
          input,
        );
      } catch (error) {
        rethrowEstimateRouterError(error, [
          {
            code: "NOT_FOUND",
            messages: ["Estimate not found", "Estimate version not found"],
          },
          {
            code: "PRECONDITION_FAILED",
            messages: [
              "Estimate has no working version",
              "Only working versions can be submitted",
            ],
          },
        ]);
      }

      await ctx.db.auditLog.create({
        data: {
          entityType: "Estimate",
          entityId: estimate.id,
          action: "UPDATE",
          ...(ctx.dbUser?.id ? { userId: ctx.dbUser.id } : {}),
          changes: {
            after: {
              id: estimate.id,
              status: estimate.status,
              submittedVersionId: estimate.versions.find(
                (version) => version.status === "SUBMITTED",
              )?.id,
            },
          } as Prisma.InputJsonValue,
        },
      });

      return estimate;
    }),

  approveVersion: managerProcedure
    .input(ApproveEstimateVersionSchema)
    .mutation(async ({ ctx, input }) => {
      requirePermission(ctx, PermissionKey.MANAGE_PROJECTS);

      let estimate;
      try {
        estimate = await approveEstimateVersion(
          ctx.db as unknown as Parameters<typeof approveEstimateVersion>[0],
          input,
        );
      } catch (error) {
        rethrowEstimateRouterError(error, [
          {
            code: "NOT_FOUND",
            messages: ["Estimate not found", "Estimate version not found"],
          },
          {
            code: "PRECONDITION_FAILED",
            messages: [
              "Estimate has no submitted version",
              "Only submitted versions can be approved",
            ],
          },
        ]);
      }

      await ctx.db.auditLog.create({
        data: {
          entityType: "Estimate",
          entityId: estimate.id,
          action: "UPDATE",
          ...(ctx.dbUser?.id ? { userId: ctx.dbUser.id } : {}),
          changes: {
            after: {
              id: estimate.id,
              status: estimate.status,
              approvedVersionId: estimate.versions.find(
                (version) => version.status === "APPROVED",
              )?.id,
            },
          } as Prisma.InputJsonValue,
        },
      });

      return estimate;
    }),

  createRevision: managerProcedure
    .input(CreateEstimateRevisionSchema)
    .mutation(async ({ ctx, input }) => {
      requirePermission(ctx, PermissionKey.MANAGE_PROJECTS);

      let estimate;
      try {
        estimate = await createEstimateRevision(
          ctx.db as unknown as Parameters<typeof createEstimateRevision>[0],
          input,
        );
      } catch (error) {
        rethrowEstimateRouterError(error, [
          {
            code: "NOT_FOUND",
            messages: ["Estimate not found", "Estimate version not found"],
          },
          {
            code: "PRECONDITION_FAILED",
            messages: [
              "Estimate already has a working version",
              "Estimate has no locked version to revise",
              "Source version must be locked before creating a revision",
            ],
          },
        ]);
      }

      await ctx.db.auditLog.create({
        data: {
          entityType: "Estimate",
          entityId: estimate.id,
          action: "UPDATE",
          ...(ctx.dbUser?.id ? { userId: ctx.dbUser.id } : {}),
          changes: {
            after: {
              id: estimate.id,
              status: estimate.status,
              latestVersionNumber: estimate.latestVersionNumber,
              workingVersionId: estimate.versions.find(
                (version) => version.status === "WORKING",
              )?.id,
            },
          } as Prisma.InputJsonValue,
        },
      });

      return estimate;
    }),
};
