import { describe, expect, it, beforeEach, vi } from "vitest";
import { ApiError, get, isAuthError, SESSION_EXPIRED_EVENT } from "../client";

describe("api/client", () => {
  beforeEach(() => {
    vi.restoreAllMocks();
  });

  it("dispatches session-expired for 401 responses", async () => {
    const dispatchSpy = vi.spyOn(window, "dispatchEvent");

    global.fetch = vi.fn().mockResolvedValue({
      ok: false,
      status: 401,
      text: vi.fn().mockResolvedValue("Unauthorized"),
    });

    await expect(get("/test")).rejects.toBeInstanceOf(ApiError);
    expect(dispatchSpy).toHaveBeenCalledTimes(1);
    const call = dispatchSpy.mock.calls[0];
    expect(call).toBeDefined();
    const event = call?.[0] as Event;
    expect(event.type).toBe(SESSION_EXPIRED_EVENT);
  });

  it("dispatches session-expired for 403 responses", async () => {
    const dispatchSpy = vi.spyOn(window, "dispatchEvent");

    global.fetch = vi.fn().mockResolvedValue({
      ok: false,
      status: 403,
      text: vi.fn().mockResolvedValue("Forbidden"),
    });

    await expect(get("/test")).rejects.toBeInstanceOf(ApiError);
    expect(dispatchSpy).toHaveBeenCalledTimes(1);
    const call = dispatchSpy.mock.calls[0];
    expect(call).toBeDefined();
    const event = call?.[0] as Event;
    expect(event.type).toBe(SESSION_EXPIRED_EVENT);
  });

  it("does not treat non-auth errors as auth errors", () => {
    const error = new ApiError(500, "Server error");
    expect(isAuthError(error)).toBe(false);
  });

  it("recognizes 401 and 403 ApiError as auth errors", () => {
    expect(isAuthError(new ApiError(401, "Unauthorized"))).toBe(true);
    expect(isAuthError(new ApiError(403, "Forbidden"))).toBe(true);
  });
});
