/**
 * Tests for SF visualizer data loader.
 * Verifies the VisualizerData interface shape and source-file contracts.
 */

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, it } from "vitest";

const __dirname = dirname(fileURLToPath(import.meta.url));

const dataPath = join(__dirname, "..", "visualizer-data.ts");
const dataSrc = readFileSync(dataPath, "utf-8");

describe("visualizer-data.ts source contracts", () => {
  // Interface exports
  it("exports VisualizerData interface", () => {
    assert.ok(dataSrc.includes("export interface VisualizerData"));
  });

  it("exports VisualizerMilestone interface", () => {
    assert.ok(dataSrc.includes("export interface VisualizerMilestone"));
  });

  it("exports VisualizerSlice interface", () => {
    assert.ok(dataSrc.includes("export interface VisualizerSlice"));
  });

  it("exports VisualizerTask interface", () => {
    assert.ok(dataSrc.includes("export interface VisualizerTask"));
  });

  it("exports CriticalPathInfo interface", () => {
    assert.ok(dataSrc.includes("export interface CriticalPathInfo"));
  });

  it("exports AgentActivityInfo interface", () => {
    assert.ok(dataSrc.includes("export interface AgentActivityInfo"));
  });

  it("exports ChangelogEntry interface", () => {
    assert.ok(dataSrc.includes("export interface ChangelogEntry"));
  });

  it("exports ChangelogInfo interface", () => {
    assert.ok(dataSrc.includes("export interface ChangelogInfo"));
  });

  it("exports SliceVerification interface", () => {
    assert.ok(dataSrc.includes("export interface SliceVerification"));
  });

  it("exports KnowledgeInfo interface", () => {
    assert.ok(dataSrc.includes("export interface KnowledgeInfo"));
  });

  it("exports CapturesInfo interface", () => {
    assert.ok(dataSrc.includes("export interface CapturesInfo"));
  });

  it("exports HealthInfo interface", () => {
    assert.ok(dataSrc.includes("export interface HealthInfo"));
  });

  it("exports VisualizerDiscussionState interface", () => {
    assert.ok(dataSrc.includes("export interface VisualizerDiscussionState"));
  });

  it("exports DiscussionState type", () => {
    assert.ok(dataSrc.includes("export type DiscussionState"));
  });

  it("exports VisualizerSliceRef interface", () => {
    assert.ok(dataSrc.includes("export interface VisualizerSliceRef"));
  });

  it("exports VisualizerSliceActivity interface", () => {
    assert.ok(dataSrc.includes("export interface VisualizerSliceActivity"));
  });

  it("exports VisualizerStats interface", () => {
    assert.ok(dataSrc.includes("export interface VisualizerStats"));
  });

  it("exports loadVisualizerData function", () => {
    assert.ok(dataSrc.includes("export async function loadVisualizerData"));
  });

  it("exports computeCriticalPath function", () => {
    assert.ok(dataSrc.includes("export function computeCriticalPath"));
  });

  it("uses deriveState for state derivation", () => {
    assert.ok(dataSrc.includes("deriveState"));
  });

  it("uses findMilestoneIds to enumerate milestones", () => {
    assert.ok(dataSrc.includes("findMilestoneIds"));
  });

  it("uses parseRoadmap for roadmap parsing", () => {
    assert.ok(dataSrc.includes("parseRoadmap"));
  });

  it("uses parsePlan for plan parsing", () => {
    assert.ok(dataSrc.includes("parsePlan"));
  });

  it("uses parseSummary for changelog parsing", () => {
    assert.ok(dataSrc.includes("parseSummary"));
  });

  it("uses getLedger for in-memory metrics", () => {
    assert.ok(dataSrc.includes("getLedger"));
  });

  it("uses loadLedgerFromDisk as fallback", () => {
    assert.ok(dataSrc.includes("loadLedgerFromDisk"));
  });

  it("uses getProjectTotals for aggregation", () => {
    assert.ok(dataSrc.includes("getProjectTotals"));
  });

  it("uses aggregateByPhase", () => {
    assert.ok(dataSrc.includes("aggregateByPhase"));
  });

  it("uses aggregateBySlice", () => {
    assert.ok(dataSrc.includes("aggregateBySlice"));
  });

  it("uses aggregateByModel", () => {
    assert.ok(dataSrc.includes("aggregateByModel"));
  });

  it("uses aggregateByTier", () => {
    assert.ok(dataSrc.includes("aggregateByTier"));
  });

  it("uses formatTierSavings", () => {
    assert.ok(dataSrc.includes("formatTierSavings"));
  });

  it("uses loadAllCaptures", () => {
    assert.ok(dataSrc.includes("loadAllCaptures"));
  });

  it("uses countPendingCaptures", () => {
    assert.ok(dataSrc.includes("countPendingCaptures"));
  });

  it("uses loadEffectiveSFPreferences", () => {
    assert.ok(dataSrc.includes("loadEffectiveSFPreferences"));
  });

  it("uses resolveSfRootFile for KNOWLEDGE path", () => {
    assert.ok(dataSrc.includes("resolveSfRootFile"));
  });

  it("VisualizerMilestone has dependsOn field", () => {
    assert.ok(dataSrc.includes("dependsOn: string[]"));
  });

  it("VisualizerSlice has depends field", () => {
    assert.ok(dataSrc.includes("depends: string[]"));
  });

  it("VisualizerData has nullable totals", () => {
    assert.ok(dataSrc.includes("totals: ProjectTotals | null"));
  });

  it("VisualizerData has units array", () => {
    assert.ok(dataSrc.includes("units: UnitMetrics[]"));
  });

  it("VisualizerTask has optional estimate field", () => {
    assert.ok(dataSrc.includes("estimate?: string"));
  });

  it("VisualizerData has criticalPath field", () => {
    assert.ok(dataSrc.includes("criticalPath: CriticalPathInfo"));
  });

  it("VisualizerData has remainingSliceCount field", () => {
    assert.ok(dataSrc.includes("remainingSliceCount: number"));
  });

  it("VisualizerData has agentActivity field", () => {
    assert.ok(dataSrc.includes("agentActivity: AgentActivityInfo | null"));
  });

  it("VisualizerData has changelog field", () => {
    assert.ok(dataSrc.includes("changelog: ChangelogInfo"));
  });

  it("VisualizerData has sliceVerifications field", () => {
    assert.ok(dataSrc.includes("sliceVerifications: SliceVerification[]"));
  });

  it("VisualizerData has knowledge field", () => {
    assert.ok(dataSrc.includes("knowledge: KnowledgeInfo"));
  });

  it("VisualizerData has captures field", () => {
    assert.ok(dataSrc.includes("captures: CapturesInfo"));
  });

  it("VisualizerData has health field", () => {
    assert.ok(dataSrc.includes("health: HealthInfo"));
  });

  it("VisualizerData has stats field", () => {
    assert.ok(dataSrc.includes("stats: VisualizerStats"));
  });

  it("VisualizerData has discussion field", () => {
    assert.ok(dataSrc.includes("discussion: VisualizerDiscussionState[]"));
  });

  it("uses loadDiscussionState helper", () => {
    assert.ok(dataSrc.includes("loadDiscussionState"));
  });

  it("uses buildVisualizerStats helper", () => {
    assert.ok(dataSrc.includes("buildVisualizerStats"));
  });

  it("VisualizerData has byTier field", () => {
    assert.ok(dataSrc.includes("byTier: TierAggregate[]"));
  });

  it("VisualizerData has tierSavingsLine field", () => {
    assert.ok(dataSrc.includes("tierSavingsLine: string"));
  });

  it("completedAt coerces to String() for YAML Date safety", () => {
    assert.ok(dataSrc.includes("String(summary.frontmatter.completed_at"));
  });

  it("changelog sort coerces completedAt to String() for YAML Date safety", () => {
    assert.ok(
      dataSrc.includes("String(b.completedAt") &&
        dataSrc.includes("String(a.completedAt"),
    );
  });
});

