import { describe, it, expect } from "vitest";
import {
  buildDiscussPrompt,
  buildVerifyPrompt,
  canAdvancePhase,
  canGoBack,
  getPhaseLabel,
  generateCriterionId,
  type WorkflowState,
  type VerifyCriterion,
} from "./workflow";

// ─── buildDiscussPrompt ───────────────────────────────────────────────────────

describe("buildDiscussPrompt", () => {
  it("includes the description in the output", () => {
    const prompt = buildDiscussPrompt("Build a user authentication system");
    expect(prompt).toContain("Build a user authentication system");
  });

  it("references CONTEXT.md", () => {
    const prompt = buildDiscussPrompt("some project");
    expect(prompt).toContain("CONTEXT.md");
  });

  it("mentions acceptance criteria section", () => {
    const prompt = buildDiscussPrompt("some project");
    expect(prompt.toLowerCase()).toContain("acceptance criteria");
  });

  it("returns a non-empty string for any description", () => {
    expect(buildDiscussPrompt("a").length).toBeGreaterThan(0);
    expect(buildDiscussPrompt("very long description ".repeat(20)).length).toBeGreaterThan(0);
  });
});

// ─── buildVerifyPrompt ────────────────────────────────────────────────────────

describe("buildVerifyPrompt", () => {
  it("references VERIFY.md", () => {
    const prompt = buildVerifyPrompt([]);
    expect(prompt).toContain("VERIFY.md");
  });

  it("handles empty criteria list gracefully", () => {
    const prompt = buildVerifyPrompt([]);
    expect(prompt.length).toBeGreaterThan(0);
    expect(prompt).not.toContain("undefined");
  });

  it("includes all criteria text in the output", () => {
    const criteria: VerifyCriterion[] = [
      { id: "c1", text: "Login must work", status: "pending" },
      { id: "c2", text: "Tests must pass", status: "pending" },
    ];
    const prompt = buildVerifyPrompt(criteria);
    expect(prompt).toContain("Login must work");
    expect(prompt).toContain("Tests must pass");
  });

  it("numbers criteria starting from 1", () => {
    const criteria: VerifyCriterion[] = [{ id: "c1", text: "First criterion", status: "pending" }];
    const prompt = buildVerifyPrompt(criteria);
    expect(prompt).toContain("1. First criterion");
  });

  it("includes all criteria when multiple are provided", () => {
    const criteria: VerifyCriterion[] = [
      { id: "c1", text: "Alpha", status: "pending" },
      { id: "c2", text: "Beta", status: "pending" },
      { id: "c3", text: "Gamma", status: "pending" },
    ];
    const prompt = buildVerifyPrompt(criteria);
    expect(prompt).toContain("1. Alpha");
    expect(prompt).toContain("2. Beta");
    expect(prompt).toContain("3. Gamma");
  });
});

// ─── canAdvancePhase ──────────────────────────────────────────────────────────

function makeState(overrides: Partial<WorkflowState> = {}): WorkflowState {
  return {
    version: 1,
    currentPhase: 1,
    quickMode: false,
    discuss: { description: "", contextCaptured: false },
    plan: { tasksApproved: false },
    execute: { completed: false },
    verify: { criteria: [], verificationComplete: false, report: "" },
    ...overrides,
  };
}

describe("canAdvancePhase", () => {
  describe("phase 1 (Discuss)", () => {
    it("returns false when context not captured and not quick mode", () => {
      const state = makeState({ currentPhase: 1 });
      expect(canAdvancePhase(state)).toBe(false);
    });

    it("returns true when context is captured", () => {
      const state = makeState({
        currentPhase: 1,
        discuss: { description: "test", contextCaptured: true },
      });
      expect(canAdvancePhase(state)).toBe(true);
    });

    it("returns true in quick mode even without context captured", () => {
      const state = makeState({ currentPhase: 1, quickMode: true });
      expect(canAdvancePhase(state)).toBe(true);
    });
  });

  describe("phase 2 (Plan)", () => {
    it("returns false when plan not approved", () => {
      const state = makeState({ currentPhase: 2 });
      expect(canAdvancePhase(state)).toBe(false);
    });

    it("returns true when plan is approved", () => {
      const state = makeState({ currentPhase: 2, plan: { tasksApproved: true } });
      expect(canAdvancePhase(state)).toBe(true);
    });
  });

  describe("phase 3 (Execute)", () => {
    it("returns false when execution not completed", () => {
      const state = makeState({ currentPhase: 3 });
      expect(canAdvancePhase(state)).toBe(false);
    });

    it("returns true when execution is completed", () => {
      const state = makeState({ currentPhase: 3, execute: { completed: true } });
      expect(canAdvancePhase(state)).toBe(true);
    });
  });

  describe("phase 4 (Verify)", () => {
    it("returns false when verification not complete", () => {
      const state = makeState({ currentPhase: 4 });
      expect(canAdvancePhase(state)).toBe(false);
    });

    it("returns true when verification is complete", () => {
      const state = makeState({
        currentPhase: 4,
        verify: { criteria: [], verificationComplete: true, report: "All good" },
      });
      expect(canAdvancePhase(state)).toBe(true);
    });
  });
});

// ─── canGoBack ────────────────────────────────────────────────────────────────

describe("canGoBack", () => {
  it("returns false for phase 1", () => {
    expect(canGoBack(1)).toBe(false);
  });

  it("returns true for phase 2", () => {
    expect(canGoBack(2)).toBe(true);
  });

  it("returns true for phase 3", () => {
    expect(canGoBack(3)).toBe(true);
  });

  it("returns true for phase 4", () => {
    expect(canGoBack(4)).toBe(true);
  });
});

// ─── getPhaseLabel ────────────────────────────────────────────────────────────

describe("getPhaseLabel", () => {
  it("returns Discuss for phase 1", () => {
    expect(getPhaseLabel(1)).toBe("Discuss");
  });

  it("returns Plan for phase 2", () => {
    expect(getPhaseLabel(2)).toBe("Plan");
  });

  it("returns Execute for phase 3", () => {
    expect(getPhaseLabel(3)).toBe("Execute");
  });

  it("returns Verify for phase 4", () => {
    expect(getPhaseLabel(4)).toBe("Verify");
  });
});

// ─── generateCriterionId ─────────────────────────────────────────────────────

describe("generateCriterionId", () => {
  it("returns a non-empty string", () => {
    expect(generateCriterionId().length).toBeGreaterThan(0);
  });

  it("returns unique IDs on successive calls", () => {
    const ids = new Set(Array.from({ length: 20 }, () => generateCriterionId()));
    expect(ids.size).toBe(20);
  });

  it("starts with the expected prefix", () => {
    expect(generateCriterionId()).toMatch(/^criterion-/);
  });
});
