import type { PrismaClient } from "@capakraken/db";
import { AllocationStatus, type FillDemandRequirementInput } from "@capakraken/shared";
import { checkDuplicateAssignment } from "@capakraken/engine";
import { TRPCError } from "@trpc/server";
import { type AssignmentWithRelations } from "./create-assignment.js";
import { fillDemandRequirementWithLegacySync } from "./fill-demand-requirement-with-legacy-sync.js";
import { listAssignmentBookings } from "./list-assignment-bookings.js";

export interface FillDemandRequirementResult {
  assignment: AssignmentWithRelations;
  updatedDemandRequirement: {
    id: string;
    projectId: string;
    headcount: number;
    status: AllocationStatus;
  };
}

export interface FillDemandRequirementOptions {
}
export async function fillDemandRequirement(
  db: PrismaClient,
  input: FillDemandRequirementInput,
): Promise<FillDemandRequirementResult> {
  const demandRequirement = await db.demandRequirement.findUnique({
    where: { id: input.demandRequirementId },
    select: {
      id: true,
      projectId: true,
      startDate: true,
      endDate: true,
      hoursPerDay: true,
      role: true,
      roleId: true,
      headcount: true,
      status: true,
      metadata: true,
    },
  });

  if (!demandRequirement) {
    throw new TRPCError({ code: "NOT_FOUND", message: "Demand requirement not found" });
  }

  if (demandRequirement.status === AllocationStatus.CANCELLED) {
    throw new TRPCError({
      code: "BAD_REQUEST",
      message: "Demand requirement is cancelled",
    });
  }

  if (demandRequirement.status === AllocationStatus.COMPLETED) {
    throw new TRPCError({
      code: "BAD_REQUEST",
      message: "Demand requirement is already completed",
    });
  }

  const existingBookings = await listAssignmentBookings(
    db as unknown as Parameters<typeof listAssignmentBookings>[0],
    {
      resourceIds: [input.resourceId],
    },
  );

  const duplicateResult = checkDuplicateAssignment(
    input.resourceId,
    demandRequirement.projectId,
    demandRequirement.startDate,
    demandRequirement.endDate,
    existingBookings.map(b => ({
      id: b.id,
      resourceId: b.resourceId ?? "",
      projectId: b.projectId,
      startDate: b.startDate,
      endDate: b.endDate,
      status: b.status,
    })),
  );

  if (duplicateResult.isDuplicate) {
    throw new TRPCError({
      code: "CONFLICT",
      message: duplicateResult.message ?? "Resource is already assigned to this project with overlapping dates",
    });
  }

  return fillDemandRequirementWithLegacySync(db, demandRequirement, input);
}
