"use client";

import { withBase } from "@/lib/basePath";

/** Thrown on a non-2xx API response; carries validation errors when present. */
export class ApiError extends Error {
  status: number;
  errors: string[];
  constructor(message: string, status: number, errors: string[] = []) {
    super(message);
    this.status = status;
    this.errors = errors;
  }
}

/** Client fetch through the same-origin proxy (token injected server-side). */
export async function api<T = any>(path: string, init?: RequestInit): Promise<T> {
  const res = await fetch(withBase(`/api/backend/${path}`), {
    ...init,
    headers: { "content-type": "application/json", ...(init?.headers || {}) },
    cache: "no-store",
  });
  const text = await res.text();
  let data: any = {};
  if (text) {
    try {
      data = JSON.parse(text);
    } catch {
      // Non-JSON body (e.g. an HTML 404/500 page). Surface a clean error instead of
      // letting JSON.parse throw a cryptic "Unexpected token '<'".
      throw new ApiError(
        res.ok ? `Unexpected non-JSON response from /${path}` : `Request to /${path} failed (${res.status} ${res.statusText})`,
        res.status,
      );
    }
  }
  if (!res.ok) {
    const errors = Array.isArray(data?.errors) ? data.errors : [];
    throw new ApiError(data?.error || errors.join(", ") || res.statusText, res.status, errors);
  }
  return data as T;
}

export const get = <T = any>(path: string) => api<T>(path);
export const put = <T = any>(path: string, body: unknown) =>
  api<T>(path, { method: "PUT", body: JSON.stringify(body) });
export const post = <T = any>(path: string, body?: unknown) =>
  api<T>(path, { method: "POST", body: body === undefined ? undefined : JSON.stringify(body) });
export const del = <T = any>(path: string) => api<T>(path, { method: "DELETE" });
