import { useState, useEffect, useCallback } from "react";

// Set by lib/session.tsx once a token is available; read synchronously here so
// callers never have to await SecureStore before every request.
let authToken: string | null = null;

export const setAuthToken = (token: string) => {
  authToken = token;
};

export const clearAuthToken = () => {
  authToken = null;
};

/** Carries the HTTP status so callers can branch on it instead of on text. */
export class ApiError extends Error {
  status: number;

  constructor(status: number, message: string) {
    super(message);
    this.name = "ApiError";
    this.status = status;
  }
}

export const fetchAPI = async (url: string, options?: RequestInit) => {
  try {
    const headers = new Headers(options?.headers);
    if (authToken && !headers.has("Authorization")) {
      headers.set("Authorization", `Bearer ${authToken}`);
    }

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

    if (!response.ok) {
      // Every route answers with `{ error }`; keep that text so the UI can show
      // what actually went wrong instead of guessing from a status code.
      const body = await response.json().catch(() => null);

      throw new ApiError(
        response.status,
        body?.error ?? `Request failed with status ${response.status}.`,
      );
    }

    return await response.json();
  } catch (error) {
    console.error(`Fetch error: ${url}`, error);
    throw error;
  }
};

export const useFetch = <T>(url: string, options?: RequestInit) => {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const fetchData = useCallback(async () => {
    setLoading(true);
    setError(null);

    try {
      const result = await fetchAPI(url, options);
      setData(result.data);
    } catch (err) {
      setError((err as Error).message);
    } finally {
      setLoading(false);
    }
  }, [url, options]);

  useEffect(() => {
    fetchData();
  }, [fetchData]);

  return { data, loading, error, refetch: fetchData };
};
