import React, { useEffect, useRef, useState } from "react";
import countyListing from "./countries.json";
import LocationChoice from "./LocationChoice";

export type LocationData = { relative: { country: string, state?: string, city: string; }, exact?: [number, number]; };
type LocPromptProps = {
    setUserLocation(location: LocationData): void;
    rejectedLocationExact(): void;
};
const LocPrompt = ({ setUserLocation, rejectedLocationExact }: LocPromptProps) =>
{
    const [exactUnused, updateExactUnused] = useState(true);
    const [relativeLoc, updateRelativeLoc] = useState({ country: { countryName: "", countryCode: "" }, state: "", city: "" });

    const [locationsList, updateLocationsList] = useState<LocationData[]>([]);
    const [locationInputVisible, updateLocationInputVisible] = useState(true);

    const handleCountryChange = (event: React.ChangeEvent<HTMLSelectElement>) =>
    {
        const newCountryCode = event.target.value;
        const newCountryName = event.target.options[event.target.selectedIndex].text;
        updateRelativeLoc({ country: { countryCode: newCountryCode, countryName: newCountryName }, state: "", city: relativeLoc.city });
    };

    // responsible for changes in both state and city
    const handleLocalChange = (event: React.ChangeEvent<HTMLInputElement>) =>
    {
        const newLocal = event.target.value;
        if (event.target.id === "stateNameInput") updateRelativeLoc({ country: relativeLoc.country, state: newLocal, city: relativeLoc.city });
        else if (event.target.id === "cityNameInput") updateRelativeLoc({ country: relativeLoc.country, state: relativeLoc.state, city: newLocal });
    };

    const countries = Object.entries(countyListing).map(([countryCode, countryName]) => { return (<option key={countryName} value={countryCode}> {countryName} </option>); });

    const basePromptClass = "mx-auto h-fit grid grid-cols-1 grid-rows-auto grid-flow-row gap-y-2";
    const locationInputPromptBoxClass = locationInputVisible ? basePromptClass : basePromptClass + " hidden";
    const locationSelectPromptBoxClass = locationInputVisible ? basePromptClass + " hidden" : basePromptClass;

    return (
        <div className="mt-4 p-12 mx-auto px-8 py-2 max-w-lg">
            {exactUnused && <button className="my-auto w-full h-fit mb-6 p-3 bg-sky-100 text-sky-500 rounded-md border-2 border-sky-500 font-medium hover:bg-sky-200" onClick={() =>
            {
                requestLocation({ updatePosition: setUserLocation, rejectExact: rejectedLocationExact });
                updateExactUnused(false);
            }}> Auto Locate </button>}

            <div className={locationInputPromptBoxClass}>
                <form onSubmit={(event) =>
                {
                    fetchLocationData({ event: event, relativeLoc: relativeLoc }).then((locationsArray) =>
                    {
                        if (locationsArray.locations.length > 0)
                        {
                            if (locationsArray.locations.length === 1)
                            {
                                updateLocationsList(locationsArray.locations);
                                setUserLocation(locationsArray.locations[0]);
                                return locationsArray;
                            }

                            // multiple locations with the same name
                            // make location selection visible

                            updateLocationsList(locationsArray.locations);
                            updateLocationInputVisible(false);
                        }
                        return locationsArray;
                    });
                }}>
                    <label htmlFor="countryNameInput" >Country</label>
                    <select name="countryName" id="countryNameSelect" placeholder="Country" defaultValue={""} className="mt-1 mb-3 w-full p-2 py-3 bg-neutral-100 border-sky-300 border-l-4 rounded-sm appearance-none" onChange={handleCountryChange}>
                        <option value="" disabled>Select a Country</option>
                        {countries}
                    </select>

                    {relativeLoc.country.countryCode === "US" && <>
                        <label htmlFor="countryNameInput">State (e.g. TX)</label>
                        <input type="text" value={relativeLoc.state} name="stateName" id="stateNameInput" placeholder="State" className="mt-1 mb-3 w-full p-2 py-3 bg-neutral-100 border-sky-300 border-l-4 rounded-sm" onChange={handleLocalChange} />
                    </>
                    }

                    <label htmlFor="countryNameInput" className="mb-4">City</label>
                    <input type="text" value={relativeLoc.city} name="cityName" id="cityNameInput" placeholder="City" className="mt-1 mb-3 w-full p-2 py-3 bg-neutral-100 border-sky-300 border-l-4 rounded-sm" onChange={handleLocalChange} />

                    <button className="my-auto w-full h-fit p-3 bg-blue-400 rounded-md text-white font-medium hover:bg-blue-500">Search</button>
                </form>
            </div>

            {!locationInputVisible && <div className={locationSelectPromptBoxClass}>
                <h2 className="text-2xl">We have a good idea of where you are, <br /> but we just wanna be <em>absolutely exact: </em></h2>
                <LocationChoice locations={locationsList} selectedLocation={(loc) => setUserLocation(loc)} />
            </div>}
        </div>
    );
};
export default LocPrompt;

// Auto Location Func
type requestLocationProps = {
    updatePosition(location: LocationData | null): void;
    rejectExact(): void;
};
const requestLocation = ({ updatePosition, rejectExact }: requestLocationProps): [number, number] | null =>
{
    const locationAccepted = (position: GeolocationPosition) =>
    {
        // reverse geocode here
        fetch(
            "/api/tempura/reverselocation",
            {
                method: "POST",
                mode: "same-origin",
                cache: "no-cache",
                credentials: "same-origin",
                headers: {
                    "Content-Type": "application/json",
                },
                redirect: "follow",
                referrerPolicy: "no-referrer",
                body: JSON.stringify({
                    lonlat: [position.coords.longitude, position.coords.latitude]
                })
            }
        ).then(response => response.json()).then((exactLocation) =>
        {
            console.log(exactLocation);

            updatePosition(exactLocation.locations[0]);
            return [position.coords.longitude, position.coords.latitude];
        });
    };

    const locationRejected = () =>
    {
        rejectExact();
    };

    if (navigator.geolocation)
    {
        navigator.geolocation.getCurrentPosition(locationAccepted, locationRejected);
    }
    else
    {
        rejectExact();
    }
    return null;
};


type fetchLocationDataProps = {
    event: React.FormEvent<HTMLFormElement>,
    relativeLoc: { country: { countryName: string, countryCode: string; }, state: string, city: string; };
};
async function fetchLocationData({ event, relativeLoc }: fetchLocationDataProps)
{
    event.preventDefault();

    // request possible locations from API, then update higher state with selected location after user selects
    return fetch(
        "/api/tempura/location",
        {
            method: "POST",
            mode: "same-origin",
            cache: "no-cache",
            credentials: "same-origin",
            headers: {
                "Content-Type": "application/json",
            },
            redirect: "follow",
            referrerPolicy: "no-referrer",
            body: JSON.stringify({
                country: relativeLoc.country,
                state: relativeLoc.state,
                city: relativeLoc.city
            })
        }
    ).then(response => response.json());
};
