'use client';

import { useState, useRef, useEffect } from 'react';
import { api, ApiError } from '@/lib/api';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Button } from '@/components/ui/button';

// ---- Types ----------------------------------------------------------------

interface Location {
  locationId: number;
  name: string;
  locationType: string;
  formattedAddress?: string;
  locality?: { localityId: number; name: string };
}

interface Locality {
  localityId: number;
  name: string;
}

interface Prediction {
  placeId: string;
  primaryText: string;
  secondaryText: string;
}

export interface LocationPickerProps {
  label: string;
  value: number | null;
  onChange: (id: number | null) => void;
  placeholder?: string;
  error?: string;
}

type Mode = 'closed' | 'open';

const LOCATION_TYPES = ['upashray', 'temple', 'residence', 'dharamshala', 'other'] as const;

// ---- Debounce hook --------------------------------------------------------

function useDebounce<T>(value: T, ms: number): T {
  const [debounced, setDebounced] = useState(value);
  useEffect(() => {
    const t = setTimeout(() => setDebounced(value), ms);
    return () => clearTimeout(t);
  }, [value, ms]);
  return debounced;
}

// ---- Component ------------------------------------------------------------

export function LocationPicker({ label, value, onChange, placeholder, error }: LocationPickerProps) {
  const [mode, setMode] = useState<Mode>('closed');
  const [query, setQuery] = useState('');
  const [selectedName, setSelectedName] = useState('');
  const [localResults, setLocalResults] = useState<Location[]>([]);
  const [googleResults, setGoogleResults] = useState<Prediction[]>([]);
  const [sessionToken, setSessionToken] = useState('');
  const [activeIdx, setActiveIdx] = useState(-1);
  const [googleLoading, setGoogleLoading] = useState(false);

  // modal
  const [modal, setModal] = useState<Prediction | null>(null);
  const [modalName, setModalName] = useState('');
  const [modalType, setModalType] = useState<string>('upashray');
  const [modalLocality, setModalLocality] = useState<number | null>(null);
  const [localities, setLocalities] = useState<Locality[]>([]);
  const [modalSaving, setModalSaving] = useState(false);
  const [modalError, setModalError] = useState('');

  const containerRef = useRef<HTMLDivElement>(null);
  // Long debounce + min 3 chars cuts the autocomplete fetch count by ~10×.
  // Within a session token, multiple keystrokes still bill as one Places
  // session if a place-details lookup follows, but bandwidth + our backend
  // throttling both benefit from the lower call rate.
  const debouncedQuery = useDebounce(query, 600);
  const MIN_CHARS_FOR_GOOGLE = 3;

  // Close on outside click
  useEffect(() => {
    function onDown(e: MouseEvent) {
      if (!containerRef.current?.contains(e.target as Node)) close();
    }
    document.addEventListener('mousedown', onDown);
    return () => document.removeEventListener('mousedown', onDown);
  }, []);

  // Local search — debounced so a fast typist doesn't blow the API throttler
  useEffect(() => {
    if (mode !== 'open') { setLocalResults([]); return; }
    if (!debouncedQuery.trim()) { setLocalResults([]); return; }
    api.get<Location[]>('/api/locations', { query: { q: debouncedQuery, limit: 10 } })
      .then(setLocalResults)
      .catch(() => setLocalResults([]));
  }, [debouncedQuery, mode]);

  // Google autocomplete — only when there's a query of meaningful length AND
  // no local matches. Avoids hitting Google for every keystroke and only
  // surfaces the option when local won't suffice.
  useEffect(() => {
    if (mode !== 'open') { setGoogleResults([]); return; }
    if (debouncedQuery.length < MIN_CHARS_FOR_GOOGLE) { setGoogleResults([]); return; }
    if (localResults.length > 0) { setGoogleResults([]); return; }
    setGoogleLoading(true);
    api.get<Prediction[]>('/api/places/autocomplete', {
      query: { q: debouncedQuery, sessionToken },
    })
      .then(setGoogleResults)
      .catch(() => setGoogleResults([]))
      .finally(() => setGoogleLoading(false));
  }, [debouncedQuery, mode, sessionToken, localResults.length]);

  // Load localities when modal opens (lazy)
  useEffect(() => {
    if (modal && localities.length === 0) {
      api.get<Locality[]>('/api/localities').then(setLocalities).catch(() => {});
    }
  }, [modal]);

  function open() {
    setMode('open');
    setQuery('');
    setActiveIdx(-1);
    if (!sessionToken) setSessionToken(crypto.randomUUID());
  }

  function close() {
    setMode('closed');
    setQuery('');
    setActiveIdx(-1);
  }

  function pickLocal(loc: Location) {
    onChange(loc.locationId);
    setSelectedName(loc.name);
    close();
  }

  function openModal(pred: Prediction) {
    setModal(pred);
    setModalName(pred.primaryText);
    setModalType('upashray');
    setModalLocality(null);
    setModalError('');
  }

  async function submitModal() {
    if (!modal) return;
    setModalSaving(true);
    setModalError('');
    try {
      const loc = await api.post<Location>('/api/locations/from-place-id', {
        placeId: modal.placeId,
        sessionToken,
        displayName: modalName.trim(),
        locationType: modalType,
        localityId: modalLocality,
      });
      pick(loc);
    } catch (e) {
      if (e instanceof ApiError && e.status === 409) {
        // Already exists — pick it transparently
        const existing = (e.details as any)?.existing as Location | undefined;
        if (existing?.locationId) { pick(existing); return; }
      }
      setModalError(e instanceof ApiError ? e.message : 'Failed to add location');
    } finally {
      setModalSaving(false);
    }
  }

  function pick(loc: Location) {
    onChange(loc.locationId);
    setSelectedName(loc.name);
    setModal(null);
    close();
  }

  function handleKey(e: React.KeyboardEvent) {
    const local = localResults;
    const google = googleResults;
    const total = local.length + google.length;
    if (e.key === 'ArrowDown') { e.preventDefault(); setActiveIdx((i) => Math.min(i + 1, total - 1)); }
    else if (e.key === 'ArrowUp') { e.preventDefault(); setActiveIdx((i) => Math.max(i - 1, 0)); }
    else if (e.key === 'Escape') { close(); }
    else if (e.key === 'Enter' && activeIdx >= 0) {
      e.preventDefault();
      if (activeIdx < local.length) {
        const l = local[activeIdx];
        if (l) pickLocal(l);
      } else {
        const p = google[activeIdx - local.length];
        if (p) openModal(p);
      }
    }
  }

  const isOpen = mode !== 'closed';
  const inputValue = isOpen ? query : (selectedName || '');

  return (
    <>
      <div ref={containerRef} className="relative">
        <Label className="mb-1.5 block text-sm font-medium text-ink">{label}</Label>
        <Input
          value={inputValue}
          onChange={(e) => { setQuery(e.target.value); setActiveIdx(-1); }}
          onFocus={() => { if (!isOpen) open(); }}
          onKeyDown={handleKey}
          placeholder={placeholder ?? `Search ${label.toLowerCase()}…`}
          autoComplete="off"
          className={error ? 'border-rust focus-visible:ring-rust' : ''}
        />
        {error && <p className="mt-1 text-xs text-rust">{error}</p>}

        {isOpen && (
          <div className="absolute z-50 mt-1 w-full animate-fade-in overflow-hidden rounded-md border border-paper-300 bg-paper-50 shadow-lg">
            {/* Local matches first */}
            {localResults.length > 0 && (
              <>
                <p className="px-3 pt-2 text-[10px] uppercase tracking-wide text-ink-300">Saved locations</p>
                {localResults.map((loc, i) => (
                  <button
                    key={loc.locationId}
                    onMouseDown={() => pickLocal(loc)}
                    className={`flex w-full flex-col px-3 py-2 text-left transition-colors hover:bg-paper-200 ${i === activeIdx ? 'bg-paper-200' : ''}`}
                  >
                    <span className="text-sm font-medium text-ink">{loc.name}</span>
                    <span className="text-xs text-ink-300 capitalize">
                      {loc.locationType}{loc.locality ? ` · ${loc.locality.name}` : ''}
                    </span>
                  </button>
                ))}
              </>
            )}

            {/* Google fallback when local has nothing for this query */}
            {localResults.length === 0 && debouncedQuery.length >= MIN_CHARS_FOR_GOOGLE && (
              <>
                <p className="border-t border-paper-200 px-3 pt-2 text-[10px] uppercase tracking-wide text-ink-300">
                  From Google Maps
                </p>
                {googleLoading && (
                  <p className="px-3 py-2 text-xs text-ink-300">Searching Google…</p>
                )}
                {!googleLoading && googleResults.length === 0 && (
                  <p className="px-3 py-2 text-xs text-ink-300">No results</p>
                )}
                {googleResults.map((pred, i) => {
                  const idx = localResults.length + i;
                  return (
                    <button
                      key={pred.placeId}
                      onMouseDown={() => openModal(pred)}
                      className={`flex w-full flex-col px-3 py-2 text-left transition-colors hover:bg-paper-200 ${idx === activeIdx ? 'bg-paper-200' : ''}`}
                    >
                      <span className="text-sm font-medium text-ink">{pred.primaryText}</span>
                      <span className="text-xs text-ink-300">{pred.secondaryText}</span>
                    </button>
                  );
                })}
                <p className="border-t border-paper-200 px-3 py-1 text-right text-[10px] text-ink-200">
                  Powered by Google
                </p>
              </>
            )}

            {/* Empty / hint state */}
            {localResults.length === 0 && debouncedQuery.length < MIN_CHARS_FOR_GOOGLE && (
              <p className="px-3 py-2 text-xs text-ink-300">
                {debouncedQuery.length === 0
                  ? 'Type to search saved locations, or 3+ chars to fetch from Google Maps'
                  : 'Keep typing…'}
              </p>
            )}
          </div>
        )}
      </div>

      {/* Add location modal */}
      {modal && (
        <div className="fixed inset-0 z-[60] flex items-end justify-center bg-black/40 sm:items-center">
          <div className="w-full max-w-sm rounded-t-2xl bg-paper px-6 pb-8 pt-6 shadow-xl sm:rounded-xl">
            <h3 className="mb-1 font-display text-lg font-semibold text-ink">Add location</h3>
            <p className="mb-4 text-xs text-ink-300">{modal.secondaryText}</p>

            <div className="space-y-4">
              <div>
                <Label className="mb-1 block text-sm">Display name</Label>
                <Input
                  value={modalName}
                  onChange={(e) => setModalName(e.target.value)}
                  placeholder="e.g. Walkeshwar Jain Upashray"
                />
              </div>

              <div>
                <Label className="mb-1 block text-sm">Type</Label>
                <select
                  value={modalType}
                  onChange={(e) => setModalType(e.target.value)}
                  className="w-full rounded-md border border-paper-300 bg-white px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-saffron"
                >
                  {LOCATION_TYPES.map((t) => (
                    <option key={t} value={t}>{t.charAt(0).toUpperCase() + t.slice(1)}</option>
                  ))}
                </select>
              </div>

              <div>
                <Label className="mb-1 block text-sm">Locality <span className="text-ink-300">(optional)</span></Label>
                <select
                  value={modalLocality ?? ''}
                  onChange={(e) => setModalLocality(e.target.value ? Number(e.target.value) : null)}
                  className="w-full rounded-md border border-paper-300 bg-white px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-saffron"
                >
                  <option value="">— none —</option>
                  {localities.map((l) => (
                    <option key={l.localityId} value={l.localityId}>{l.name}</option>
                  ))}
                </select>
              </div>

              {modalError && (
                <p className="text-sm text-rust">{modalError}</p>
              )}
            </div>

            <div className="mt-6 flex gap-3">
              <Button
                variant="outline"
                className="flex-1"
                onClick={() => setModal(null)}
                disabled={modalSaving}
              >
                Cancel
              </Button>
              <Button
                className="flex-1"
                onClick={submitModal}
                disabled={modalSaving || !modalName.trim()}
              >
                {modalSaving ? 'Saving…' : 'Add Location'}
              </Button>
            </div>
          </div>
        </div>
      )}
    </>
  );
}
