import { TRPCError } from "@trpc/server";
import {
  calculateScenarioEntryHours,
  getScenarioAvailability,
  loadScenarioAvailabilityContexts,
  scenarioBaselineAssignmentInclude,
  scenarioBaselineProjectSelect,
  scenarioDemandInclude,
  type ScenarioDb,
} from "./scenario-shared.js";

export async function readProjectScenarioBaseline(
  db: ScenarioDb,
  projectId: string,
) {
  const project = await db.project.findUnique({
    where: { id: projectId },
    select: scenarioBaselineProjectSelect,
  });
  if (!project) {
    throw new TRPCError({ code: "NOT_FOUND", message: "Project not found" });
  }

  const assignments = await db.assignment.findMany({
    where: {
      projectId,
      status: { not: "CANCELLED" },
    },
    include: scenarioBaselineAssignmentInclude,
  });

  const demands = await db.demandRequirement.findMany({
    where: {
      projectId,
      status: { not: "CANCELLED" },
    },
    include: scenarioDemandInclude,
  });

  const assignmentRangeStart = assignments.length > 0
    ? new Date(Math.min(...assignments.map((assignment) => assignment.startDate.getTime())))
    : project.startDate;
  const assignmentRangeEnd = assignments.length > 0
    ? new Date(Math.max(...assignments.map((assignment) => assignment.endDate.getTime())))
    : project.endDate;

  const contexts = await loadScenarioAvailabilityContexts(
    db,
    assignments
      .flatMap((assignment) => (assignment.resource ? [assignment.resource] : [])),
    assignmentRangeStart,
    assignmentRangeEnd,
  );

  const baselineAllocations = assignments.map((assignment) => {
    const availability = getScenarioAvailability(assignment.resource?.availability);
    const lcrCents = assignment.resource?.lcrCents ?? 0;
    const totalHours = calculateScenarioEntryHours({
      resourceId: assignment.resourceId,
      lcrCents,
      hoursPerDay: assignment.hoursPerDay,
      startDate: assignment.startDate,
      endDate: assignment.endDate,
      availability,
    }, {
      periodStart: assignmentRangeStart,
      periodEnd: assignmentRangeEnd,
      contexts,
    });
    const costCents = Math.round(totalHours * lcrCents);
    const workingDays = assignment.hoursPerDay > 0
      ? Math.round((totalHours / assignment.hoursPerDay) * 100) / 100
      : 0;

    return {
      id: assignment.id,
      resourceId: assignment.resourceId,
      resourceName: assignment.resource?.displayName ?? "Unknown",
      resourceEid: assignment.resource?.eid ?? "",
      lcrCents,
      roleId: assignment.roleId,
      roleName: assignment.roleEntity?.name ?? assignment.role ?? "",
      roleColor: assignment.roleEntity?.color ?? null,
      startDate: assignment.startDate.toISOString(),
      endDate: assignment.endDate.toISOString(),
      hoursPerDay: assignment.hoursPerDay,
      status: assignment.status,
      costCents,
      totalHours,
      workingDays,
    };
  });

  const baselineDemands = demands.map((demand) => ({
    id: demand.id,
    roleId: demand.roleId,
    roleName: demand.roleEntity?.name ?? demand.role ?? "",
    roleColor: demand.roleEntity?.color ?? null,
    startDate: demand.startDate.toISOString(),
    endDate: demand.endDate.toISOString(),
    hoursPerDay: demand.hoursPerDay,
    headcount: demand.headcount,
    status: demand.status,
  }));

  return {
    project,
    assignments: baselineAllocations,
    demands: baselineDemands,
    totalCostCents: baselineAllocations.reduce((sum, allocation) => sum + allocation.costCents, 0),
    totalHours: baselineAllocations.reduce((sum, allocation) => sum + allocation.totalHours, 0),
    budgetCents: project.budgetCents,
  };
}
