import {
  calculateAllocation,
  deriveResourceForecast,
  type AssignmentSlice,
} from "@capakraken/engine";
import type { CalculationRule, WeekdayAvailability } from "@capakraken/shared";
import type { loadResourceGraphAvailability } from "./computation-graph-resource-availability.js";

type ResourceGraphAssignment = {
  id: string;
  hoursPerDay: number;
  startDate: Date;
  endDate: Date;
  dailyCostCents: number | null;
  status: string;
  project: {
    id: string;
    name: string;
    shortCode: string;
    utilizationCategory: {
      code: string;
    } | null;
  };
};

type ResourceGraphAllocationInput = {
  assignments: ResourceGraphAssignment[];
  absenceDays: Awaited<ReturnType<typeof loadResourceGraphAvailability>>["absenceDays"];
  calcRules: CalculationRule[];
  effectiveAvailableHours: number;
  monthEnd: Date;
  monthStart: Date;
  resourceLcrCents: number;
  resourceFte: number;
  targetPct: number;
  weeklyAvailability: WeekdayAvailability;
};

export function buildResourceAllocationSummary(input: ResourceGraphAllocationInput) {
  const slices: AssignmentSlice[] = [];
  const assignmentBreakdown: Array<{
    id: string;
    projectId: string;
    projectName: string;
    projectCode: string;
    status: string;
    bookedHours: number;
  }> = [];

  let totalAllocHours = 0;
  let totalAllocCostCents = 0;
  let totalChargeableHours = 0;
  let totalProjectCostCents = 0;
  let totalWorkingDaysInMonth = 0;
  let hasRulesEffect = false;

  for (const assignment of input.assignments) {
    const overlapStart = new Date(Math.max(input.monthStart.getTime(), assignment.startDate.getTime()));
    const overlapEnd = new Date(Math.min(input.monthEnd.getTime(), assignment.endDate.getTime()));
    const categoryCode = assignment.project.utilizationCategory?.code ?? "Chg";

    const calcResult = calculateAllocation({
      lcrCents: input.resourceLcrCents,
      hoursPerDay: assignment.hoursPerDay,
      startDate: overlapStart,
      endDate: overlapEnd,
      availability: input.weeklyAvailability,
      absenceDays: input.absenceDays,
      calculationRules: input.calcRules,
    });
    if (calcResult.workingDays <= 0 && calcResult.totalHours <= 0) {
      continue;
    }

    totalWorkingDaysInMonth += calcResult.workingDays;
    totalAllocHours += calcResult.totalHours;
    totalAllocCostCents += calcResult.totalCostCents;
    assignmentBreakdown.push({
      id: assignment.id,
      projectId: assignment.project.id,
      projectName: assignment.project.name,
      projectCode: assignment.project.shortCode,
      status: assignment.status,
      bookedHours: calcResult.totalHours,
    });

    if (calcResult.totalChargeableHours !== undefined) {
      totalChargeableHours += calcResult.totalChargeableHours;
      totalProjectCostCents += calcResult.totalProjectCostCents ?? calcResult.totalCostCents;
      hasRulesEffect = true;
    } else {
      totalChargeableHours += calcResult.totalHours;
      totalProjectCostCents += calcResult.totalCostCents;
    }

    slices.push({
      hoursPerDay: assignment.hoursPerDay,
      workingDays: calcResult.workingDays,
      categoryCode,
      ...(calcResult.totalChargeableHours !== undefined
        ? { totalChargeableHours: calcResult.totalChargeableHours }
        : {}),
    });
  }

  const forecast = deriveResourceForecast({
    fte: input.resourceFte,
    targetPercentage: input.targetPct,
    assignments: slices,
    sah: input.effectiveAvailableHours,
  });

  const dailyCostCents = input.assignments.length > 0
    ? Math.round(input.assignments[0]!.hoursPerDay * input.resourceLcrCents)
    : 0;
  const avgHoursPerDay = input.assignments.length > 0
    ? input.assignments.reduce((sum, assignment) => sum + assignment.hoursPerDay, 0) / input.assignments.length
    : 0;
  const utilizationPct = input.effectiveAvailableHours > 0
    ? (totalAllocHours / input.effectiveAvailableHours) * 100
    : 0;
  const chargeableHours = forecast.chg * input.effectiveAvailableHours;

  return {
    assignmentBreakdown,
    avgHoursPerDay,
    chargeableHours,
    dailyCostCents,
    forecast,
    hasRulesEffect,
    totalAllocCostCents,
    totalAllocHours,
    totalChargeableHours,
    totalProjectCostCents,
    totalWorkingDaysInMonth,
    utilizationPct,
  };
}
