'use client';

import { useEffect, useId, useRef, useState } from 'react';
import { MapPin } from 'lucide-react';
import {
  fetchGeoapifyAddressSuggestions,
  isDeliverableGeoapifyFeature,
  shouldUseGeoapifyAutocomplete,
} from '@/infrastructure/geocoding/geoapify-autocomplete';
import type { GeoapifyFeature } from '@/infrastructure/geocoding/geoapify-types';

export interface DeliveryAddressAutocompleteLabels {
  placeholder: string;
  hint: string;
  fallbackPlaceholder: string;
  fallbackHint: string;
  searching: string;
  noResults: string;
  outsideGothenburg: string;
  selectSuggestion: string;
}

interface DeliveryAddressAutocompleteProps {
  value: string;
  onChange: (value: string) => void;
  onValidationChange?: (isValid: boolean) => void;
  language: 'sv' | 'en';
  labels: DeliveryAddressAutocompleteLabels;
  inputClassName: string;
}

function formatSuggestion(feature: GeoapifyFeature): string {
  return (
    feature.properties.formatted ??
    [feature.properties.address_line1, feature.properties.address_line2]
      .filter(Boolean)
      .join(', ')
  );
}

export default function DeliveryAddressAutocomplete({
  value,
  onChange,
  onValidationChange,
  language,
  labels,
  inputClassName,
}: DeliveryAddressAutocompleteProps) {
  const listboxId = useId();
  const rootRef = useRef<HTMLDivElement>(null);
  const fetchGenerationRef = useRef(0);
  const [query, setQuery] = useState(value);
  const [suggestions, setSuggestions] = useState<GeoapifyFeature[]>([]);
  const [isOpen, setIsOpen] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState('');
  const [selectedFromList, setSelectedFromList] = useState(false);
  const [autocompleteActive, setAutocompleteActive] = useState<boolean | null>(null);

  const deactivateAutocomplete = () => {
    setAutocompleteActive(false);
    setSuggestions([]);
    setIsOpen(false);
    setIsLoading(false);
    setSelectedFromList(false);
    setError('');
    onValidationChange?.(true);
  };

  useEffect(() => {
    const active = shouldUseGeoapifyAutocomplete();
    setAutocompleteActive(active);
    if (!active) onValidationChange?.(true);
  }, [onValidationChange]);

  useEffect(() => {
    setQuery(value);
    if (autocompleteActive) {
      setSelectedFromList(!!value.trim());
    }
    setError('');
  }, [value, autocompleteActive]);

  useEffect(() => {
    if (autocompleteActive !== true) return;

    if (!query.trim()) {
      setSuggestions([]);
      setError('');
      setSelectedFromList(false);
      onValidationChange?.(true);
      return;
    }

    if (selectedFromList) {
      onValidationChange?.(!error);
      return;
    }

    onValidationChange?.(false);

    const generation = ++fetchGenerationRef.current;

    const handle = window.setTimeout(async () => {
      const trimmedQuery = query.trim();
      if (trimmedQuery.length < 3) {
        if (generation === fetchGenerationRef.current) {
          setSuggestions([]);
          setIsLoading(false);
        }
        return;
      }

      setIsLoading(true);
      try {
        const result = await fetchGeoapifyAddressSuggestions(trimmedQuery, language);
        if (generation !== fetchGenerationRef.current) return;

        if (result.status === 'unavailable') {
          deactivateAutocomplete();
          return;
        }
        setSuggestions(result.features);
        setIsOpen(result.features.length > 0);
      } finally {
        if (generation === fetchGenerationRef.current) {
          setIsLoading(false);
        }
      }
    }, 600);

    return () => window.clearTimeout(handle);
  }, [query, language, selectedFromList, error, onValidationChange, autocompleteActive]);

  useEffect(() => {
    if (autocompleteActive !== true) return;

    const handlePointerDown = (event: MouseEvent) => {
      if (!rootRef.current?.contains(event.target as Node)) {
        setIsOpen(false);
      }
    };
    document.addEventListener('mousedown', handlePointerDown);
    return () => document.removeEventListener('mousedown', handlePointerDown);
  }, [autocompleteActive]);

  const applySuggestion = (feature: GeoapifyFeature) => {
    if (!isDeliverableGeoapifyFeature(feature)) {
      setError(labels.outsideGothenburg);
      setSelectedFromList(false);
      onValidationChange?.(false);
      return;
    }

    const formatted = formatSuggestion(feature);
    setQuery(formatted);
    onChange(formatted);
    setSelectedFromList(true);
    setSuggestions([]);
    setIsOpen(false);
    setError('');
    onValidationChange?.(true);
  };

  const handleInputChange = (next: string) => {
    setQuery(next);
    onChange(next);
    if (autocompleteActive) {
      setSelectedFromList(false);
      setError('');
      onValidationChange?.(!next.trim());
    } else {
      onValidationChange?.(true);
    }
  };

  if (autocompleteActive === false) {
    return (
      <div className="relative">
        <div className="relative">
          <MapPin className="pointer-events-none absolute start-4 top-4 z-10 h-5 w-5 text-[#B38B4D]" />
          <textarea
            value={query}
            onChange={(e) => handleInputChange(e.target.value)}
            placeholder={labels.fallbackPlaceholder}
            autoComplete="street-address"
            rows={3}
            className={`${inputClassName} min-h-[5.5rem] resize-y ps-12`}
          />
        </div>
        <p className="mt-1.5 text-xs text-[#6B665F]">{labels.fallbackHint}</p>
      </div>
    );
  }

  return (
    <div ref={rootRef} className="relative">
      <div className="relative">
        <MapPin className="pointer-events-none absolute start-4 top-4 z-10 h-5 w-5 text-[#B38B4D]" />
        <input
          type="text"
          value={query}
          onChange={(e) => handleInputChange(e.target.value)}
          onFocus={() => {
            if (suggestions.length > 0) setIsOpen(true);
          }}
          placeholder={labels.placeholder}
          autoComplete="street-address"
          role="combobox"
          aria-expanded={isOpen}
          aria-controls={listboxId}
          className={`${inputClassName} ps-12`}
        />
      </div>

      <p className="mt-1.5 text-xs text-[#6B665F]">{labels.hint}</p>

      {isLoading && (
        <p className="mt-1 text-xs text-[#8A8478]">{labels.searching}</p>
      )}

      {isOpen && suggestions.length > 0 && (
        <ul
          id={listboxId}
          role="listbox"
          className="absolute z-20 mt-1 max-h-56 w-full overflow-auto rounded-xl border border-[#EDE6D9] bg-white py-1 shadow-lg"
        >
          {suggestions.map((feature, index) => {
            const label = formatSuggestion(feature);
            const secondary = [feature.properties.postcode, feature.properties.city]
              .filter(Boolean)
              .join(' · ');

            return (
              <li key={`${label}-${index}`} role="option">
                <button
                  type="button"
                  onMouseDown={(e) => e.preventDefault()}
                  onTouchStart={(e) => e.preventDefault()}
                  onClick={() => applySuggestion(feature)}
                  className="flex w-full flex-col px-4 py-3.5 text-left hover:bg-[#F8F5F0] active:bg-[#EDE6D9] min-h-[48px] touch-manipulation"
                >
                  <span className="truncate text-sm font-medium text-[#101724]" title={label}>{label}</span>
                  {secondary && (
                    <span className="text-xs text-[#6B665F]">{secondary}</span>
                  )}
                </button>
              </li>
            );
          })}
        </ul>
      )}

      {!isLoading && query.trim().length >= 3 && suggestions.length === 0 && !selectedFromList && (
        <p className="mt-1 text-xs text-[#8A8478]">{labels.noResults}</p>
      )}

      {error && (
        <p className="mt-1 text-xs text-red-600" role="alert">
          {error}
        </p>
      )}

      {!selectedFromList && query.trim().length > 0 && !error && (
        <p className="mt-1 text-xs text-[#8A8478]">{labels.selectSuggestion}</p>
      )}
    </div>
  );
}