import { useState, useEffect, useRef } from "preact/hooks";

export default function RangeForm() {
    const [city, setCity] = useState("");
    const [citySuggest, setCitySuggest] = useState([]);
    const [highlightIndex, setHighlightIndex] = useState(-1);

    const [street, setStreet] = useState("");
    const [streetSuggest, setStreetSuggest] = useState([]);
    const [streetHighlightIndex, setStreetHighlightIndex] = useState(-1);

    const [streetDisabled, setStreetDisabled] = useState(true);
    const [streetRequired, setStreetRequired] = useState(false);

    const [number, setNumber] = useState("");
    const [error, setError] = useState("");
    const [loading, setLoading] = useState(false);

    const cityListRef = useRef(null);
    const streetListRef = useRef(null);

    let timeoutCity = null;
    let timeoutStreet = null;

    async function fetchCitySuggestions(q) {
        const res = await fetch(`/api/range/cities-autocomplete?q=${encodeURIComponent(q)}`);
        setCitySuggest(await res.json());
        setHighlightIndex(-1);
    }

    function onCityInput(e) {
        const value = e.target.value;
        setCity(value);
        setError("");

        if (timeoutCity) clearTimeout(timeoutCity);

        if (value.trim().length < 2) {
            setCitySuggest([]);
            return;
        }

        timeoutCity = setTimeout(() => fetchCitySuggestions(value), 250);
    }

    function onCityKeyDown(e) {
        if (!citySuggest.length) return;

        if (e.key === "ArrowDown") {
            e.preventDefault();
            setHighlightIndex((prev) => (prev + 1) % citySuggest.length);
        }

        if (e.key === "ArrowUp") {
            e.preventDefault();
            setHighlightIndex((prev) =>
                prev <= 0 ? citySuggest.length - 1 : prev - 1
            );
        }

        if (e.key === "Enter" && highlightIndex >= 0) {
            e.preventDefault();
            const chosen = citySuggest[highlightIndex];
            setCity(chosen);
            setCitySuggest([]);
            setHighlightIndex(-1);
        }

        if (e.key === "Escape") {
            setCitySuggest([]);
            setHighlightIndex(-1);
        }
    }

    useEffect(() => {
        if (highlightIndex < 0 || !cityListRef.current) return;
        cityListRef.current.children[highlightIndex]?.scrollIntoView({ block: "nearest" });
    }, [highlightIndex]);

    useEffect(() => {
        if (!citySuggest.length) return;

        const exact = citySuggest.find(
            (c) => c.toLowerCase() === city.toLowerCase()
        );

        if (exact) {
            setCity(exact);
            setCitySuggest([]);
            setHighlightIndex(-1);
            updateStreetAvailability(exact);
        }
    }, [city, citySuggest]);

    async function updateStreetAvailability(currentCity) {
        if (!currentCity) {
            setStreetDisabled(true);
            setStreetRequired(false);
            setStreet("");
            setStreetSuggest([]);
            setStreetHighlightIndex(-1);
            return;
        }

        const res = await fetch(`/api/range/has-streets?city=${encodeURIComponent(currentCity)}`);
        const { hasStreets } = await res.json();

        if (!hasStreets) {
            setStreetDisabled(true);
            setStreetRequired(false);
            setStreet("");
            setStreetSuggest([]);
            setStreetHighlightIndex(-1);
            return;
        }

        setStreetDisabled(false);
        setStreetRequired(true);
        setStreetSuggest([]);
        setStreetHighlightIndex(-1);
    }

    useEffect(() => {
        updateStreetAvailability(city);
    }, [city]);

    async function fetchStreetSuggestions(q, c) {
        const res = await fetch(
            `/api/range/streets-autocomplete?city=${encodeURIComponent(c)}&q=${encodeURIComponent(q)}`
        );
        setStreetSuggest(await res.json());
        setStreetHighlightIndex(-1);
    }

    function onStreetInput(e) {
        const value = e.target.value;
        setStreet(value);
        setError("");

        if (!city || streetDisabled) return;

        if (!value) {
            setStreetSuggest([]);
            setStreetHighlightIndex(-1);
            return;
        }

        if (timeoutStreet) clearTimeout(timeoutStreet);
        timeoutStreet = setTimeout(() => fetchStreetSuggestions(value, city), 250);
    }

    function onStreetKeyDown(e) {
        if (!streetSuggest.length) return;

        if (e.key === "ArrowDown") {
            e.preventDefault();
            setStreetHighlightIndex((prev) => (prev + 1) % streetSuggest.length);
        }

        if (e.key === "ArrowUp") {
            e.preventDefault();
            setStreetHighlightIndex((prev) =>
                prev <= 0 ? streetSuggest.length - 1 : prev - 1
            );
        }

        if (e.key === "Enter" && streetHighlightIndex >= 0) {
            e.preventDefault();
            setStreet(streetSuggest[streetHighlightIndex]);
            setStreetSuggest([]);
            setStreetHighlightIndex(-1);
        }

        if (e.key === "Escape") {
            setStreetSuggest([]);
            setStreetHighlightIndex(-1);
        }
    }

    useEffect(() => {
        if (streetHighlightIndex < 0 || !streetListRef.current) return;
        streetListRef.current.children[streetHighlightIndex]?.scrollIntoView({ block: "nearest" });
    }, [streetHighlightIndex]);

    useEffect(() => {
        if (!streetSuggest.length) return;

        const exact = streetSuggest.find(
            (s) => s.toLowerCase() === street.toLowerCase()
        );

        if (exact) {
            setStreet(exact);
            setStreetSuggest([]);
            setStreetHighlightIndex(-1);
        }
    }, [street, streetSuggest]);

    async function onSubmit(e) {
        e.preventDefault();
        setError("");

        if (streetRequired && !street.trim()) {
            setError("Ulica jest wymagana w tej miejscowości.");
            return;
        }

        setLoading(true);

        const res = await fetch("/api/range/search", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ city, street, number }),
        });

        const data = await res.json();

        if (!data.ok || !data.result) {
            setError("Adres nie znajduje się w zasięgu.");
            setLoading(false);
            return;
        }

        window.showAddressOnMap(data.result);

        setCity("");
        setStreet("");
        setNumber("");
        updateStreetAvailability(city);
        setLoading(false);
    }

    return (
        <form class="flex flex-col gap-2" onSubmit={onSubmit} autocomplete="off">
            {/* CITY */}
            <div class="autocomplete-wrapper">
                <input
                    class={`f-input ${citySuggest.length ? "autocomplete-open" : ""}`}
                    name="formCity"
                    placeholder="Wpisz miejscowość..."
                    value={city}
                    onInput={onCityInput}
                    onKeyDown={onCityKeyDown}
                    required
                />

                {citySuggest.length > 0 && (
                    <ul class="autocomplete-list" ref={cityListRef}>
                        {citySuggest.map((item, idx) => (
                            <li
                                class={idx === highlightIndex ? "active" : ""}
                                onPointerDown={() => {
                                    setCity(item);
                                    setCitySuggest([]);
                                    setHighlightIndex(-1);
                                }}
                            >
                                {item}
                            </li>
                        ))}
                    </ul>
                )}
            </div>

            {/* STREET */}
            <div class="autocomplete-wrapper">
                <input
                    class={`f-input ${
                        streetSuggest.length ? "autocomplete-open" : ""
                    } ${streetDisabled ? "opacity-50 cursor-not-allowed" : ""}`}
                    placeholder={
                        streetDisabled
                            ? "W tej miejscowości nie występują"
                            : "Wpisz ulicę..."
                    }
                    name="formStreet"
                    value={street}
                    readOnly={streetDisabled}
                    onInput={streetDisabled ? undefined : onStreetInput}
                    onKeyDown={streetDisabled ? undefined : onStreetKeyDown}
                    required={streetRequired}
                />

                {streetSuggest.length > 0 && (
                    <ul class="autocomplete-list" ref={streetListRef}>
                        {streetSuggest.map((item, idx) => (
                            <li
                                class={idx === streetHighlightIndex ? "active" : ""}
                                onPointerDown={() => {
                                    setStreet(item);
                                    setStreetSuggest([]);
                                    setStreetHighlightIndex(-1);
                                }}
                            >
                                {item}
                            </li>
                        ))}
                    </ul>
                )}
            </div>

            {/* NUMBER */}
            <input
                class="f-input"
                name="formNumber"
                placeholder="np. 1A"
                value={number}
                onInput={(e) => setNumber(e.target.value)}
                required
            />

            {error && (
                <p class="text-red-600text-lg">{error}</p>
            )}

            <button
                class="btn btn-primary"
                disabled={loading}
            >
                {loading ? (
                    <span class="w-5 h-5 border-2 border-[var(--f-text)] border-t-transparent rounded-full animate-spin"></span>
                ) : (
                    "Sprawdź dostępność →"
                )}
            </button>
        </form>
    );
}
