/**
 * Unit tests for GET /api/reports/allocations — A01 role-check enforcement.
 *
 * Heavy dependencies (Prisma, PDF renderer, XLSX builder) are mocked so the
 * test focuses purely on authentication and authorisation behaviour.
 */

import { describe, expect, it, vi } from "vitest";

// ─── auth mock ────────────────────────────────────────────────────────────────
const authMock = vi.hoisted(() => vi.fn());

vi.mock("~/server/auth.js", () => ({ auth: authMock }));

// ─── heavy dep stubs ─────────────────────────────────────────────────────────
vi.mock("@capakraken/db", () => ({
  prisma: {
    demandRequirement: { findMany: vi.fn().mockResolvedValue([]) },
    assignment: { findMany: vi.fn().mockResolvedValue([]) },
    user: { findMany: vi.fn().mockResolvedValue([]) },
  },
}));

vi.mock("@capakraken/application", () => ({
  buildSplitAllocationReadModel: vi.fn().mockReturnValue({ assignments: [] }),
}));

vi.mock("@capakraken/api", () => ({
  anonymizeResource: vi.fn((r: unknown) => r),
  getAnonymizationDirectory: vi.fn().mockResolvedValue({}),
}));

vi.mock("@react-pdf/renderer", () => ({
  renderToBuffer: vi.fn().mockResolvedValue(Buffer.from("PDF")),
}));

vi.mock("react", async (importOriginal) => {
  const actual = await importOriginal<typeof import("react")>();
  return { ...actual, createElement: vi.fn().mockReturnValue(null) };
});

vi.mock("~/lib/workbook-export.js", () => ({
  createWorkbookArrayBuffer: vi.fn().mockResolvedValue(new ArrayBuffer(8)),
}));

vi.mock("~/components/reports/AllocationReport.js", () => ({
  AllocationReport: () => null,
}));

// ─── import route after mocks ─────────────────────────────────────────────────
import { GET } from "./route.js";

function makeRequest(url = "http://localhost/api/reports/allocations") {
  return new Request(url);
}

// ─── tests ───────────────────────────────────────────────────────────────────

describe("GET /api/reports/allocations — authentication", () => {
  it("returns 401 when no session exists", async () => {
    authMock.mockResolvedValue(null);
    const res = await GET(makeRequest());
    expect(res.status).toBe(401);
  });

  it("returns 401 when session has no user", async () => {
    authMock.mockResolvedValue({ user: null });
    const res = await GET(makeRequest());
    expect(res.status).toBe(401);
  });
});

describe("GET /api/reports/allocations — authorisation (A01)", () => {
  it("returns 403 for USER role", async () => {
    authMock.mockResolvedValue({ user: { email: "user@example.com", role: "USER" } });
    const res = await GET(makeRequest());
    expect(res.status).toBe(403);
  });

  it("returns 403 for VIEWER role", async () => {
    authMock.mockResolvedValue({ user: { email: "viewer@example.com", role: "VIEWER" } });
    const res = await GET(makeRequest());
    expect(res.status).toBe(403);
  });

  it("returns 403 when role is absent from session", async () => {
    authMock.mockResolvedValue({ user: { email: "noRole@example.com" } });
    const res = await GET(makeRequest());
    expect(res.status).toBe(403);
  });

  it("returns 200 for ADMIN role (PDF)", async () => {
    authMock.mockResolvedValue({ user: { email: "admin@example.com", role: "ADMIN" } });
    const res = await GET(makeRequest());
    expect(res.status).toBe(200);
    expect(res.headers.get("Content-Type")).toContain("pdf");
  });

  it("returns 200 for MANAGER role (PDF)", async () => {
    authMock.mockResolvedValue({ user: { email: "mgr@example.com", role: "MANAGER" } });
    const res = await GET(makeRequest());
    expect(res.status).toBe(200);
  });

  it("returns 200 for CONTROLLER role (PDF)", async () => {
    authMock.mockResolvedValue({ user: { email: "ctrl@example.com", role: "CONTROLLER" } });
    const res = await GET(makeRequest());
    expect(res.status).toBe(200);
  });

  it("returns 200 for ADMIN role with xlsx format", async () => {
    authMock.mockResolvedValue({ user: { email: "admin@example.com", role: "ADMIN" } });
    const res = await GET(makeRequest("http://localhost/api/reports/allocations?format=xlsx"));
    expect(res.status).toBe(200);
    expect(res.headers.get("Content-Type")).toContain("spreadsheetml");
  });
});
