import { describe, expect, test } from "bun:test";
import type { ObservabilityReportQuery } from "@overdeck/report-contract";
import type { FactoryAgentAttemptView, FactoryRunView, FactoryUsageView } from "../adapters/factory";
import type { SessionsPanelData } from "../adapters/sessions";
import { buildCapacityReportSection } from "./capacity-report";

const QUERY: ObservabilityReportQuery = {
  from: "2026-08-16T00:00:00.000Z",
  to: "2026-08-17T00:00:00.000Z",
  timezone: "UTC",
};

function usage(overrides: Partial<FactoryUsageView> = {}): FactoryUsageView {
  return {
    inputTokens: 60,
    outputTokens: 40,
    cacheReadTokens: 0,
    cacheWriteTokens: 0,
    reasoningTokens: 0,
    totalTokens: 100,
    inputCost: 0.6,
    outputCost: 0.4,
    cacheReadCost: 0,
    cacheWriteCost: 0,
    totalCost: 1,
    usageEstimated: false,
    billingStatus: "recorded",
    maxTokens: null,
    contextWindow: null,
    providerFailure: null,
    ...overrides,
  };
}

function attempt(overrides: Partial<FactoryAgentAttemptView> = {}): FactoryAgentAttemptView {
  return {
    attemptId: "attempt-1",
    phaseId: "build",
    agent: "coder",
    sessionId: "session-1",
    command: null,
    systemPrompt: null,
    userPrompt: null,
    returncode: 0,
    signal: null,
    timedOut: false,
    timeoutKind: null,
    tokens: 100,
    error: null,
    stderrPath: null,
    host: "debian1",
    account: "claude11",
    model: "sonnet",
    usage: usage(),
    providerFailure: null,
    startedAt: "2026-08-16T01:00:00.000Z",
    lastOutputAt: "2026-08-16T01:05:00.000Z",
    endedAt: "2026-08-16T01:10:00.000Z",
    durationMs: 600_000,
    idleMs: 0,
    toolCalls: [],
    ...overrides,
  };
}

function run(overrides: Partial<FactoryRunView> = {}): FactoryRunView {
  return {
    adwId: "adw-1",
    repo: "/work/overdeck",
    repoName: "overdeck",
    adwName: "build",
    runSlug: "capacity",
    preset: null,
    request: "Build reports",
    status: "success",
    engineer: null,
    startedAt: "2026-08-16T01:00:00.000Z",
    endedAt: "2026-08-16T01:10:00.000Z",
    totalTokens: 100,
    totalCost: 1,
    phases: [],
    events: [],
    attempts: [attempt()],
    gates: [],
    diffs: [],
    processes: [],
    unavailableTables: [],
    decisions: [],
    ...overrides,
  };
}

const SESSIONS = {
  ledgerDir: "/redacted",
  ledgerMissing: false,
  unreadableFiles: [],
  tmuxAvailable: true,
  attachEnabled: false,
  localHost: "laptop",
  homeDir: null,
  hosts: [],
  hostsRegistryPath: "/redacted",
  hostsRegistryMissing: false,
  hostProbes: [],
  sessions: [],
  boxResident: [],
} satisfies SessionsPanelData;

const COMPLETE_INPUT = {
  factoryRuns: [run()],
  limits: {
    stale: false,
    ageSeconds: 3,
    accounts: [{
      slug: "claude:claude11",
      provider: "claude" as const,
      label: "Claude · Primary",
      percent: 42,
      status: "ok",
      spend: { amount: 12, limit: 50, currency: "USD", display: "$12 / $50" },
      window: { primaryResetAt: Date.parse("2026-08-20T00:00:00.000Z"), secondaryResetAt: null },
      capEtaMinutes: null,
    }],
  },
  sessions: SESSIONS,
  agents: { fleet: [], orphans: 0, events: [], culprits: [], totalLive: 3 },
  cluster: { debian1: "online" as const, autoscaler: { state: "idle" as const, idle: 1, pressure: 0 }, buildslot: { running: 2, queued: 4, p95WaitSeconds: 30 } },
};

describe("buildCapacityReportSection", () => {
  test("reports recorded usage and explicit live capacity", () => {
    const section = buildCapacityReportSection(QUERY, COMPLETE_INPUT);

    expect(section.status).toBe("complete");
    expect(section.metrics.map((metric) => [metric.id, metric.value])).toEqual([
      ["recorded-tokens", 100],
      ["recorded-cost", 1],
      ["active-sessions", 0],
      ["queued-builds", 4],
    ]);
    expect(section.byModel[0]).toMatchObject({ label: "sonnet", tokens: 100, cost: 1, attempts: 1 });
    expect(section.accounts[0]).toMatchObject({ id: "claude:claude11", usedPercent: 42, spendAmount: 12, currency: "USD" });
    expect(section.snapshot).toEqual({ activeSessions: 0, liveAgents: 3, runningBuilds: 2, queuedBuilds: 4, buildWaitP95Ms: 30_000 });
    expect(section.costPerSucceededRun).toBe(1);
  });

  test("excludes estimated cost and leaves incomplete attribution visible", () => {
    const factoryRuns = [run({ attempts: [attempt({ model: null, account: null, usage: usage({ totalCost: 9, usageEstimated: true }) })] })];
    const section = buildCapacityReportSection(QUERY, { ...COMPLETE_INPUT, factoryRuns });

    expect(section.metrics.find((metric) => metric.id === "recorded-cost")).toMatchObject({ value: null, coverage: "partial" });
    expect(section.byModel[0]).toMatchObject({ label: "Unattributed", unattributed: true, cost: null });
    expect(section.costPerSucceededRun).toBeNull();
    expect(section.gaps.some((gap) => gap.reason.includes("estimated cost"))).toBe(true);
    expect(section.gaps.some((gap) => gap.reason.includes("explicit model, account, host, or project"))).toBe(true);
  });

  test("never turns missing authorities into zero", () => {
    const section = buildCapacityReportSection(QUERY, {});

    expect(section.status).toBe("unavailable");
    expect(section.metrics.every((metric) => metric.value === null)).toBe(true);
    expect(section.snapshot).toEqual({ activeSessions: null, liveAgents: null, runningBuilds: null, queuedBuilds: null, buildWaitP95Ms: null });
    expect(section.gaps).toHaveLength(5);
  });

  test("uses only attempts inside the requested range and project", () => {
    const section = buildCapacityReportSection({ ...QUERY, projects: ["other"] }, COMPLETE_INPUT);
    expect(section.metrics.find((metric) => metric.id === "recorded-tokens")?.value).toBe(0);
    expect(section.byModel).toEqual([]);
  });
});
