import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { createPortal } from 'react-dom';
import { ts } from '../../../i18n/server';
import { dropdownPositionStyle, useDropdownPosition } from '../../../hooks/useDropdownPosition';
import { ChevronIcon } from '../../ui/icons/ChevronIcon';
import { SearchIcon } from '../../ui/icons/SearchIcon';
import { getFeatureIcon } from '../../../lib/feature-icons';
import { getGroupIcon } from '../../../lib/group-icons';
import { getPoiFeatureCategory } from '../../../lib/poi-distance-filter';
import type { FeatureMeta } from '../../../types';

const DROPDOWN_MAX_HEIGHT = 256;
const FALLBACK_DROPDOWN_MAX_HEIGHT = 'min(16rem, 45dvh)';

interface PoiTypeDropdownProps {
  options: FeatureMeta[];
  value: string;
  onChange: (featureName: string) => void;
}

function optionLabel(option: FeatureMeta): string {
  return ts(getPoiFeatureCategory(option.name) ?? option.name);
}

function optionIcon(option: FeatureMeta, className: string) {
  const icon = getFeatureIcon(option.name, className);
  if (icon) return icon;
  const G = option.group ? getGroupIcon(option.group) : null;
  return G ? <G className={className} /> : null;
}

export function PoiTypeDropdown({ options, value, onChange }: PoiTypeDropdownProps) {
  const { t } = useTranslation();
  const [open, setOpen] = useState(false);
  const [filter, setFilter] = useState('');
  const [activeIndex, setActiveIndex] = useState(-1);
  const containerRef = useRef<HTMLDivElement>(null);
  const dropdownRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);
  const listRef = useRef<HTMLDivElement>(null);
  const pos = useDropdownPosition(containerRef, open);

  const selected = options.find((option) => option.name === value);

  const filtered = useMemo(() => {
    if (!filter.trim()) return options;
    const lower = filter.trim().toLowerCase();
    return options.filter((option) => optionLabel(option).toLowerCase().includes(lower));
  }, [options, filter]);

  useEffect(() => {
    if (!open) return;
    const handler = (e: MouseEvent) => {
      if (
        containerRef.current &&
        !containerRef.current.contains(e.target as Node) &&
        !dropdownRef.current?.contains(e.target as Node)
      ) {
        setOpen(false);
        setFilter('');
        setActiveIndex(-1);
      }
    };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, [open]);

  useEffect(() => {
    if (activeIndex < 0 || !listRef.current) return;
    const item = listRef.current.children[activeIndex] as HTMLElement | undefined;
    item?.scrollIntoView({ block: 'nearest' });
  }, [activeIndex]);

  const handleSelect = useCallback(
    (option: FeatureMeta) => {
      onChange(option.name);
      setOpen(false);
      setFilter('');
      setActiveIndex(-1);
    },
    [onChange]
  );

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      if (e.key === 'ArrowDown') {
        e.preventDefault();
        setActiveIndex((prev) => (prev < filtered.length - 1 ? prev + 1 : prev));
      } else if (e.key === 'ArrowUp') {
        e.preventDefault();
        setActiveIndex((prev) => (prev > 0 ? prev - 1 : -1));
      } else if (e.key === 'Enter') {
        e.preventDefault();
        if (activeIndex >= 0 && activeIndex < filtered.length) {
          handleSelect(filtered[activeIndex]);
        }
      } else if (e.key === 'Escape') {
        setOpen(false);
        setFilter('');
        setActiveIndex(-1);
      }
    },
    [filtered, activeIndex, handleSelect]
  );

  const handleOpen = () => {
    setOpen(true);
    setFilter('');
    setActiveIndex(-1);
    requestAnimationFrame(() => inputRef.current?.focus({ preventScroll: true }));
  };

  const dropdownStyle = pos
    ? { ...dropdownPositionStyle(pos), maxHeight: Math.min(pos.maxHeight, DROPDOWN_MAX_HEIGHT) }
    : { maxHeight: FALLBACK_DROPDOWN_MAX_HEIGHT };

  const dropdown = open && (
    <div
      ref={dropdownRef}
      className="flex flex-col overflow-hidden rounded-md border border-warm-200 bg-white shadow-lg dark:border-warm-700 dark:bg-warm-800"
      style={dropdownStyle}
    >
      <div className="shrink-0 border-b border-warm-100 p-1.5 dark:border-warm-700">
        <div className="relative">
          <SearchIcon className="pointer-events-none absolute left-2 top-1/2 h-3 w-3 -translate-y-1/2 text-warm-400 dark:text-warm-500" />
          <input
            ref={inputRef}
            type="text"
            value={filter}
            onChange={(e) => {
              setFilter(e.target.value);
              setActiveIndex(-1);
            }}
            onKeyDown={handleKeyDown}
            placeholder={t('poiPane.searchCategories')}
            className="w-full rounded border border-warm-200 bg-warm-50 py-1 pl-7 pr-2 text-xs text-navy-950 outline-none placeholder:text-warm-400 focus:ring-1 focus:ring-teal-400 dark:border-warm-600 dark:bg-warm-900 dark:text-warm-200 dark:placeholder:text-warm-500"
          />
        </div>
      </div>

      <div ref={listRef} className="min-h-0 flex-1 overflow-y-auto">
        {filtered.length === 0 ? (
          <div className="px-2 py-3 text-center text-xs text-warm-400 dark:text-warm-500">
            {t('filters.noMatchingFeatures')}
          </div>
        ) : (
          filtered.map((option, idx) => {
            const isSelected = option.name === value;
            const isActive = idx === activeIndex;
            return (
              <button
                key={option.name}
                type="button"
                className={`flex w-full cursor-pointer items-center gap-1.5 px-2 py-1.5 text-left text-sm ${
                  isActive
                    ? 'bg-teal-50 dark:bg-teal-900/30'
                    : isSelected
                      ? 'bg-warm-50 dark:bg-warm-700/50'
                      : 'hover:bg-warm-50 dark:hover:bg-warm-700'
                }`}
                onMouseEnter={() => setActiveIndex(idx)}
                onMouseDown={(e) => {
                  e.preventDefault();
                  handleSelect(option);
                }}
              >
                {optionIcon(option, 'h-3.5 w-3.5 shrink-0 text-teal-600 dark:text-teal-400')}
                <span
                  className={`truncate ${
                    isSelected
                      ? 'font-medium text-navy-950 dark:text-warm-100'
                      : 'text-warm-700 dark:text-warm-200'
                  }`}
                >
                  {optionLabel(option)}
                </span>
              </button>
            );
          })
        )}
      </div>
    </div>
  );

  return (
    <div ref={containerRef} className="relative">
      <button
        type="button"
        onClick={() => (open ? setOpen(false) : handleOpen())}
        className="flex w-full items-center gap-1.5 rounded-md border border-warm-200 bg-warm-50 px-2 py-1.5 pr-8 text-left text-sm font-medium text-navy-950 shadow-inner outline-none transition-colors hover:bg-white focus:border-teal-400 focus:ring-2 focus:ring-teal-200 dark:border-warm-700 dark:bg-navy-900 dark:text-warm-100 dark:hover:bg-navy-800 dark:focus:ring-teal-900/50"
      >
        {selected && optionIcon(selected, 'h-4 w-4 shrink-0 text-teal-600 dark:text-teal-400')}
        <span className="min-w-0 flex-1 truncate">{selected ? optionLabel(selected) : ''}</span>
        <ChevronIcon
          direction={open ? 'up' : 'down'}
          className="pointer-events-none absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 text-warm-400 dark:text-warm-500"
        />
      </button>

      {open && createPortal(dropdown, document.body)}
    </div>
  );
}
