/* OnSumn — VenuePicker (Phase 4.15 / ship #2)
   Google Places (New) Autocomplete + Place Details, browser-only.
   API key read from window.GOOGLE_PLACES_API_KEY. Key is HTTP-referrer-locked
   to onsumn.com + localhost, so exposing it in client JS is safe by design.

   Usage:
     <VenuePicker
       onSelect={(venue) => { ... }}
       placeholder="search for a venue…"
       initialValue=""
     />
   onSelect receives: { place_id, name, address, lat, lng, types[] } */

const VENUE_PICKER_PLACES_HOST = 'https://places.googleapis.com/v1';
const VENUE_PICKER_FIELD_MASK = 'id,displayName,formattedAddress,location,types';
const VENUE_PICKER_DEBOUNCE_MS = 250;
// Bay Area bounding box — 9 counties (Marin/Sonoma/Napa/Solano in N,
// down through SF/SM/SCl in S, plus Alameda/CC east).
// Circle radius caps at 50km per Places API, so we use a rectangle.
const VENUE_PICKER_BAY_RECT = {
  low:  { latitude: 36.85, longitude: -122.55 },  // SW: just south of Santa Cruz / west of Half Moon Bay
  high: { latitude: 38.55, longitude: -121.55 },  // NE: Napa / Fairfield area
};

function venuePickerNewSession() {
  if (typeof crypto !== 'undefined' && crypto.randomUUID) return crypto.randomUUID();
  // Fallback: timestamp + random hex (still under 36 chars)
  return Date.now().toString(16) + '-' + Math.random().toString(16).slice(2, 14);
}

