import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
import { ApiError } from "../../api/client";
import { handleFetchError, createStringErrorAdapter, setAuthErrorHandler } from "../fetchError";

describe("utils/fetchError", () => {
  beforeEach(() => {
    // Clear handler before each test
    setAuthErrorHandler(null);
  });

  afterEach(() => {
    // Clean up after each test
    setAuthErrorHandler(null);
  });

  it("ignores AbortError errors", () => {
    const setError = vi.fn();
    handleFetchError(new DOMException("Aborted", "AbortError"), setError, "fallback");
    expect(setError).not.toHaveBeenCalled();
  });

  it("calls registered auth error handler on 401", () => {
    const authHandler = vi.fn();
    setAuthErrorHandler(authHandler);
    const setError = vi.fn();
    handleFetchError(new ApiError(401, "Unauthorized"), setError, "fallback");
    expect(authHandler).toHaveBeenCalledOnce();
    expect(setError).not.toHaveBeenCalled();
  });

  it("calls registered auth error handler on 403", () => {
    const authHandler = vi.fn();
    setAuthErrorHandler(authHandler);
    const setError = vi.fn();
    handleFetchError(new ApiError(403, "Forbidden"), setError, "fallback");
    expect(authHandler).toHaveBeenCalledOnce();
    expect(setError).not.toHaveBeenCalled();
  });

  it("logs warning when auth error occurs without registered handler", () => {
    const consoleWarnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
    const setError = vi.fn();
    handleFetchError(new ApiError(401, "Unauthorized"), setError, "fallback");
    expect(consoleWarnSpy).toHaveBeenCalledOnce();
    const firstCall = consoleWarnSpy.mock.calls[0];
    expect(firstCall).toBeDefined();
    expect(String(firstCall?.[0])).toContain("Auth error (401) without registered handler");
    expect(setError).not.toHaveBeenCalled();
    consoleWarnSpy.mockRestore();
  });

  it("sets fallback for normal errors", () => {
    const setError = vi.fn();
    handleFetchError(new Error("Oops"), createStringErrorAdapter(setError), "fallback");
    expect(setError).toHaveBeenCalledWith("Oops");
  });
});
