import { useCallback, useEffect, useRef, useState } from 'react';
import type { BaseSelectProps } from './BaseSelect';
import { BaseSelect } from './BaseSelect';
import type { SelectOption } from './types';

export type AsyncSelectProps<TValue = string> = {
  loadOptions: (query: string) => Promise<SelectOption<TValue>[]>;
  defaultOptions?: SelectOption<TValue>[];
  debounceMs?: number;
} & Omit<BaseSelectProps<TValue>, 'options' | 'isLoading'>;

export function AsyncSelect<TValue = string>({
  loadOptions,
  defaultOptions = [],
  debounceMs = 250,
  ...rest
}: AsyncSelectProps<TValue>) {
  const [options, setOptions] = useState<SelectOption<TValue>[]>(defaultOptions);
  const [isLoading, setIsLoading] = useState(false);
  const reqId = useRef(0);
  const timer = useRef<number | null>(null);

  const onQueryChange = useCallback(
    (q: string) => {
      if (timer.current != null) window.clearTimeout(timer.current);
      timer.current = window.setTimeout(async () => {
        const my = ++reqId.current;
        setIsLoading(true);
        try {
          const next = await loadOptions(q);
          if (reqId.current !== my) return;
          setOptions(next);
        } finally {
          if (reqId.current === my) setIsLoading(false);
        }
      }, debounceMs);
    },
    [debounceMs, loadOptions]
  );

  useEffect(() => {
    return () => {
      if (timer.current != null) window.clearTimeout(timer.current);
    };
  }, []);

  return <BaseSelect<TValue> {...rest} options={options} isLoading={isLoading} onQueryChange={onQueryChange} />;
}

