/**
 * API client — typed fetch wrapper + TanStack Query setup.
 *
 * All requests hit relative URLs (e.g. `/api/cases`) which next.config.ts
 * rewrites transparently proxy to legal-ai.nautilus.marcusgroup.org. No CORS
 * gymnastics, no direct public-URL references in component code.
 */

import { QueryClient } from "@tanstack/react-query";

export class ApiError extends Error {
  constructor(
    message: string,
    public readonly status: number,
    public readonly body: unknown,
  ) {
    super(message);
    this.name = "ApiError";
  }
}

type RequestOptions = {
  method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
  body?: unknown;
  signal?: AbortSignal;
};

/**
 * Typed JSON request. Throws ApiError on non-2xx responses with the parsed body.
 * Always returns parsed JSON — callers pass the expected type parameter.
 */
export async function apiRequest<T>(
  path: string,
  { method = "GET", body, signal }: RequestOptions = {},
): Promise<T> {
  const res = await fetch(path, {
    method,
    headers: body ? { "Content-Type": "application/json" } : undefined,
    body: body ? JSON.stringify(body) : undefined,
    signal,
  });

  const contentType = res.headers.get("content-type") ?? "";
  const parsed = contentType.includes("application/json")
    ? await res.json().catch(() => null)
    : await res.text().catch(() => null);

  if (!res.ok) {
    throw new ApiError(
      `${method} ${path} failed with ${res.status}`,
      res.status,
      parsed,
    );
  }

  return parsed as T;
}

/**
 * Shared TanStack Query client. Defaults are tuned for a dashboard that polls
 * for case progress — stale for 5 seconds, 1 automatic retry, no background
 * refetch on window focus (preserves editor state during long sessions).
 */
export function makeQueryClient(): QueryClient {
  return new QueryClient({
    defaultOptions: {
      queries: {
        staleTime: 5_000,
        retry: 1,
        refetchOnWindowFocus: false,
      },
      mutations: {
        retry: 0,
      },
    },
  });
}
