import { getOrCreateSessionId } from "@/lib/sessionId";

// При basePath=/trade-in (production behind gendsgn.ru/trade-in/*) API calls
// должны идти на `/trade-in/api/...`, чтобы Caddy `handle_path /trade-in/api/*`
// проксировал на tradein-backend — а не в main `handle /api/*` (gendesign).
// В dev (без basePath) — empty prefix, Next.js rewrites относительный путь.
const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH ?? "";
export const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL ?? BASE_PATH;

/**
 * Merges a global X-Session-Id header into the request init.
 * Only runs in browser (SSR guard). User-supplied headers win over the
 * auto-injected value so explicit overrides remain backward-compatible.
 */
function withSessionHeader(init?: RequestInit): RequestInit {
  const base: RequestInit = init ?? {};
  if (typeof window === "undefined") return base;
  const sessionId = getOrCreateSessionId();
  if (!sessionId) return base;
  return {
    ...base,
    headers: {
      "X-Session-Id": sessionId,
      ...(base.headers ?? {}),
    },
  };
}

/**
 * Status-aware variant of apiFetch — возвращает status + body для случаев
 * когда логика зависит от HTTP кода (например 202 Accepted для async jobs).
 *
 * Throws на 4xx/5xx (используя HTTPError ниже); 2xx коды все ОК.
 */
export class HTTPError extends Error {
  status: number;
  body: unknown;
  constructor(status: number, body: unknown, msg?: string) {
    super(msg ?? `API error ${status}`);
    this.status = status;
    this.body = body;
  }
}

export async function apiFetchWithStatus<T>(
  path: string,
  init?: RequestInit,
): Promise<{ status: number; body: T }> {
  const merged = withSessionHeader(init);
  const response = await fetch(`${API_BASE_URL}${path}`, {
    ...merged,
    headers: {
      "Content-Type": "application/json",
      ...(merged.headers ?? {}),
    },
  });
  let body: unknown = null;
  // 204 No Content имеет пустое тело; для всех остальных читаем как text один раз
  // (fetch body stream consumable только один раз — нельзя сначала .json() потом .text()).
  if (response.status !== 204) {
    const rawText = await response.text();
    if (rawText) {
      try {
        body = JSON.parse(rawText);
      } catch {
        // Не JSON (HTML error page от Caddy / 502 / etc) — оборачиваем в detail
        body = { detail: rawText };
      }
    }
  }
  if (!response.ok) {
    const detail =
      (body as { detail?: string })?.detail ?? `API error ${response.status}`;
    throw new HTTPError(response.status, body, detail);
  }
  return { status: response.status, body: body as T };
}

export async function apiFetch<T>(
  path: string,
  init?: RequestInit,
): Promise<T> {
  const { body } = await apiFetchWithStatus<T>(path, init);
  return body;
}
