// @vitest-environment happy-dom
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";

describe("auth/api fetch wrapper", () => {
  let originalFetch: typeof globalThis.fetch;
  let originalLocation: Location;

  beforeEach(() => {
    originalFetch = globalThis.fetch;
    originalLocation = window.location;
    delete (window as any).__navCalls;
    (window as any).__navCalls = [];
  });
  afterEach(() => {
    globalThis.fetch = originalFetch;
    window.location = originalLocation as any;
  });

  it("redirects to /login on 401 response", async () => {
    globalThis.fetch = vi.fn().mockResolvedValue({
      ok: false,
      status: 401,
      statusText: "Unauthorized",
      headers: new Headers(),
      json: async () => ({ error: "session_expired" }),
    } as unknown as Response) as unknown as typeof globalThis.fetch;

    // Stub window.location.href setter to capture navigation without
    // actually navigating (jsdom does not implement location.href assignment).
    let href = originalLocation.href;
    Object.defineProperty(window, "location", {
      configurable: true,
      get: () => ({
        ...originalLocation,
        get href() {
          return href;
        },
        set href(v: string) {
          (window as any).__navCalls.push(v);
          href = v;
        },
      }),
    });

    const { authedFetch } = await import("./api");
    await expect(authedFetch("/api/anything")).rejects.toThrow();
    expect((window as any).__navCalls).toContainEqual(expect.stringContaining("/login"));
  });

  it("does NOT redirect on 403", async () => {
    globalThis.fetch = vi.fn().mockResolvedValue({
      ok: false,
      status: 403,
      statusText: "Forbidden",
      headers: new Headers(),
      json: async () => ({ error: "forbidden" }),
    } as unknown as Response) as unknown as typeof globalThis.fetch;
    Object.defineProperty(window, "location", {
      configurable: true,
      get: () => ({
        ...originalLocation,
        set href(_: string) {
          throw new Error("should not nav");
        },
      }),
    });

    const { authedFetch } = await import("./api");
    await expect(authedFetch("/api/anything")).rejects.toThrow();
  });

  it("returns parsed JSON on 200", async () => {
    globalThis.fetch = vi.fn().mockResolvedValue({
      ok: true,
      status: 200,
      headers: new Headers(),
      json: async () => ({ hello: "world" }),
    } as unknown as Response) as unknown as typeof globalThis.fetch;
    const { authedFetch } = await import("./api");
    const data = await authedFetch("/api/anything");
    expect(data).toEqual({ hello: "world" });
  });
});
