/**
 * City autocomplete search hook.
 *
 * Loads the cities dictionary from the API on first use, then searches
 * the in-memory list by name prefix / inclusion — matching the Angular
 * CitiesSearchService behavior.
 *
 * @module
 */

import { useState, useRef, useCallback } from "react";
import { useApiClient } from "@/shared/api/provider.js";

// ---------------------------------------------------------------------------
// Types matching the Angular CityModel shape from the dictionary API
// ---------------------------------------------------------------------------

interface DictionaryCity {
  code: string;
  title: Record<string, string>;
  country_code: string;
  has_afl_flights?: boolean;
  location?: { lat: number; lon: number };
}

export interface CitySuggestion {
  /** IATA city code */
  code: string;
  /** Localized display name */
  name: string;
}

// ---------------------------------------------------------------------------
// Hook
// ---------------------------------------------------------------------------

const MAX_ITEMS = 10;

export function useCitySearch() {
  const client = useApiClient();
  const [suggestions, setSuggestions] = useState<CitySuggestion[]>([]);
  const citiesRef = useRef<CitySuggestion[] | null>(null);
  const loadingRef = useRef<Promise<CitySuggestion[]> | null>(null);

  const loadCities = useCallback(async (): Promise<CitySuggestion[]> => {
    if (citiesRef.current) return citiesRef.current;
    if (loadingRef.current) return loadingRef.current;

    const promise = client
      .get<DictionaryCity[]>("dictionary/1/cities")
      .then((raw) => {
        const locale = client.locale;
        const mapped: CitySuggestion[] = raw
          .filter((c) => {
            const title = c.title?.[locale] ?? c.title?.["ru"] ?? "";
            // Filter out entries with only latin characters (matches Angular filter)
            return title && !/^[a-zA-Z.,:; ]+$/.test(title);
          })
          .map((c) => ({
            code: c.code,
            name: c.title?.[locale] ?? c.title?.["ru"] ?? c.code,
          }));
        citiesRef.current = mapped;
        return mapped;
      });

    loadingRef.current = promise;
    return promise;
  }, [client]);

  const search = useCallback(
    async (query: string) => {
      if (!query || query.length === 0) {
        setSuggestions([]);
        return;
      }

      const cities = await loadCities();
      const q = query.toLowerCase();

      // If exactly 3 chars, try code match first
      if (query.length === 3) {
        const byCode = cities.filter(
          (c) => c.code.toLowerCase() === q,
        );
        if (byCode.length > 0) {
          setSuggestions(byCode.slice(0, MAX_ITEMS));
          return;
        }
      }

      // Search by name: starts-with first, then includes
      const startsWith = cities.filter((c) =>
        c.name.toLowerCase().startsWith(q),
      );

      if (startsWith.length >= MAX_ITEMS) {
        setSuggestions(startsWith.slice(0, MAX_ITEMS));
        return;
      }

      const includes = cities.filter((c) =>
        c.name.toLowerCase().includes(q),
      );

      // Deduplicate preserving startsWith order
      const seen = new Set(startsWith.map((c) => c.code));
      const merged = [...startsWith];
      for (const c of includes) {
        if (!seen.has(c.code)) {
          seen.add(c.code);
          merged.push(c);
        }
      }

      setSuggestions(merged.slice(0, MAX_ITEMS));
    },
    [loadCities],
  );

  return { suggestions, search };
}
