import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
import { renderHook } from "@testing-library/react";

// ---------------------------------------------------------------------------
// Mock next-auth/react so the hook can run without a real auth provider.
// ---------------------------------------------------------------------------
const mockUseSession = vi.fn();

vi.mock("next-auth/react", () => ({
  useSession: () => mockUseSession(),
}));

const { usePermissions } = await import("./usePermissions.js");

// ---------------------------------------------------------------------------
// Helper: build a mock session object with the given role.
// ---------------------------------------------------------------------------
function sessionWith(role: string) {
  return { data: { user: { role } } };
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
describe("usePermissions", () => {
  beforeEach(() => {
    mockUseSession.mockReset();
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  // -------------------------------------------------------------------------
  // No session / unauthenticated
  // -------------------------------------------------------------------------
  describe("when there is no session", () => {
    it("falls back to role USER when data is null", () => {
      mockUseSession.mockReturnValue({ data: null });
      const { result } = renderHook(() => usePermissions());
      expect(result.current.role).toBe("USER");
    });

    it("falls back to role USER when data is undefined", () => {
      mockUseSession.mockReturnValue({ data: undefined });
      const { result } = renderHook(() => usePermissions());
      expect(result.current.role).toBe("USER");
    });

    it("falls back to role USER when user has no role property", () => {
      mockUseSession.mockReturnValue({ data: { user: {} } });
      const { result } = renderHook(() => usePermissions());
      expect(result.current.role).toBe("USER");
    });

    it("denies all privileged permissions for anonymous user", () => {
      mockUseSession.mockReturnValue({ data: null });
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canViewCosts).toBe(false);
      expect(result.current.canEdit).toBe(false);
      expect(result.current.canManageUsers).toBe(false);
      expect(result.current.canManageBlueprints).toBe(false);
      expect(result.current.canViewScores).toBe(false);
    });
  });

  // -------------------------------------------------------------------------
  // ADMIN role
  // -------------------------------------------------------------------------
  describe("ADMIN role", () => {
    beforeEach(() => {
      mockUseSession.mockReturnValue(sessionWith("ADMIN"));
    });

    it("exposes role as ADMIN", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.role).toBe("ADMIN");
    });

    it("canViewCosts is true", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canViewCosts).toBe(true);
    });

    it("canEdit is true", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canEdit).toBe(true);
    });

    it("canManageUsers is true", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canManageUsers).toBe(true);
    });

    it("canManageBlueprints is true", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canManageBlueprints).toBe(true);
    });

    it("canViewScores is true", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canViewScores).toBe(true);
    });
  });

  // -------------------------------------------------------------------------
  // MANAGER role
  // -------------------------------------------------------------------------
  describe("MANAGER role", () => {
    beforeEach(() => {
      mockUseSession.mockReturnValue(sessionWith("MANAGER"));
    });

    it("exposes role as MANAGER", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.role).toBe("MANAGER");
    });

    it("canViewCosts is true", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canViewCosts).toBe(true);
    });

    it("canEdit is true", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canEdit).toBe(true);
    });

    it("canManageUsers is false", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canManageUsers).toBe(false);
    });

    it("canManageBlueprints is false", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canManageBlueprints).toBe(false);
    });

    it("canViewScores is true", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canViewScores).toBe(true);
    });
  });

  // -------------------------------------------------------------------------
  // CONTROLLER role
  // -------------------------------------------------------------------------
  describe("CONTROLLER role", () => {
    beforeEach(() => {
      mockUseSession.mockReturnValue(sessionWith("CONTROLLER"));
    });

    it("exposes role as CONTROLLER", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.role).toBe("CONTROLLER");
    });

    it("canViewCosts is true", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canViewCosts).toBe(true);
    });

    it("canEdit is false (CONTROLLER is not in EDIT_ROLES)", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canEdit).toBe(false);
    });

    it("canManageUsers is false", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canManageUsers).toBe(false);
    });

    it("canManageBlueprints is false", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canManageBlueprints).toBe(false);
    });

    it("canViewScores is false (CONTROLLER is not in SCORE_ROLES)", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canViewScores).toBe(false);
    });
  });

  // -------------------------------------------------------------------------
  // USER role (default / authenticated but unprivileged)
  // -------------------------------------------------------------------------
  describe("USER role", () => {
    beforeEach(() => {
      mockUseSession.mockReturnValue(sessionWith("USER"));
    });

    it("exposes role as USER", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.role).toBe("USER");
    });

    it("canViewCosts is false", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canViewCosts).toBe(false);
    });

    it("canEdit is false", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canEdit).toBe(false);
    });

    it("canManageUsers is false", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canManageUsers).toBe(false);
    });

    it("canManageBlueprints is false", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canManageBlueprints).toBe(false);
    });

    it("canViewScores is false", () => {
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canViewScores).toBe(false);
    });
  });

  // -------------------------------------------------------------------------
  // Unknown / arbitrary role
  // -------------------------------------------------------------------------
  describe("unknown role", () => {
    it("denies all privileged permissions for an unknown role string", () => {
      mockUseSession.mockReturnValue(sessionWith("SUPER_DUPER_ADMIN"));
      const { result } = renderHook(() => usePermissions());
      expect(result.current.canViewCosts).toBe(false);
      expect(result.current.canEdit).toBe(false);
      expect(result.current.canManageUsers).toBe(false);
      expect(result.current.canManageBlueprints).toBe(false);
      expect(result.current.canViewScores).toBe(false);
    });

    it("still surfaces the raw role string for arbitrary roles", () => {
      mockUseSession.mockReturnValue(sessionWith("VIEWER"));
      const { result } = renderHook(() => usePermissions());
      expect(result.current.role).toBe("VIEWER");
    });
  });
});
