import { SystemRole } from "@capakraken/shared";
import { describe, expect, it, vi } from "vitest";
import { createCallerFactory } from "../trpc.js";
import { holidayCalendarRouter } from "../router/holiday-calendar.js";

vi.mock("../lib/audit.js", () => ({
  createAuditEntry: vi.fn().mockResolvedValue(undefined),
}));

const createCaller = createCallerFactory(holidayCalendarRouter);

function createContext(
  db: Record<string, unknown>,
  options: {
    role?: SystemRole;
    session?: boolean;
  } = {},
) {
  const { role = SystemRole.USER, session = true } = options;

  return {
    session: session
      ? {
          user: { email: "user@example.com", name: "User", image: null },
          expires: "2099-01-01T00:00:00.000Z",
        }
      : null,
    db: db as never,
    dbUser: session
      ? {
          id: role === SystemRole.ADMIN ? "user_admin" : role === SystemRole.MANAGER ? "user_mgr" : "user_1",
          systemRole: role,
          permissionOverrides: null,
        }
      : null,
  };
}

function resolveInput(resourceId: string) {
  return {
    resourceId,
    periodStart: new Date("2026-01-01T00:00:00.000Z"),
    periodEnd: new Date("2026-12-31T00:00:00.000Z"),
  };
}

describe("holiday calendar router authorization", () => {
  it("requires authentication for resource holiday resolution", async () => {
    const resourceFindFirst = vi.fn();
    const resourceFindUnique = vi.fn();
    const caller = createCaller(createContext({
      resource: {
        findFirst: resourceFindFirst,
        findUnique: resourceFindUnique,
      },
      holidayCalendar: {
        findMany: vi.fn(),
      },
    }, { session: false }));

    await expect(caller.resolveResourceHolidays(resolveInput("res_1"))).rejects.toMatchObject({
      code: "UNAUTHORIZED",
      message: "Authentication required",
    });

    expect(resourceFindFirst).not.toHaveBeenCalled();
    expect(resourceFindUnique).not.toHaveBeenCalled();
  });

  it("forbids regular users from resolving another resource's holidays", async () => {
    const resourceFindUnique = vi.fn();
    const holidayCalendarFindMany = vi.fn();
    const caller = createCaller(createContext({
      resource: {
        findFirst: vi.fn().mockResolvedValue({ id: "res_own" }),
        findUnique: resourceFindUnique,
      },
      holidayCalendar: {
        findMany: holidayCalendarFindMany,
      },
    }));

    await expect(caller.resolveResourceHolidays(resolveInput("res_other"))).rejects.toMatchObject({
      code: "FORBIDDEN",
      message: "You can only view holiday data for your own resource",
    });

    expect(resourceFindUnique).not.toHaveBeenCalled();
    expect(holidayCalendarFindMany).not.toHaveBeenCalled();
  });

  it("allows regular users to resolve holidays for their own resource", async () => {
    const resourceFindUnique = vi.fn().mockResolvedValue({
      id: "res_own",
      eid: "EMP-001",
      displayName: "Alice Example",
      federalState: "BY",
      countryId: "country_de",
      metroCityId: null,
      country: { code: "DE", name: "Deutschland" },
      metroCity: null,
    });
    const caller = createCaller(createContext({
      resource: {
        findFirst: vi.fn().mockResolvedValue({ id: "res_own" }),
        findUnique: resourceFindUnique,
      },
      holidayCalendar: {
        findMany: vi.fn().mockResolvedValue([]),
      },
    }));

    const result = await caller.resolveResourceHolidays(resolveInput("res_own"));

    expect(result.resource).toEqual({
      id: "res_own",
      eid: "EMP-001",
      name: "Alice Example",
      country: "Deutschland",
      countryCode: "DE",
      federalState: "BY",
      metroCity: null,
    });
    expect(resourceFindUnique).toHaveBeenCalledWith({
      where: { id: "res_own" },
      select: {
        id: true,
        eid: true,
        displayName: true,
        federalState: true,
        countryId: true,
        metroCityId: true,
        country: { select: { code: true, name: true } },
        metroCity: { select: { name: true } },
      },
    });
  });

  it("allows managers to resolve holidays for other resources", async () => {
    const resourceFindFirst = vi.fn();
    const resourceFindUnique = vi.fn().mockResolvedValue({
      id: "res_other",
      eid: "EMP-002",
      displayName: "Bob Example",
      federalState: "BY",
      countryId: "country_de",
      metroCityId: null,
      country: { code: "DE", name: "Deutschland" },
      metroCity: null,
    });
    const caller = createCaller(createContext({
      resource: {
        findFirst: resourceFindFirst,
        findUnique: resourceFindUnique,
      },
      holidayCalendar: {
        findMany: vi.fn().mockResolvedValue([]),
      },
    }, { role: SystemRole.MANAGER }));

    const result = await caller.resolveResourceHolidays(resolveInput("res_other"));

    expect(result.resource.id).toBe("res_other");
    expect(resourceFindFirst).not.toHaveBeenCalled();
    expect(resourceFindUnique).toHaveBeenCalledWith({
      where: { id: "res_other" },
      select: {
        id: true,
        eid: true,
        displayName: true,
        federalState: true,
        countryId: true,
        metroCityId: true,
        country: { select: { code: true, name: true } },
        metroCity: { select: { name: true } },
      },
    });
  });
});
