import {
  updateAssignment,
  updateDemandRequirement,
} from "@capakraken/application";
import type { PrismaClient } from "@capakraken/db";
import {
  assertTimelineProjectShiftValid,
  buildTimelineProjectShiftEventPayload,
  buildTimelineProjectShiftValidation,
  type LoadedTimelineShiftContext,
} from "./timeline-shift-support.js";
import {
  buildTimelineProjectDateRangeUpdate,
  buildTimelineProjectShiftAuditChanges,
  buildTimelineShiftedAssignmentUpdate,
  recalculateShiftedAssignmentDailyCost,
} from "./timeline-shift-mutation-support.js";

export interface ApplyTimelineProjectShiftInput {
  db: PrismaClient;
  projectId: string;
  newStartDate: Date;
  newEndDate: Date;
  context: LoadedTimelineShiftContext;
}

export async function applyTimelineProjectShift(input: ApplyTimelineProjectShiftInput) {
  const validation = buildTimelineProjectShiftValidation({
    context: input.context,
    newStartDate: input.newStartDate,
    newEndDate: input.newEndDate,
  });
  assertTimelineProjectShiftValid(validation);

  const updatedProject = await input.db.$transaction(async (tx) => {
    const projectRecord = await tx.project.update({
      where: { id: input.projectId },
      data: buildTimelineProjectDateRangeUpdate(input),
    });

    for (const demandRequirement of input.context.demandRequirements) {
      await updateDemandRequirement(
        tx as unknown as Parameters<typeof updateDemandRequirement>[0],
        demandRequirement.id,
        buildTimelineProjectDateRangeUpdate(input),
      );
    }

    for (const assignment of input.context.assignments) {
      const dailyCostCents = await recalculateShiftedAssignmentDailyCost({
        db: input.db,
        assignment,
        newStartDate: input.newStartDate,
        newEndDate: input.newEndDate,
      });

      await updateAssignment(
        tx as unknown as Parameters<typeof updateAssignment>[0],
        assignment.id,
        buildTimelineShiftedAssignmentUpdate({
          newStartDate: input.newStartDate,
          newEndDate: input.newEndDate,
          dailyCostCents,
        }),
      );
    }

    await tx.auditLog.create({
      data: {
        entityType: "Project",
        entityId: input.projectId,
        action: "SHIFT",
        changes: buildTimelineProjectShiftAuditChanges({
          project: input.context.project,
          newStartDate: input.newStartDate,
          newEndDate: input.newEndDate,
          validation,
        }),
      },
    });

    return projectRecord;
  });

  return {
    project: updatedProject,
    validation,
    event: buildTimelineProjectShiftEventPayload({
      projectId: input.projectId,
      newStartDate: input.newStartDate,
      newEndDate: input.newEndDate,
      validation,
      assignments: input.context.assignments,
    }),
  };
}
