import { computeBudgetStatus } from "@capakraken/engine";
import type { TRPCContext } from "../trpc.js";
import { fmtEur } from "../lib/format-utils.js";
import { type GraphLink, type GraphNode, l, n } from "./computation-graph-shared.js";

type ResourceBudgetProject = {
  id: string;
  name: string;
  budgetCents: number | null;
  winProbability: number;
};

type ResourceBudgetAssignment = {
  project: ResourceBudgetProject;
};

export type ResourceBudgetGraph = {
  nodes: GraphNode[];
  links: GraphLink[];
};

export async function readResourceBudgetGraph(
  db: TRPCContext["db"],
  assignments: ResourceBudgetAssignment[],
  monthStart: Date,
  monthEnd: Date,
): Promise<ResourceBudgetGraph> {
  const budgetProject = assignments.find((assignment) => (
    assignment.project.budgetCents != null && assignment.project.budgetCents > 0
  ))?.project;

  if (!budgetProject?.budgetCents) {
    return { nodes: [], links: [] };
  }

  const projectAllocs = await db.assignment.findMany({
    where: { projectId: budgetProject.id },
    select: {
      status: true,
      dailyCostCents: true,
      startDate: true,
      endDate: true,
      hoursPerDay: true,
    },
  });
  const budgetStatus = computeBudgetStatus(
    budgetProject.budgetCents,
    budgetProject.winProbability,
    projectAllocs.map((projectAllocation) => ({
      status: projectAllocation.status as unknown as string,
      dailyCostCents: projectAllocation.dailyCostCents,
      startDate: projectAllocation.startDate,
      endDate: projectAllocation.endDate,
      hoursPerDay: projectAllocation.hoursPerDay,
    })) as Parameters<typeof computeBudgetStatus>[2],
    monthStart,
    monthEnd,
  );

  return {
    nodes: [
      n("input.budgetCents", "Project Budget", fmtEur(budgetProject.budgetCents), "EUR", "INPUT", `Budget for ${budgetProject.name}`, 0),
      n("input.winProbability", "Win Probability", `${budgetProject.winProbability}%`, "%", "INPUT", "Project win probability", 0),
      n("budget.confirmedCents", "Confirmed", fmtEur(budgetStatus.confirmedCents), "EUR", "BUDGET", "Sum of CONFIRMED/ACTIVE allocation costs", 2, "Σ(confirmed allocs)"),
      n("budget.proposedCents", "Proposed", fmtEur(budgetStatus.proposedCents), "EUR", "BUDGET", "Sum of PROPOSED allocation costs", 2, "Σ(proposed allocs)"),
      n("budget.allocatedCents", "Allocated", fmtEur(budgetStatus.allocatedCents), "EUR", "BUDGET", "Total allocated budget", 2, "confirmed + proposed"),
      n("budget.remainingCents", "Remaining", fmtEur(budgetStatus.remainingCents), "EUR", "BUDGET", "Remaining budget", 3, "budget - allocated"),
      n("budget.utilizationPct", "Utilization", `${budgetStatus.utilizationPercent.toFixed(1)}%`, "%", "BUDGET", "Budget utilization percentage", 3, "allocated / budget × 100"),
      n("budget.weightedCents", "Win-Weighted", fmtEur(budgetStatus.winProbabilityWeightedCents), "EUR", "BUDGET", "Win-probability-weighted cost", 3, "allocated × winProb / 100"),
    ],
    links: [
      l("alloc.totalCostCents", "budget.confirmedCents", "per assignment", 1),
      l("budget.confirmedCents", "budget.allocatedCents", "+", 2),
      l("budget.proposedCents", "budget.allocatedCents", "+", 2),
      l("input.budgetCents", "budget.remainingCents", "−", 2),
      l("budget.allocatedCents", "budget.remainingCents", "−", 2),
      l("budget.allocatedCents", "budget.utilizationPct", "÷ budget × 100", 2),
      l("input.budgetCents", "budget.utilizationPct", "÷", 1),
      l("budget.allocatedCents", "budget.weightedCents", "× winProb / 100", 1),
      l("input.winProbability", "budget.weightedCents", "×", 1),
    ],
  };
}
