import { useEffect, useMemo, useRef, useState } from 'react';
import { RiCheckLine, RiCloseLine } from '@remixicon/react';
import {
    InputGroup,
    InputGroupAddon,
    InputGroupButton,
    InputGroupInput,
} from '@/components/ui/input-group';
import { cn } from '@/lib/utils';

export type LocationSearchOption = {
    id: number;
    name: string;
    address: string | null;
    city: string | null;
    state: string | null;
    zip: string | null;
};

type LocationSearchSelectProps = {
    locations: LocationSearchOption[];
    value: number | '';
    onValueChange: (value: number | '') => void;
    inputId?: string;
    placeholder?: string;
    showClear?: boolean;
};

function locationAddressLine(location: LocationSearchOption): string {
    return [location.address, location.city, location.state, location.zip]
        .filter(Boolean)
        .join(', ');
}

function locationCityStateZip(location: LocationSearchOption): string {
    const cityState = [location.city, location.state]
        .filter(Boolean)
        .join(', ');

    if (cityState && location.zip) {
        return `${cityState} ${location.zip}`;
    }

    return cityState || location.zip || '';
}

const listItemClassName =
    'group/item relative flex w-full cursor-default rounded-sm py-1.5 pr-8 pl-2 text-left text-sm outline-hidden select-none hover:bg-accent hover:text-accent-foreground';

const locationMetaClassName =
    'truncate text-xs text-popover-foreground/75 transition-colors group-hover/item:text-accent-foreground/90';

const locationCityClassName =
    'shrink-0 font-medium text-popover-foreground/90 group-hover/item:text-accent-foreground';

export function LocationSearchSelect({
    locations,
    value,
    onValueChange,
    inputId = 'location-search',
    placeholder = 'Search by name, address, city, or ZIP...',
    showClear = true,
}: LocationSearchSelectProps) {
    const containerRef = useRef<HTMLDivElement>(null);
    const [open, setOpen] = useState(false);
    const [query, setQuery] = useState('');

    const selectedLocation = useMemo(
        () => locations.find((location) => location.id === value) ?? null,
        [locations, value],
    );

    useEffect(() => {
        if (!open) {
            return;
        }

        const handlePointerDown = (event: PointerEvent) => {
            if (containerRef.current?.contains(event.target as Node)) {
                return;
            }

            setOpen(false);
            setQuery('');
        };

        document.addEventListener('pointerdown', handlePointerDown);

        return () => {
            document.removeEventListener('pointerdown', handlePointerDown);
        };
    }, [open]);

    const filteredLocations = useMemo(() => {
        const term = query.trim().toLowerCase();

        if (!term) {
            return locations.slice(0, 15);
        }

        return locations
            .filter((location) => {
                const addressLine = locationAddressLine(location).toLowerCase();
                const zipDigits = location.zip?.replace(/\D/g, '') ?? '';
                const queryDigits = term.replace(/\D/g, '');

                return (
                    location.name.toLowerCase().includes(term) ||
                    addressLine.includes(term) ||
                    (queryDigits !== '' && zipDigits.includes(queryDigits))
                );
            })
            .slice(0, 15);
    }, [locations, query]);

    const inputValue = open
        ? query
        : selectedLocation
          ? selectedLocation.name
          : '';

    const canClear =
        showClear &&
        (selectedLocation !== null || (open && query.length > 0));

    const closePicker = () => {
        setOpen(false);
        setQuery('');
    };

    const selectLocation = (location: LocationSearchOption) => {
        onValueChange(location.id);
        closePicker();
    };

    const handleClear = () => {
        setQuery('');
        onValueChange('');
        setOpen(false);
    };

    if (locations.length === 0) {
        return (
            <p className="text-sm text-muted-foreground">
                No active locations yet.
            </p>
        );
    }

    return (
        <div ref={containerRef} className="grid gap-2">
            <InputGroup>
                <InputGroupInput
                    id={inputId}
                    value={inputValue}
                    placeholder={placeholder}
                    autoComplete="off"
                    onFocus={() => setOpen(true)}
                    onChange={(event) => {
                        setQuery(event.target.value);
                        setOpen(true);
                    }}
                />
                {canClear ? (
                    <InputGroupAddon align="inline-end">
                        <InputGroupButton
                            size="icon-xs"
                            variant="ghost"
                            aria-label="Clear location search"
                            onMouseDown={(event) => event.preventDefault()}
                            onClick={handleClear}
                        >
                            <RiCloseLine className="pointer-events-none" />
                        </InputGroupButton>
                    </InputGroupAddon>
                ) : null}
            </InputGroup>

            {open ? (
                <div className="overflow-hidden rounded-md bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10">
                    <div className="max-h-48 scroll-py-1 overflow-y-auto p-1">
                        {filteredLocations.length === 0 ? (
                            <p className="px-2 py-3 text-center text-sm text-muted-foreground">
                                No locations found.
                            </p>
                        ) : (
                            filteredLocations.map((location) => {
                                const isSelected =
                                    selectedLocation?.id === location.id;
                                const cityStateZip =
                                    locationCityStateZip(location);

                                return (
                                    <button
                                        key={location.id}
                                        type="button"
                                        className={cn(
                                            listItemClassName,
                                            'flex-col items-start gap-0.5',
                                        )}
                                        onMouseDown={(event) =>
                                            event.preventDefault()
                                        }
                                        onClick={() =>
                                            selectLocation(location)
                                        }
                                    >
                                        <span className="truncate font-medium">
                                            {location.name}
                                        </span>
                                        {location.address || cityStateZip ? (
                                            <span className="flex min-w-0 flex-col gap-0.5 sm:flex-row sm:items-center sm:gap-1.5">
                                                {location.address ? (
                                                    <span
                                                        className={
                                                            locationMetaClassName
                                                        }
                                                    >
                                                        {location.address}
                                                    </span>
                                                ) : null}
                                                {location.address &&
                                                cityStateZip ? (
                                                    <span
                                                        aria-hidden
                                                        className="hidden text-popover-foreground/40 group-hover/item:text-accent-foreground/50 sm:inline"
                                                    >
                                                        ·
                                                    </span>
                                                ) : null}
                                                {cityStateZip ? (
                                                    <span
                                                        className={
                                                            locationCityClassName
                                                        }
                                                    >
                                                        {cityStateZip}
                                                    </span>
                                                ) : null}
                                            </span>
                                        ) : null}
                                        {isSelected ? (
                                            <span className="pointer-events-none absolute top-2 right-2 flex size-4 items-center justify-center">
                                                <RiCheckLine className="size-4" />
                                            </span>
                                        ) : null}
                                    </button>
                                );
                            })
                        )}
                    </div>
                </div>
            ) : null}
        </div>
    );
}
