"use client";

import { useMemo, useState, type KeyboardEvent } from "react";
import { LoaderCircle, MapPin, Search, X } from "lucide-react";
import { useLocationSearch } from "@/hooks/use-location-search";
import { useWeatherStore } from "@/lib/store";
import { findNearestSynopStation, locateSynopStations } from "@/lib/location-utils";
import { useI18n } from "@/lib/i18n";
import type { MeteoStationPosition, SynopStation } from "@/types/imgw";
import type { SelectedLocation } from "@/types/location";
import { CurrentLocationControl } from "@/components/weather/current-location-control";

export function LocationSearch({ stations, positions }: { stations: SynopStation[]; positions: MeteoStationPosition[] }) {
  const { language, t } = useI18n();
  const [query, setQuery] = useState("");
  const [isFocused, setIsFocused] = useState(false);
  const selectedLocation = useWeatherStore((state) => state.selectedLocation);
  const selectLocation = useWeatherStore((state) => state.selectLocation);
  const { data: locations, isFetching, isError } = useLocationSearch(query, language);
  const locatedStations = useMemo(() => locateSynopStations(stations, positions), [positions, stations]);
  const suggestions = useMemo(() => (locations ?? []).map((location) => ({
    location,
    nearest: findNearestSynopStation(location, locatedStations),
  })).filter((suggestion) => suggestion.nearest !== null), [locatedStations, locations]);
  const showSuggestions = isFocused && query.trim().length >= 2;
  const isPreparingStations = positions.length === 0;

  function chooseLocation(location: SelectedLocation) {
    selectLocation(location);
    setQuery("");
    setIsFocused(false);
  }

  function handleSearchKeyDown(event: KeyboardEvent<HTMLInputElement>) {
    const firstSuggestion = suggestions[0]?.nearest;
    if (event.key !== "Enter" || !showSuggestions || !firstSuggestion) return;
    event.preventDefault();
    chooseLocation(firstSuggestion);
  }

  return (
    <section className="relative z-30">
      <div className="glass rounded-panel p-3 sm:p-4">
        <div className="flex items-center gap-2 px-1 pb-3">
          <MapPin className="size-4 text-accent" />
          <p className="section-kicker">{t("location.label")}</p>
        </div>
        <div className="relative z-20">
          <label className="relative block">
            <span className="sr-only">{t("location.searchLabel")}</span>
            {isFetching || isPreparingStations ? <LoaderCircle className="pointer-events-none absolute left-3.5 top-1/2 size-4 -translate-y-1/2 animate-spin text-accent" /> : <Search className="pointer-events-none absolute left-3.5 top-1/2 size-4 -translate-y-1/2 text-muted" />}
            <input
              value={query}
              onChange={(event) => setQuery(event.target.value)}
              onKeyDown={handleSearchKeyDown}
              onFocus={() => setIsFocused(true)}
              onBlur={() => window.setTimeout(() => setIsFocused(false), 150)}
              placeholder={t("location.placeholder")}
              autoComplete="off"
              className="w-full rounded-card border border-border/70 bg-surface-raised/80 py-3.5 pl-10 pr-10 text-sm placeholder:text-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent"
            />
            {query && <button type="button" aria-label={t("location.clear")} onClick={() => setQuery("")} className="absolute right-3 top-1/2 -translate-y-1/2 rounded-control p-1 text-muted transition hover:bg-surface-muted/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent"><X className="size-4" /></button>}
          </label>
          {showSuggestions && (
            <div className="glass absolute inset-x-0 top-[calc(100%+0.5rem)] overflow-hidden rounded-panel p-2 shadow-card">
              {isPreparingStations ? <p className="px-3 py-4 text-sm text-muted">{t("location.preparing")}</p> :
                isError ? <p className="px-3 py-4 text-sm text-muted">{t("location.error")}</p> :
                !isFetching && !suggestions.length ? <p className="px-3 py-4 text-sm text-muted">{t("location.empty")}</p> :
                  suggestions.map(({ location, nearest }) => nearest && (
                    <button
                      type="button"
                      key={location.id}
                      onClick={() => chooseLocation(nearest)}
                      className="flex w-full items-start justify-between gap-3 rounded-card px-3 py-3 text-left transition hover:bg-surface-muted/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent"
                    >
                      <span>
                        <span className="block text-sm font-semibold">{location.name}</span>
                        <span className="mt-0.5 block text-xs text-muted">{[location.district, location.province].filter(Boolean).join(" · ")}</span>
                      </span>
                      <span className="shrink-0 text-right text-[0.68rem] leading-5 text-muted">{t("location.nearest")}<br /><strong className="font-semibold text-foreground">{nearest.stationName} · {nearest.distanceKm} km</strong></span>
                    </button>
                  ))}
            </div>
          )}
        </div>
        <CurrentLocationControl stations={locatedStations} />
        {selectedLocation && (
          <p className="mt-3 px-1 text-xs text-muted">
            {t("location.currentSource", { location: selectedLocation.name, station: selectedLocation.stationName, distance: selectedLocation.distanceKm })}
          </p>
        )}
        <p className="mt-3 px-1 text-[0.68rem] text-muted">
          {t("location.attribution")} <a href="https://open-meteo.com/en/docs/geocoding-api" target="_blank" rel="noreferrer" className="underline decoration-muted/60 underline-offset-2 transition hover:text-accent">Open-Meteo / GeoNames</a>
        </p>
      </div>
    </section>
  );
}