describe("visualizer-overlay.ts source contracts", () => {
  const overlayPath = join(__dirname, "..", "visualizer-overlay.ts");
  const overlaySrc = readFileSync(overlayPath, "utf-8");

  it("exports SFVisualizerOverlay class", () => {
    assert.ok(overlaySrc.includes("export class SFVisualizerOverlay"));
  });

  it("overlay uses loadVisualizerData", () => {
    assert.ok(overlaySrc.includes("loadVisualizerData"));
  });

  it("overlay delegates to renderProgressView", () => {
    assert.ok(overlaySrc.includes("renderProgressView"));
  });

  it("overlay delegates to renderDepsView", () => {
    assert.ok(overlaySrc.includes("renderDepsView"));
  });

  it("overlay delegates to renderMetricsView", () => {
    assert.ok(overlaySrc.includes("renderMetricsView"));
  });

  it("overlay delegates to renderTimelineView", () => {
    assert.ok(overlaySrc.includes("renderTimelineView"));
  });

  it("overlay delegates to renderAgentView", () => {
    assert.ok(overlaySrc.includes("renderAgentView"));
  });

  it("overlay delegates to renderChangelogView", () => {
    assert.ok(overlaySrc.includes("renderChangelogView"));
  });

  it("overlay delegates to renderExportView", () => {
    assert.ok(overlaySrc.includes("renderExportView"));
  });

  it("overlay delegates to renderKnowledgeView", () => {
    assert.ok(overlaySrc.includes("renderKnowledgeView"));
  });

  it("overlay delegates to renderCapturesView", () => {
    assert.ok(overlaySrc.includes("renderCapturesView"));
  });

  it("overlay delegates to renderHealthView", () => {
    assert.ok(overlaySrc.includes("renderHealthView"));
  });

  it("overlay has handleInput method", () => {
    assert.ok(overlaySrc.includes("handleInput"));
  });

  it("overlay has dispose method", () => {
    assert.ok(overlaySrc.includes("dispose"));
  });

  it("overlay has wrapInBox helper", () => {
    assert.ok(overlaySrc.includes("wrapInBox"));
  });

  it("overlay tracks active tab", () => {
    assert.ok(overlaySrc.includes("activeTab"));
  });

  it("overlay tracks per-tab scroll offsets", () => {
    assert.ok(overlaySrc.includes("scrollOffsets"));
  });

  it("overlay has filterMode state", () => {
    assert.ok(overlaySrc.includes("filterMode"));
  });

  it("overlay has filterText state", () => {
    assert.ok(overlaySrc.includes("filterText"));
  });

  it("overlay has filterField state", () => {
    assert.ok(overlaySrc.includes("filterField"));
  });

  it("overlay defines TAB_COUNT", () => {
    assert.ok(overlaySrc.includes("TAB_COUNT"));
  });

  it("overlay has 10 tab labels", () => {
    assert.ok(overlaySrc.includes("0 Export"));
  });
});

describe("commands/handlers/core.ts integration", () => {
  const coreHandlerPath = join(__dirname, "..", "commands", "handlers", "core.ts");
  const coreHandlerSrc = readFileSync(coreHandlerPath, "utf-8");

  it("core.ts has visualize in subcommands array", () => {
    assert.ok(coreHandlerSrc.includes('"visualize"'));
  });

  it("core.ts imports SFVisualizerOverlay", () => {
    assert.ok(coreHandlerSrc.includes("SFVisualizerOverlay"));
  });

  it("core.ts has handleVisualize handler", () => {
    assert.ok(coreHandlerSrc.includes("handleVisualize"));
  });
});