import { describe, it, expect } from "vitest";
import {
  canPerformAction,
  getAvailableActions,
  getTransition,
  requiresNote,
} from "@/lib/po-state-machine";

describe("PO State Machine", () => {
  describe("canPerformAction", () => {
    it("allows TECHNICAL to submit a DRAFT", () => {
      expect(canPerformAction("DRAFT", "submit", "TECHNICAL")).toBe(true);
    });

    it("allows MANNING to submit a DRAFT", () => {
      expect(canPerformAction("DRAFT", "submit", "MANNING")).toBe(true);
    });

    it("disallows ACCOUNTS from submitting a DRAFT", () => {
      expect(canPerformAction("DRAFT", "submit", "ACCOUNTS")).toBe(false);
    });

    it("allows MANAGER to approve in MGR_REVIEW", () => {
      expect(canPerformAction("MGR_REVIEW", "approve", "MANAGER")).toBe(true);
    });

    it("allows SUPERUSER to approve in MGR_REVIEW", () => {
      expect(canPerformAction("MGR_REVIEW", "approve", "SUPERUSER")).toBe(true);
    });

    it("disallows TECHNICAL from approving", () => {
      expect(canPerformAction("MGR_REVIEW", "approve", "TECHNICAL")).toBe(false);
    });

    it("allows ACCOUNTS to process payment on MGR_APPROVED", () => {
      expect(canPerformAction("MGR_APPROVED", "process_payment", "ACCOUNTS")).toBe(true);
    });

    it("allows TECHNICAL to confirm receipt on PAID_DELIVERED", () => {
      expect(canPerformAction("PAID_DELIVERED", "confirm_receipt", "TECHNICAL")).toBe(true);
    });

    it("disallows action on wrong status", () => {
      expect(canPerformAction("CLOSED", "approve", "MANAGER")).toBe(false);
    });
  });

  describe("getTransition", () => {
    it("returns correct target state for submit from DRAFT", () => {
      const t = getTransition("DRAFT", "submit");
      expect(t?.to).toBe("SUBMITTED");
    });

    it("returns correct target state for approve from MGR_REVIEW", () => {
      const t = getTransition("MGR_REVIEW", "approve");
      expect(t?.to).toBe("MGR_APPROVED");
    });

    it("returns correct target state for reject from MGR_REVIEW", () => {
      const t = getTransition("MGR_REVIEW", "reject");
      expect(t?.to).toBe("REJECTED");
    });

    it("returns null for unknown action on status", () => {
      expect(getTransition("CLOSED", "approve")).toBeNull();
    });
  });

  describe("requiresNote", () => {
    it("reject requires a note", () => {
      expect(requiresNote("MGR_REVIEW", "reject")).toBe(true);
    });

    it("approve does not require a note", () => {
      expect(requiresNote("MGR_REVIEW", "approve")).toBe(false);
    });

    it("approve_with_note requires a note", () => {
      expect(requiresNote("MGR_REVIEW", "approve_with_note")).toBe(true);
    });

    it("request_edits requires a note", () => {
      expect(requiresNote("MGR_REVIEW", "request_edits")).toBe(true);
    });
  });

  describe("getAvailableActions", () => {
    it("returns submit for TECHNICAL on DRAFT", () => {
      const actions = getAvailableActions("DRAFT", "TECHNICAL");
      expect(actions).toContain("submit");
    });

    it("returns all 5 actions for MANAGER on MGR_REVIEW", () => {
      const actions = getAvailableActions("MGR_REVIEW", "MANAGER");
      expect(actions).toContain("approve");
      expect(actions).toContain("approve_with_note");
      expect(actions).toContain("reject");
      expect(actions).toContain("request_edits");
      expect(actions).toContain("request_vendor_id");
    });

    it("returns empty for ACCOUNTS on DRAFT", () => {
      const actions = getAvailableActions("DRAFT", "ACCOUNTS");
      expect(actions).toHaveLength(0);
    });

    it("returns empty for closed PO", () => {
      const actions = getAvailableActions("CLOSED", "MANAGER");
      expect(actions).toHaveLength(0);
    });

    // Role expansions added in feat: manager PO creation
    it("returns submit for MANAGER on DRAFT", () => {
      expect(getAvailableActions("DRAFT", "MANAGER")).toContain("submit");
    });

    it("returns submit for MANAGER on EDITS_REQUESTED", () => {
      expect(getAvailableActions("EDITS_REQUESTED", "MANAGER")).toContain("submit");
    });

    it("returns provide_vendor_id for ACCOUNTS on VENDOR_ID_PENDING", () => {
      expect(getAvailableActions("VENDOR_ID_PENDING", "ACCOUNTS")).toContain("provide_vendor_id");
    });

    it("still returns no submit for ACCOUNTS on DRAFT", () => {
      expect(getAvailableActions("DRAFT", "ACCOUNTS")).not.toContain("submit");
    });

    it("AUDITOR has no available actions on any status", () => {
      for (const status of ["DRAFT", "MGR_REVIEW", "VENDOR_ID_PENDING", "MGR_APPROVED"] as const) {
        expect(getAvailableActions(status, "AUDITOR")).toHaveLength(0);
      }
    });
  });

  describe("canPerformAction — new role expansions", () => {
    it("MANAGER can submit from DRAFT", () => {
      expect(canPerformAction("DRAFT", "submit", "MANAGER")).toBe(true);
    });

    it("MANAGER can submit from EDITS_REQUESTED", () => {
      expect(canPerformAction("EDITS_REQUESTED", "submit", "MANAGER")).toBe(true);
    });

    it("ACCOUNTS can provide_vendor_id from VENDOR_ID_PENDING", () => {
      expect(canPerformAction("VENDOR_ID_PENDING", "provide_vendor_id", "ACCOUNTS")).toBe(true);
    });

    it("ACCOUNTS still cannot submit from DRAFT", () => {
      expect(canPerformAction("DRAFT", "submit", "ACCOUNTS")).toBe(false);
    });

    it("AUDITOR cannot perform any action", () => {
      expect(canPerformAction("DRAFT", "submit", "AUDITOR")).toBe(false);
      expect(canPerformAction("MGR_REVIEW", "approve", "AUDITOR")).toBe(false);
    });

    it("ADMIN cannot perform any PO state transitions", () => {
      expect(canPerformAction("DRAFT", "submit", "ADMIN")).toBe(false);
      expect(canPerformAction("MGR_REVIEW", "approve", "ADMIN")).toBe(false);
      expect(canPerformAction("MGR_APPROVED", "process_payment", "ADMIN")).toBe(false);
    });
  });
});
