import { AllocationStatus } from "@capakraken/shared";
import { describe, expect, it } from "vitest";
import { computeBudgetStatus } from "../budget/monitor.js";

const now = new Date("2025-01-06");
const endDate = new Date("2025-03-07");

const mkAlloc = (
  hoursPerDay: number,
  dailyCostCents: number,
  status: AllocationStatus = AllocationStatus.CONFIRMED,
) => ({
  status,
  dailyCostCents,
  hoursPerDay,
  startDate: now,
  endDate,
});

describe("computeBudgetStatus", () => {
  it("returns 0% utilization for no allocations", () => {
    const result = computeBudgetStatus(1000000, 100, [], now, endDate);
    expect(result.allocatedCents).toBe(0);
    expect(result.utilizationPercent).toBe(0);
    expect(result.remainingCents).toBe(1000000);
    expect(result.warnings).toHaveLength(0);
  });

  it("calculates correct utilization", () => {
    // 1 alloc, 10 working days, 8000 cents/day = 80000 cents
    const alloc = { ...mkAlloc(8, 8000), startDate: new Date("2025-01-06"), endDate: new Date("2025-01-17") };
    const result = computeBudgetStatus(400000, 100, [alloc], now, endDate);
    expect(result.confirmedCents).toBe(80000);
    expect(result.utilizationPercent).toBeCloseTo(20, 0);
  });

  it("emits WARNING at 85% utilization", () => {
    // Budget 100000, alloc cost 87000 = 87%
    const alloc = { ...mkAlloc(8, 87000 / 10), startDate: new Date("2025-01-06"), endDate: new Date("2025-01-17") };
    const result = computeBudgetStatus(100000, 100, [alloc], now, endDate);
    const hasWarning = result.warnings.some((w) => w.code === "BUDGET_WARNING");
    expect(hasWarning).toBe(true);
  });

  it("emits CRITICAL at 95% utilization", () => {
    const alloc = { ...mkAlloc(8, 96000 / 10), startDate: new Date("2025-01-06"), endDate: new Date("2025-01-17") };
    const result = computeBudgetStatus(100000, 100, [alloc], now, endDate);
    const hasCritical = result.warnings.some((w) => w.code === "BUDGET_CRITICAL");
    expect(hasCritical).toBe(true);
  });

  it("emits EXCEEDED when allocations exceed budget", () => {
    const alloc = { ...mkAlloc(8, 120000 / 10), startDate: new Date("2025-01-06"), endDate: new Date("2025-01-17") };
    const result = computeBudgetStatus(100000, 100, [alloc], now, endDate);
    const hasExceeded = result.warnings.some((w) => w.code === "BUDGET_EXCEEDED");
    expect(hasExceeded).toBe(true);
  });

  it("applies win probability weighting", () => {
    const alloc = { ...mkAlloc(8, 10000), startDate: new Date("2025-01-06"), endDate: new Date("2025-01-17") };
    const result = computeBudgetStatus(1000000, 50, [alloc], now, endDate);
    // allocated = 10 days × 10000 = 100000, weighted = 50% = 50000
    expect(result.winProbabilityWeightedCents).toBe(Math.round(result.allocatedCents * 0.5));
  });

  it("separates proposed from confirmed costs", () => {
    const confirmed = { ...mkAlloc(8, 5000, AllocationStatus.CONFIRMED), startDate: new Date("2025-01-06"), endDate: new Date("2025-01-10") };
    const proposed = { ...mkAlloc(8, 5000, AllocationStatus.PROPOSED), startDate: new Date("2025-01-06"), endDate: new Date("2025-01-10") };
    const result = computeBudgetStatus(1000000, 100, [confirmed, proposed], now, endDate);
    expect(result.confirmedCents).toBeGreaterThan(0);
    expect(result.proposedCents).toBeGreaterThan(0);
    expect(result.confirmedCents).toBe(result.proposedCents);
  });
});
