import type { PrismaClient, Prisma } from "@capakraken/db";
import type {
  AllocationWithDetails,
  UpdateAssignmentInput,
  UpdateDemandRequirementInput,
} from "@capakraken/shared";
import { TRPCError } from "@trpc/server";
import { findAllocationEntry } from "./load-allocation-entry.js";
import { updateAssignment } from "./update-assignment.js";
import { updateDemandRequirement } from "./update-demand-requirement.js";

type DbClient =
  | Pick<PrismaClient, "demandRequirement" | "assignment">
  | Pick<Prisma.TransactionClient, "demandRequirement" | "assignment">;

export interface UpdateAllocationEntryInput {
  id: string;
  demandRequirementUpdate: UpdateDemandRequirementInput;
  assignmentUpdate: UpdateAssignmentInput;
}

export interface UpdateAllocationEntryResult {
  allocation: AllocationWithDetails;
  strategy: "explicit_demand" | "explicit_assignment";
}

export async function updateAllocationEntry(
  db: DbClient,
  input: UpdateAllocationEntryInput,
): Promise<UpdateAllocationEntryResult> {
  const resolved = await findAllocationEntry(db, input.id);

  if (!resolved) {
    throw new TRPCError({ code: "NOT_FOUND", message: "Allocation not found" });
  }

  if (resolved.kind === "demand") {
    const updatedDemandRequirement = await updateDemandRequirement(
      db as Parameters<typeof updateDemandRequirement>[0],
      resolved.demandRequirement.id,
      input.demandRequirementUpdate,
    );

    return {
      allocation: {
        ...resolved.entry,
        ...updatedDemandRequirement,
        id: resolved.entry.id,
        resourceId: null,
        isPlaceholder: true,
        headcount: updatedDemandRequirement.headcount,
        dailyCostCents: 0,
        project: updatedDemandRequirement.project,
        roleEntity: updatedDemandRequirement.roleEntity ?? null,
        updatedAt: updatedDemandRequirement.updatedAt,
      } as AllocationWithDetails,
      strategy: "explicit_demand",
    };
  }

  const updatedAssignment = await updateAssignment(
    db as Parameters<typeof updateAssignment>[0],
    resolved.assignment.id,
    input.assignmentUpdate,
  );

  return {
    allocation: {
      ...resolved.entry,
      ...updatedAssignment,
      id: resolved.entry.id,
      resourceId: updatedAssignment.resourceId,
      isPlaceholder: false,
      headcount: 1,
      project: updatedAssignment.project,
      resource: updatedAssignment.resource ?? null,
      roleEntity: updatedAssignment.roleEntity ?? null,
      updatedAt: updatedAssignment.updatedAt,
    } as AllocationWithDetails,
    strategy: "explicit_assignment",
  };
}
