"use client";

import useDebounce from "@/hooks/useDebounce";
import type { ILabelValue } from "@/types/shared";
import { keepPreviousData, useQuery } from "@tanstack/react-query";
import { useMemo } from "react";

export type SelectSearchMode = "client" | "server";

export type UseSelectServerSearchArgs = {
  /** When `"server"`, options are loaded via `searchFn` + React Query. */
  searchMode: SelectSearchMode;
  searchable: boolean;
  /** Whether the dropdown panel is open (queries run only while open). */
  open: boolean;
  /** Live search input (debounced before the request). */
  query: string;
  debounceMs?: number;
  /** Base React Query key; debounced search term is appended. */
  searchQueryKey?: readonly unknown[];
  searchFn?: (query: string) => Promise<ILabelValue[]>;
  /** Fallback / initial options (e.g. first page or selected value). */
  items: readonly ILabelValue[];
  /** Current selected value — kept visible if missing from server results. */
  selectedValue?: string;
};

export function useSelectServerSearch({
  searchMode,
  searchable,
  open,
  query,
  debounceMs = 300,
  searchQueryKey,
  searchFn,
  items,
  selectedValue,
}: UseSelectServerSearchArgs) {
  const isServerMode = searchable && searchMode === "server" && !!searchFn;

  const debouncedQuery = useDebounce(query, debounceMs);

  const queryKey = useMemo(
    () => [...(searchQueryKey ?? ["select-search"]), debouncedQuery],
    [searchQueryKey, debouncedQuery],
  );

  const {
    data: serverItems,
    isFetching,
    isPending,
    isError,
    error,
  } = useQuery({
    queryKey,
    queryFn: () => searchFn!(debouncedQuery),
    enabled: isServerMode && open,
    placeholderData: keepPreviousData,
    staleTime: 30_000,
  });

  const displayItems = useMemo(() => {
    if (!isServerMode) return null;

    const list = serverItems ?? (debouncedQuery.trim() ? [] : [...items]);

    if (!selectedValue) return list;

    const hasSelected = list.some(
      (i) => String(i.value) === String(selectedValue),
    );
    if (hasSelected) return list;

    const fromItems = items.find(
      (i) => String(i.value) === String(selectedValue),
    );
    if (fromItems) return [fromItems, ...list];

    return [{ value: selectedValue, label: String(selectedValue) }, ...list];
  }, [
    isServerMode,
    serverItems,
    debouncedQuery,
    items,
    selectedValue,
  ]);

  const isSearchDebouncing =
    isServerMode && open && query.trim() !== debouncedQuery.trim();

  return {
    isServerMode,
    displayItems,
    isSearchLoading:
      isServerMode &&
      open &&
      (isSearchDebouncing || isFetching || isPending),
    isSearchDebouncing,
    isSearchError: isServerMode && open && isError,
    searchError: error,
  };
}
