import React, { useMemo } from 'react';
import Select, { StylesConfig, GroupBase } from 'react-select';
import { useUiStore } from '../../stores/uiStore';

export interface SelectOption {
  value: string | number;
  label: string;
}

interface Props {
  options: SelectOption[];
  value?: string | number | null;
  onChange?: (value: string | number | null) => void;
  placeholder?: string;
  isLoading?: boolean;
  isDisabled?: boolean;
  isClearable?: boolean;
  noOptionsMessage?: string;
  inputId?: string;
  height?: number;
  /**
   * نام دسترس‌پذیر فیلد. react-select ورودی داخلی خودش را بدون label رندر می‌کند و
   * placeholder را هم به‌صورت div می‌گذارد نه attribute، پس بدون این، فیلد برای
   * screen reader بی‌نام می‌ماند. پیش‌فرض روی placeholder می‌افتد.
   */
  ariaLabel?: string;
  /** اگر label قابل‌مشاهده‌ای وجود دارد، id آن را بده (بر ariaLabel اولویت دارد). */
  ariaLabelledBy?: string;
  /**
   * جستجوی سمت سرور: با هر تایپ صدا زده می‌شود تا مصرف‌کننده `options` تازه بدهد.
   *
   * وقتی داده می‌شود، فیلترِ داخلی react-select خاموش می‌شود؛ وگرنه نتیجهٔ سرور
   * دوباره روی متنِ تایپ‌شده فیلتر می‌شد و گزینه‌هایی که سرور با معیارِ دیگری
   * (مثلاً شمارهٔ موبایل) پیدا کرده بود ناپدید می‌شدند.
   */
  onInputChange?: (input: string) => void;
}

export default function SearchableSelect({
  options,
  value,
  onChange,
  placeholder = 'انتخاب کنید...',
  isLoading,
  isDisabled,
  isClearable,
  noOptionsMessage = 'موردی یافت نشد',
  inputId,
  height = 42,
  ariaLabel,
  ariaLabelledBy,
  onInputChange,
}: Props) {
  const darkMode = useUiStore((s) => s.darkMode);

  // مقایسهٔ نرم (string↔number): مقدار پیش‌فرض ممکن است number باشد ولی value گزینه String
  // (مثلاً id بیمه). تطبیق سخت‌گیرانه در این حالت گزینه را خالی نشان می‌داد.
  const selected = useMemo(
    () => (value == null || value === ''
      ? null
      : options.find((o) => String(o.value) === String(value)) ?? null),
    [options, value],
  );

  const styles: StylesConfig<SelectOption, false, GroupBase<SelectOption>> = {
    control: (base, state) => ({
      ...base,
      background:   state.isFocused ? 'var(--surface)' : 'var(--surface-2)',
      borderColor:  state.isFocused ? 'var(--primary)' : 'var(--border)',
      boxShadow:    state.isFocused ? '0 0 0 4px var(--ring)' : 'none',
      borderRadius: 'var(--r-sm)',
      minHeight:    height,
      fontSize:     14,
      cursor:       'pointer',
      '&:hover': {
        borderColor: state.isFocused ? 'var(--primary)' : 'var(--border-2)',
      },
    }),
    valueContainer: (base) => ({ ...base, padding: '0 14px' }),
    menu: (base) => ({
      ...base,
      background:   'var(--surface)',
      border:       '1px solid var(--border)',
      boxShadow:    'var(--shadow-lg)',
      borderRadius: 'var(--r)',
      overflow:     'hidden',
      marginTop:    4,
    }),
    menuPortal: (base) => ({ ...base, zIndex: 9999 }),
    option: (base, state) => ({
      ...base,
      background: state.isSelected
        ? 'var(--primary-soft2)'
        : state.isFocused
          ? 'var(--surface-2)'
          : 'transparent',
      color:      state.isSelected ? 'var(--primary-700)' : 'var(--text)',
      fontWeight: state.isSelected ? 700 : 400,
      fontSize:   14,
      cursor:     'pointer',
      padding:    '9px 14px',
    }),
    singleValue:        (base) => ({ ...base, color: 'var(--text)' }),
    input:              (base) => ({ ...base, color: 'var(--text)', margin: 0, padding: 0 }),
    placeholder:        (base) => ({ ...base, color: 'var(--text-3)' }),
    indicatorSeparator: (base) => ({ ...base, background: 'var(--border)' }),
    dropdownIndicator:  (base) => ({
      ...base,
      color: 'var(--text-3)',
      padding: '0 10px',
      '&:hover': { color: 'var(--text-2)' },
    }),
    clearIndicator: (base) => ({
      ...base,
      color: 'var(--text-3)',
      padding: '0 6px',
      '&:hover': { color: 'var(--danger)' },
    }),
    loadingIndicator:  (base) => ({ ...base, color: 'var(--primary)' }),
    noOptionsMessage:  (base) => ({ ...base, color: 'var(--text-3)', fontSize: 13 }),
    loadingMessage:    (base) => ({ ...base, color: 'var(--text-3)', fontSize: 13 }),
  };

  return (
    <Select<SelectOption>
      // پیشوند پایدار برای کلاس‌ها: کلاس‌های emotion در build تولیدی برچسب ندارند و
      // «منوی باز است یا نه» با آن‌ها قابل تشخیص نیست. useOverlayDismiss به همین
      // نشانه نگاه می‌کند تا Esc اول منو را ببندد نه مودال را.
      classNamePrefix="cp-select"
      options={options}
      value={selected}
      onChange={(opt) => onChange?.(opt ? opt.value : null)}
      placeholder={placeholder}
      isLoading={isLoading}
      isDisabled={isDisabled}
      isClearable={isClearable}
      onInputChange={onInputChange ? (input, meta) => {
        // react-select ورودی را هنگام بستن منو و blur هم «تغییر» می‌داند؛ آن دو را
        // رد نکنیم، هر بار بستنِ منو لیست را به حالت خالی برمی‌گرداند.
        if (meta.action === 'input-change') { onInputChange(input); }
      } : undefined}
      filterOption={onInputChange ? null : undefined}
      styles={styles}
      isRtl
      menuPortalTarget={typeof document !== 'undefined' ? document.body : undefined}
      menuPosition="fixed"
      noOptionsMessage={() => noOptionsMessage}
      loadingMessage={() => 'در حال بارگذاری...'}
      inputId={inputId}
      aria-labelledby={ariaLabelledBy}
      aria-label={ariaLabelledBy ? undefined : (ariaLabel ?? placeholder)}
    />
  );
}
