import { describe, it, expect, afterEach, vi } from "vitest";
import { hasPermission } from "@/lib/permissions";

// Verifies the crewing rows of the §6 grant matrix in the wiki
// Crewing-Implementation-Spec are wired up exactly as written.
describe("Crewing permissions (spec §6)", () => {
  it("SITE_STAFF holds its site-level grants", () => {
    for (const p of [
      "request_relief_cover",
      "sign_off_crew",
      "view_crew_records",
      "upload_crew_records",
      "issue_ppe",
      "apply_leave",
      "record_attendance",
      "view_attendance",
      "raise_appraisal",
    ] as const) {
      expect(hasPermission("SITE_STAFF", p)).toBe(true);
    }
  });

  it("SITE_STAFF cannot raise requisitions or decide leave or do any purchasing", () => {
    expect(hasPermission("SITE_STAFF", "raise_requisition")).toBe(false);
    expect(hasPermission("SITE_STAFF", "decide_leave")).toBe(false);
    expect(hasPermission("SITE_STAFF", "create_po")).toBe(false);
    expect(hasPermission("SITE_STAFF", "manage_ranks")).toBe(false);
  });

  it("MPO (MANNING) has NO attendance or leave access (R5/R1)", () => {
    expect(hasPermission("MANNING", "record_attendance")).toBe(false);
    expect(hasPermission("MANNING", "view_attendance")).toBe(false);
    expect(hasPermission("MANNING", "apply_leave")).toBe(false);
    expect(hasPermission("MANNING", "decide_leave")).toBe(false);
  });

  it("MPO sources recruitment but never gives final approvals", () => {
    expect(hasPermission("MANNING", "raise_requisition")).toBe(true);
    expect(hasPermission("MANNING", "manage_candidates")).toBe(true);
    expect(hasPermission("MANNING", "record_interview_result")).toBe(true);
    expect(hasPermission("MANNING", "verify_site_records")).toBe(true);
    // Approvals are Manager-only:
    expect(hasPermission("MANNING", "approve_salary_structure")).toBe(false);
    expect(hasPermission("MANNING", "select_candidate")).toBe(false);
    expect(hasPermission("MANNING", "approve_interview_waiver")).toBe(false);
  });

  it("Manager owns every crewing approval gate (R1/R2/R8)", () => {
    for (const p of [
      "decide_leave",
      "approve_interview_waiver",
      "approve_salary_structure",
      "select_candidate",
      "approve_appraisal",
      "approve_wage_report",
      "generate_wage_report",
    ] as const) {
      expect(hasPermission("MANAGER", p)).toBe(true);
    }
  });

  it("Accounts verifies bank/EPF and sees wages only (R11)", () => {
    expect(hasPermission("ACCOUNTS", "verify_bank_epf")).toBe(true);
    expect(hasPermission("ACCOUNTS", "view_wage_report")).toBe(true);
    expect(hasPermission("ACCOUNTS", "view_crew_records")).toBe(true);
    expect(hasPermission("ACCOUNTS", "verify_site_records")).toBe(false);
    expect(hasPermission("ACCOUNTS", "record_attendance")).toBe(false);
  });

  it("manage_crew is Manager + SuperUser + Admin (office crew management)", () => {
    expect(hasPermission("MANAGER", "manage_crew")).toBe(true);
    expect(hasPermission("SUPERUSER", "manage_crew")).toBe(true);
    expect(hasPermission("ADMIN", "manage_crew")).toBe(true);
    expect(hasPermission("SITE_STAFF", "manage_crew")).toBe(false);
    expect(hasPermission("MANNING", "manage_crew")).toBe(false);
    expect(hasPermission("ACCOUNTS", "manage_crew")).toBe(false);
  });

  it("manage_ranks is Manager + Admin only (not SuperUser)", () => {
    expect(hasPermission("MANAGER", "manage_ranks")).toBe(true);
    expect(hasPermission("ADMIN", "manage_ranks")).toBe(true);
    expect(hasPermission("SUPERUSER", "manage_ranks")).toBe(false);
    expect(hasPermission("MANNING", "manage_ranks")).toBe(false);
  });

  it("Auditor keeps read-only crewing visibility", () => {
    expect(hasPermission("AUDITOR", "view_requisitions")).toBe(true);
    expect(hasPermission("AUDITOR", "view_crew_records")).toBe(true);
    expect(hasPermission("AUDITOR", "view_wage_report")).toBe(true);
    expect(hasPermission("AUDITOR", "raise_requisition")).toBe(false);
  });
});

describe("CREWING_ENABLED flag", () => {
  afterEach(() => {
    vi.unstubAllEnvs();
    vi.resetModules();
  });

  it("defaults off when the env var is unset", async () => {
    vi.resetModules();
    vi.stubEnv("NEXT_PUBLIC_CREWING_ENABLED", "");
    const flags = await import("@/lib/feature-flags");
    expect(flags.CREWING_ENABLED).toBe(false);
  });

  it("is on only for the exact string \"true\"", async () => {
    vi.resetModules();
    vi.stubEnv("NEXT_PUBLIC_CREWING_ENABLED", "true");
    const flags = await import("@/lib/feature-flags");
    expect(flags.CREWING_ENABLED).toBe(true);
  });
});
