import { useState, useRef, useCallback, useEffect, type FC } from "react";
import { AutoComplete, type AutoCompleteCompleteEvent } from "primereact/autocomplete";
import { CityPickerPopup } from "./CityPickerPopup.js";
import type { IDictionaries } from "@/shared/dictionaries/index.js";
import "./CityAutocomplete.scss";

interface CitySuggestion {
  code: string;
  name: string;
}

export interface CityAutocompleteProps {
  label: string;
  placeholder: string;
  value: string;
  onChange: (code: string) => void;
  dictionaries: IDictionaries | null;
  onLocate?: () => void | Promise<void>;
  error?: string;
  testIdPrefix?: string;
}

export const CityAutocomplete: FC<CityAutocompleteProps> = ({
  label,
  placeholder,
  value,
  onChange,
  dictionaries,
  onLocate,
  error,
  testIdPrefix = "city-autocomplete",
}) => {
  const [inputValue, setInputValue] = useState<CitySuggestion | string>(value);
  const [suggestions, setSuggestions] = useState<CitySuggestion[]>([]);
  const [popupOpen, setPopupOpen] = useState(false);
  const rootRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    setInputValue(value);
  }, [value]);

  useEffect(() => {
    const handler = (e: MouseEvent) => {
      if (rootRef.current && !rootRef.current.contains(e.target as Node)) {
        setPopupOpen(false);
      }
    };
    document.addEventListener("mousedown", handler);
    return () => document.removeEventListener("mousedown", handler);
  }, []);

  const handleComplete = useCallback(
    (event: AutoCompleteCompleteEvent) => {
      if (!dictionaries) {
        setSuggestions([]);
        return;
      }
      const q = event.query.trim().toUpperCase();
      if (q.length === 0) {
        setSuggestions([]);
        return;
      }

      if (q.length === 3) {
        const byCity = dictionaries.cityByCode.get(q);
        if (byCity) {
          setSuggestions([{ code: byCity.code, name: byCity.name }]);
          return;
        }
      }

      const lc = event.query.toLowerCase();
      const byName = dictionaries.cities
        .filter((c) => c.name.toLowerCase().includes(lc))
        .slice(0, 15)
        .map((c) => ({ code: c.code, name: c.name }));
      if (byName.length) {
        setSuggestions(byName);
        return;
      }

      const byAirport = dictionaries.airportByCode.get(q);
      if (byAirport) {
        const city = dictionaries.cityByCode.get(byAirport.city_code.toUpperCase());
        if (city) {
          setSuggestions([{ code: city.code, name: city.name }]);
          return;
        }
      }
      setSuggestions([]);
    },
    [dictionaries],
  );

  const handleSelect = useCallback(
    (code: string) => {
      onChange(code);
      setPopupOpen(false);
    },
    [onChange],
  );

  const handleClear = useCallback(() => {
    onChange("");
    setInputValue("");
  }, [onChange]);

  const selectedCity = dictionaries?.cityByCode.get(value.toUpperCase()) ?? null;
  const hasValue = Boolean(selectedCity);

  return (
    <div ref={rootRef} className="city-autocomplete">
      <div className="city-autocomplete__labels-container">
        <label className="city-autocomplete__label">{label}</label>
        <label className="city-autocomplete__label" data-testid={`${testIdPrefix}-code`}>
          {selectedCity?.code ?? ""}
        </label>
      </div>

      {error && (
        <div className="tooltip" data-testid={`${testIdPrefix}-error`}>
          {error}
        </div>
      )}

      <div
        className={`city-autocomplete__input${
          hasValue ? " city-autocomplete__input--has-value" : ""
        }${error ? " city-autocomplete__input--has-error" : ""}`}
      >
        <AutoComplete
          value={inputValue}
          suggestions={suggestions}
          completeMethod={handleComplete}
          field="name"
          minLength={1}
          placeholder={placeholder}
          onChange={(e) => setInputValue(e.value as CitySuggestion | string)}
          onSelect={(e) => {
            const sel = e.value as CitySuggestion;
            if (sel?.code) handleSelect(sel.code);
          }}
          data-testid={`${testIdPrefix}-input`}
          inputClassName="input--filter"
          className="input--filter"
        />
        <button
          type="button"
          className="button-clear"
          onClick={handleClear}
          data-testid={`${testIdPrefix}-clear-button`}
          aria-label="clear"
        />
        <button
          type="button"
          className={`city-autocomplete__search-button${
            popupOpen ? " city-autocomplete__search-button--opened" : ""
          }`}
          onClick={() => {
            if (!dictionaries) return;
            setPopupOpen((v) => !v);
          }}
          data-testid={`${testIdPrefix}-popup-button`}
          aria-label="open regional picker"
        />
      </div>

      {popupOpen && dictionaries && (
        <div className="city-autocomplete-popup-wrapper">
          <CityPickerPopup
            dictionaries={dictionaries}
            selectedCode={value}
            onSelect={handleSelect}
            {...(onLocate ? { onLocate } : {})}
          />
        </div>
      )}
    </div>
  );
};
