import { describe, it, expect } from "vitest";
import {
  BOARD_STAGES,
  canPerformAction,
  canReject,
  getAvailableActions,
  getTransition,
} from "@/lib/application-pipeline";

// The gated 7-stage recruitment pipeline (Crewing-Implementation-Spec §5.1).
describe("Application pipeline state machine", () => {
  it("has the 7 board stages in order", () => {
    expect(BOARD_STAGES).toEqual([
      "SHORTLISTED",
      "COMPETENCY_AND_REFERENCES",
      "DOC_VERIFICATION",
      "SALARY_AGREEMENT",
      "PROPOSED",
      "INTERVIEW",
      "SELECTED",
    ]);
  });

  describe("sourcing advances (MPO/Manager)", () => {
    it("MPO walks the early stages", () => {
      expect(getTransition("SHORTLISTED", "start_competency")?.to).toBe("COMPETENCY_AND_REFERENCES");
      expect(canPerformAction("SHORTLISTED", "start_competency", "MANNING")).toBe(true);
      expect(getTransition("COMPETENCY_AND_REFERENCES", "verify_competency")?.to).toBe("DOC_VERIFICATION");
      expect(getTransition("DOC_VERIFICATION", "verify_docs")?.to).toBe("SALARY_AGREEMENT");
      expect(getTransition("PROPOSED", "propose_accepted")?.to).toBe("INTERVIEW");
    });
  });

  describe("Manager-gated advances (spec §6)", () => {
    it("salary approval is Manager-only", () => {
      expect(canPerformAction("SALARY_AGREEMENT", "approve_salary", "MANAGER")).toBe(true);
      expect(canPerformAction("SALARY_AGREEMENT", "approve_salary", "SUPERUSER")).toBe(true);
      expect(canPerformAction("SALARY_AGREEMENT", "approve_salary", "MANNING")).toBe(false);
      expect(getTransition("SALARY_AGREEMENT", "approve_salary")?.to).toBe("PROPOSED");
    });

    it("selection is Manager-only", () => {
      expect(canPerformAction("INTERVIEW", "select", "MANAGER")).toBe(true);
      expect(canPerformAction("INTERVIEW", "select", "MANNING")).toBe(false);
      expect(getTransition("INTERVIEW", "select")?.to).toBe("SELECTED");
    });
  });

  it("rejects actions on the wrong stage", () => {
    expect(getTransition("SHORTLISTED", "select")).toBeNull();
    expect(getTransition("SELECTED", "approve_salary")).toBeNull();
  });

  it("offers MPO only sourcing actions, Manager the gated ones", () => {
    expect(getAvailableActions("SALARY_AGREEMENT", "MANNING")).toHaveLength(0);
    expect(getAvailableActions("SALARY_AGREEMENT", "MANAGER")).toEqual(["approve_salary"]);
    expect(getAvailableActions("SHORTLISTED", "SITE_STAFF")).toHaveLength(0);
  });

  describe("rejection (orthogonal)", () => {
    it("MPO/Manager can reject from any active stage", () => {
      expect(canReject("COMPETENCY_AND_REFERENCES", "MANNING")).toBe(true);
      expect(canReject("INTERVIEW", "MANAGER")).toBe(true);
    });
    it("cannot reject once selected/onboarded/already rejected", () => {
      expect(canReject("SELECTED", "MANAGER")).toBe(false);
      expect(canReject("ONBOARDED", "MANAGER")).toBe(false);
      expect(canReject("REJECTED", "MANAGER")).toBe(false);
    });
    it("site staff cannot reject", () => {
      expect(canReject("SHORTLISTED", "SITE_STAFF")).toBe(false);
    });
  });
});
