'use client';

import React, { useState, useEffect, useRef, useCallback } from 'react';
import SearchableSelect, { Option } from '@/components/SearchableSelect';
import {
  fetchCountriesAsync,
  fetchStatesAsync,
  fetchCitiesAsync,
  LocationOption,
} from '@/lib/locationCache';

export interface LocationAsyncSelectProps {
  locationType: 'country' | 'state' | 'city';
  countryId?: number | string | null;
  stateId?: number | string | null;
  allowAny?: boolean;
  isCreatable?: boolean;
  value?: any;
  onChange?: (val: any, rawOption?: LocationOption | LocationOption[] | null) => void;
  disabled?: boolean;
  placeholder?: string;
  isMulti?: boolean;
  isClearable?: boolean;
  minSearchLength?: number;
  debounceMs?: number;
  className?: string;
  controlBgClass?: string;
}

export default function LocationAsyncSelect({
  locationType,
  countryId,
  stateId,
  allowAny = false,
  isCreatable = false,
  value,
  onChange,
  disabled = false,
  placeholder,
  isMulti = false,
  isClearable = true,
  minSearchLength = 2,
  debounceMs = 400,
  className = '',
  controlBgClass,
}: LocationAsyncSelectProps) {
  const [options, setOptions] = useState<LocationOption[]>([]);
  const [loading, setLoading] = useState(false);
  const [searchQuery, setSearchQuery] = useState('');
  const activeSearchQuery = useRef('');
  const debounceTimer = useRef<NodeJS.Timeout | null>(null);

  // Compute default placeholder based on type
  const defaultPlaceholder =
    placeholder ||
    (locationType === 'country'
      ? 'Search Country...'
      : locationType === 'state'
      ? countryId
        ? 'Search State...'
        : 'Select Country first'
      : allowAny || stateId || countryId
      ? 'Search City...'
      : 'Select State first');

  // Check if disabled due to missing parent
  const isDisabled =
    disabled ||
    (locationType === 'state' && !countryId) ||
    (locationType === 'city' && !allowAny && !stateId && !countryId);

  // Fetch location data based on type
  const performFetch = useCallback(
    async (query: string) => {
      if (isDisabled) {
        setOptions([]);
        setLoading(false);
        return;
      }

      setLoading(true);
      try {
        let results: LocationOption[] = [];
        if (locationType === 'country') {
          results = await fetchCountriesAsync(query, 50);
        } else if (locationType === 'state') {
          results = await fetchStatesAsync(countryId, query, 50);
        } else if (locationType === 'city') {
          results = await fetchCitiesAsync(
            allowAny ? null : stateId,
            allowAny ? null : countryId,
            query,
            50,
            allowAny
          );
        }

        // Ensure current selected value is present in options list so it renders correctly
        if (value) {
          const valsToKeep = Array.isArray(value) ? value : [value];
          for (const v of valsToKeep) {
            const rawVal = v && typeof v === 'object' && 'value' in v ? v.value : v;
            const rawLbl = v && typeof v === 'object' && 'label' in v ? v.label : String(v);
            if (rawVal && !results.some((o) => o.value === rawVal || o.label === rawLbl)) {
              results.unshift({ value: rawVal, label: rawLbl });
            }
          }
        }

        setOptions(results);
      } catch (err) {
        console.error(`Error loading ${locationType} options:`, err);
        setOptions([]);
      } finally {
        setLoading(false);
      }
    },
    [locationType, countryId, stateId, allowAny, isDisabled, value]
  );

  // Trigger search with debounce
  const handleSearchChange = (query: string) => {
    setSearchQuery(query);
    activeSearchQuery.current = query;

    if (debounceTimer.current) {
      clearTimeout(debounceTimer.current);
    }

    if (query.trim().length > 0 && query.trim().length < minSearchLength) {
      return;
    }

    debounceTimer.current = setTimeout(() => {
      performFetch(query);
    }, debounceMs);
  };

  // Run initial fetch
  useEffect(() => {
    performFetch('');
    return () => {
      if (debounceTimer.current) clearTimeout(debounceTimer.current);
    };
  }, [performFetch]);

  // Handle value change
  const handleChange = (selectedVal: any) => {
    let rawOption: LocationOption | LocationOption[] | null = null;

    if (Array.isArray(selectedVal)) {
      rawOption = selectedVal
        .map((sv) => {
          const valStr = typeof sv === 'object' ? sv?.value : sv;
          return (
            options.find(
              (o) =>
                o.value === valStr ||
                o.label === valStr ||
                String(o.value) === String(valStr) ||
                o.name === valStr
            ) || (isCreatable ? { value: valStr, label: String(valStr) } : null)
          );
        })
        .filter(Boolean) as LocationOption[];
    } else if (selectedVal !== null && selectedVal !== undefined) {
      const valStr = typeof selectedVal === 'object' ? selectedVal?.value : selectedVal;
      rawOption =
        options.find(
          (o) =>
            o.value === valStr ||
            o.label === valStr ||
            String(o.value) === String(valStr) ||
            o.name === valStr ||
            (o.id && String(o.id) === String(valStr))
        ) || (isCreatable ? { value: valStr, label: String(valStr) } : null);
    }

    if (onChange) {
      onChange(selectedVal, rawOption);
    }
  };

  const getNoOptionsMessage = () => {
    if (isDisabled) {
      return locationType === 'state' ? 'Select Country first' : 'Select State first';
    }
    if (searchQuery.trim().length > 0 && searchQuery.trim().length < minSearchLength) {
      return `Type at least ${minSearchLength} characters to search...`;
    }
    return `No ${locationType}s found`;
  };

  return (
    <SearchableSelect
      options={options}
      value={value}
      onChange={handleChange}
      onSearchChange={handleSearchChange}
      loading={loading}
      disabled={isDisabled}
      placeholder={defaultPlaceholder}
      isMulti={isMulti}
      isClearable={isClearable}
      isCreatable={isCreatable}
      noOptionsMessage={getNoOptionsMessage()}
      className={className}
      controlBgClass={controlBgClass}
    />
  );
}
