"use client";

import { useAuth } from "@/context/AuthContext";
import { useCallback, useMemo } from "react";

const DEFAULT_API_BASE =
  process.env.NEXT_PUBLIC_API_BASE_URL ?? "";

export function useApi(baseUrl: string = DEFAULT_API_BASE) {
  const { token } = useAuth();

  const apiFetch = useCallback(
    async <T = any>(path: string, options: RequestInit = {}): Promise<T> => {
      // Allow either full URLs or just `/api/...`
      const url = path.startsWith("http")
        ? path
        : `${baseUrl.replace(/\/$/, "")}${path}`;

      const headers: HeadersInit = {
        "Content-Type": "application/json",
        ...(options.headers || {}),
        ...(token ? { Authorization: `Bearer ${token}` } : {}),
      };

      const res = await fetch(url, {
        ...options,
        headers,
      });

      if (!res.ok) {
        let bodyText = "";
        try {
          bodyText = await res.text();
        } catch {
          // ignore
        }
        throw new Error(
          `API error ${res.status}: ${
            bodyText || res.statusText || "Unknown error"
          }`
        );
      }

      // handle 204 / empty body safely
      try {
        return (await res.json()) as T;
      } catch {
        return {} as T;
      }
    },
    [baseUrl, token] // 👈 only changes when baseUrl or token change
  );

  const get = useCallback(
    <T = any>(path: string) => apiFetch<T>(path, { method: "GET" }),
    [apiFetch]
  );

  const post = useCallback(
    <T = any>(path: string, body?: unknown) =>
      apiFetch<T>(path, {
        method: "POST",
        body: body !== undefined ? JSON.stringify(body) : undefined,
      }),
    [apiFetch]
  );

  const put = useCallback(
    <T = any>(path: string, body?: unknown) =>
      apiFetch<T>(path, {
        method: "PUT",
        body: body !== undefined ? JSON.stringify(body) : undefined,
      }),
    [apiFetch]
  );

  const del = useCallback(
    <T = any>(path: string) => apiFetch<T>(path, { method: "DELETE" }),
    [apiFetch]
  );

  // Optional: memoize the returned object so destructuring doesn't change refs
  return useMemo(
    () => ({ apiFetch, get, post, put, del }),
    [apiFetch, get, post, put, del]
  );
}