"use client";

import { useCallback, useRef, useState } from "react";
import type { PagedResult } from "@/types/zxdb";

/**
 * Manages API search fetching with automatic request cancellation
 * to prevent race conditions from rapid filter/page changes.
 * Keeps previous results visible while a new request is in flight.
 *
 * @param onExtra - optional callback to capture extra fields from the response
 *   (e.g., facets) that sit alongside the standard paged fields.
 */
export default function useSearchFetch<T>(
  endpoint: string,
  initialData: PagedResult<T> | null = null,
  onExtra?: (json: Record<string, unknown>) => void,
) {
  const [data, setData] = useState<PagedResult<T> | null>(initialData);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const abortRef = useRef<AbortController | null>(null);
  const fetchIdRef = useRef(0);
  const onExtraRef = useRef(onExtra);
  onExtraRef.current = onExtra;

  const fetch_ = useCallback(
    async (params: URLSearchParams) => {
      // Cancel any in-flight request
      abortRef.current?.abort();
      const controller = new AbortController();
      abortRef.current = controller;

      const id = ++fetchIdRef.current;
      setLoading(true);
      setError(null);

      try {
        const res = await globalThis.fetch(
          `${endpoint}?${params.toString()}`,
          { signal: controller.signal },
        );
        if (!res.ok) throw new Error(`Search failed (${res.status})`);
        const json = await res.json();

        // Only apply if this is still the latest request
        if (id === fetchIdRef.current) {
          setData({
            items: json.items,
            page: json.page,
            pageSize: json.pageSize,
            total: json.total,
          });
          onExtraRef.current?.(json);
        }
      } catch (e: unknown) {
        if (e instanceof DOMException && e.name === "AbortError") return;
        if (id === fetchIdRef.current) {
          const msg = e instanceof Error ? e.message : "Search failed";
          console.error(msg);
          setError(msg);
          setData({ items: [] as T[], page: 1, pageSize: 20, total: 0 });
        }
      } finally {
        if (id === fetchIdRef.current) {
          setLoading(false);
        }
      }
    },
    [endpoint],
  );

  // Allow syncing SSR data without a fetch
  const syncData = useCallback((d: PagedResult<T>) => {
    abortRef.current?.abort();
    setData(d);
    setLoading(false);
    setError(null);
  }, []);

  return { data, loading, error, fetch: fetch_, syncData };
}