function VenuePicker({ onSelect, placeholder = 'search venue…', initialValue = '', autoFocus = false }) {
  const apiKey = (typeof window !== 'undefined' && window.GOOGLE_PLACES_API_KEY) || '';
  const [input, setInput] = React.useState(initialValue);
  const [suggestions, setSuggestions] = React.useState([]);
  const [open, setOpen] = React.useState(false);
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [highlight, setHighlight] = React.useState(0);
  const [selected, setSelected] = React.useState(null);

  const sessionRef = React.useRef(venuePickerNewSession());
  const abortRef = React.useRef(null);
  const debounceRef = React.useRef(null);
  const containerRef = React.useRef(null);
  const inputRef = React.useRef(null);

  React.useEffect(() => {
    if (autoFocus && inputRef.current) inputRef.current.focus();
  }, [autoFocus]);

  // Close on outside click
  React.useEffect(() => {
    function onDocClick(e) {
      if (containerRef.current && !containerRef.current.contains(e.target)) setOpen(false);
    }
    document.addEventListener('mousedown', onDocClick);
    return () => document.removeEventListener('mousedown', onDocClick);
  }, []);

  // Cleanup any in-flight fetch on unmount
  React.useEffect(() => {
    return () => {
      if (abortRef.current) abortRef.current.abort();
      if (debounceRef.current) clearTimeout(debounceRef.current);
    };
  }, []);

  function runAutocomplete(query) {
    if (!apiKey) {
      setError('GOOGLE_PLACES_API_KEY not set on window');
      return;
    }
    if (abortRef.current) abortRef.current.abort();
    const ctrl = new AbortController();
    abortRef.current = ctrl;
    setLoading(true);
    setError(null);

    fetch(`${VENUE_PICKER_PLACES_HOST}/places:autocomplete`, {
      method: 'POST',
      signal: ctrl.signal,
      headers: {
        'Content-Type': 'application/json',
        'X-Goog-Api-Key': apiKey,
      },
      body: JSON.stringify({
        input: query,
        sessionToken: sessionRef.current,
        locationBias: {
          rectangle: VENUE_PICKER_BAY_RECT,
        },
      }),
    })
      .then((r) => r.json().then((j) => ({ ok: r.ok, status: r.status, body: j })))
      .then(({ ok, status, body }) => {
        if (ctrl.signal.aborted) return;
        if (!ok) {
          setError(body?.error?.message || `Places error (${status})`);
          setSuggestions([]);
          setOpen(true);
          return;
        }
        const list = (body.suggestions || [])
          .map((s) => s.placePrediction)
          .filter(Boolean);
        setSuggestions(list);
        setHighlight(0);
        setOpen(true);
      })
      .catch((err) => {
        if (err.name === 'AbortError') return;
        setError(err.message || 'Network error');
      })
      .finally(() => {
        if (!ctrl.signal.aborted) setLoading(false);
      });
  }

  function onInputChange(e) {
    const v = e.target.value;
    setInput(v);
    setSelected(null);
    if (debounceRef.current) clearTimeout(debounceRef.current);
    if (v.trim().length < 2) {
      setSuggestions([]);
      setOpen(false);
      setLoading(false);
      if (abortRef.current) abortRef.current.abort();
      return;
    }
    debounceRef.current = setTimeout(() => runAutocomplete(v.trim()), VENUE_PICKER_DEBOUNCE_MS);
  }

  function pick(prediction) {
    if (!apiKey) return;
    setLoading(true);
    setError(null);
    fetch(`${VENUE_PICKER_PLACES_HOST}/places/${prediction.placeId}?sessionToken=${sessionRef.current}`, {
      method: 'GET',
      headers: {
        'X-Goog-Api-Key': apiKey,
        'X-Goog-FieldMask': VENUE_PICKER_FIELD_MASK,
      },
    })
      .then((r) => r.json().then((j) => ({ ok: r.ok, status: r.status, body: j })))
      .then(({ ok, status, body }) => {
        if (!ok) {
          setError(body?.error?.message || `Place Details error (${status})`);
          return;
        }
        const resolved = {
          place_id: body.id,
          name: body.displayName?.text || prediction.structuredFormat?.mainText?.text || '',
          address: body.formattedAddress || '',
          lat: body.location?.latitude,
          lng: body.location?.longitude,
          types: body.types || [],
        };
        setSelected(resolved);
        setInput(resolved.name);
        setOpen(false);
        sessionRef.current = venuePickerNewSession(); // Rotate session after a successful pick
        if (onSelect) onSelect(resolved);
      })
      .catch((err) => setError(err.message || 'Network error'))
      .finally(() => setLoading(false));
  }

  function clear() {
    setInput('');
    setSelected(null);
    setSuggestions([]);
    setOpen(false);
    setError(null);
    if (onSelect) onSelect(null);
    if (inputRef.current) inputRef.current.focus();
  }

  function onKeyDown(e) {
    if (!open) {
      if (e.key === 'ArrowDown' && suggestions.length) { setOpen(true); e.preventDefault(); }
      return;
    }
    if (e.key === 'ArrowDown') {
      setHighlight((h) => Math.min(h + 1, suggestions.length - 1));
      e.preventDefault();
    } else if (e.key === 'ArrowUp') {
      setHighlight((h) => Math.max(h - 1, 0));
      e.preventDefault();
    } else if (e.key === 'Enter') {
      if (suggestions[highlight]) { pick(suggestions[highlight]); e.preventDefault(); }
    } else if (e.key === 'Escape') {
      setOpen(false);
    }
  }

  const accent = '#D57800';
  const styles = {
    container: { position: 'relative', width: '100%' },
    inputWrap: {
      position: 'relative',
      display: 'flex',
      alignItems: 'center',
      gap: 8,
      padding: '12px 14px',
      background: 'rgba(255,255,255,0.04)',
      border: `1px solid ${selected ? accent : 'rgba(255,255,255,0.12)'}`,
      borderRadius: 10,
      transition: 'border-color 140ms ease',
    },
    input: {
      flex: 1,
      background: 'transparent',
      border: 'none',
      outline: 'none',
      color: '#F5F2EE',
      fontSize: 16,
      fontFamily: 'inherit',
      padding: 0,
    },
    clearBtn: {
      background: 'transparent',
      border: 'none',
      color: 'rgba(255,255,255,0.55)',
      cursor: 'pointer',
      padding: 4,
      display: 'flex',
      alignItems: 'center',
      fontSize: 18,
      lineHeight: 1,
    },
    dropdown: {
      position: 'absolute',
      top: 'calc(100% + 4px)',
      left: 0,
      right: 0,
      background: '#1A1815',
      border: '1px solid rgba(255,255,255,0.10)',
      borderRadius: 10,
      maxHeight: 280,
      overflowY: 'auto',
      zIndex: 50,
      boxShadow: '0 10px 30px rgba(0,0,0,0.45)',
    },
    row: (hi) => ({
      padding: '10px 14px',
      cursor: 'pointer',
      borderBottom: '1px solid rgba(255,255,255,0.04)',
      background: hi ? 'rgba(213,120,0,0.10)' : 'transparent',
      transition: 'background 100ms ease',
    }),
    rowMain: { color: '#F5F2EE', fontSize: 15, fontWeight: 500 },
    rowSecondary: { color: 'rgba(245,242,238,0.55)', fontSize: 13, marginTop: 2 },
    empty: { padding: '14px', color: 'rgba(255,255,255,0.45)', fontSize: 13, fontStyle: 'italic' },
    error: { padding: '14px', color: '#FF6B6B', fontSize: 13 },
    loadingDot: {
      width: 6, height: 6, borderRadius: '50%', background: accent,
      animation: 'venuePickerPulse 900ms ease-in-out infinite',
    },
    selectedTag: {
      display: 'inline-block',
      fontSize: 11,
      color: accent,
      letterSpacing: 0.5,
      textTransform: 'uppercase',
      marginRight: 6,
      fontFamily: 'JetBrains Mono, ui-monospace, monospace',
    },
  };

  // Inject keyframes once
  React.useEffect(() => {
    if (document.getElementById('venue-picker-styles')) return;
    const s = document.createElement('style');
    s.id = 'venue-picker-styles';
    s.textContent = `@keyframes venuePickerPulse { 0%,100% { opacity: 0.35 } 50% { opacity: 1 } }`;
    document.head.appendChild(s);
  }, []);

  return (
    <div ref={containerRef} style={styles.container}>
      <div style={styles.inputWrap}>
        {selected ? <span style={styles.selectedTag}>places</span> : null}
        <input
          ref={inputRef}
          type="text"
          value={input}
          onChange={onInputChange}
          onKeyDown={onKeyDown}
          onFocus={() => { if (suggestions.length) setOpen(true); }}
          placeholder={placeholder}
          style={styles.input}
          autoComplete="off"
          spellCheck="false"
        />
        {loading ? <div style={styles.loadingDot} /> : null}
        {input && !loading ? (
          <button type="button" onClick={clear} style={styles.clearBtn} aria-label="clear venue">×</button>
        ) : null}
      </div>

      {open ? (
        <div style={styles.dropdown}>
          {error ? (
            <div style={styles.error}>{error}</div>
          ) : suggestions.length === 0 && !loading ? (
            <div style={styles.empty}>no matches — try a different name</div>
          ) : (
            suggestions.map((s, i) => (
              <div
                key={s.placeId}
                style={styles.row(i === highlight)}
                onMouseEnter={() => setHighlight(i)}
                onMouseDown={(e) => { e.preventDefault(); pick(s); }}
              >
                <div style={styles.rowMain}>{s.structuredFormat?.mainText?.text || s.text?.text}</div>
                <div style={styles.rowSecondary}>{s.structuredFormat?.secondaryText?.text || ''}</div>
              </div>
            ))
          )}
        </div>
      ) : null}
    </div>
  );
}
