/* FormControls.jsx — shared inputs:
   - AviSelect: dropdown with the standard Dutch AVI levels
   - NameAutocomplete: text input that suggests matching kid names as you type
                        (handles single-value or comma-separated lists) */
(function () {
  const LucideIcon = window.LucideIcon;
  const { useState, useRef, useEffect } = React;
  const { lc } = window.AppData;

  // Standard Dutch (Cito) AVI levels in order
  const AVI_LEVELS = ['Start', 'M3', 'E3', 'M4', 'E4', 'M5', 'E5', 'M6', 'E6', 'M7', 'E7', 'Plus'];

  function AviSelect({ value, onChange, className }) {
    return React.createElement('select', {
      className: 'avi-select ' + (className || ''),
      value: value || '',
      onChange: (e) => onChange(e.target.value),
    },
      React.createElement('option', { value: '' }, '—'),
      AVI_LEVELS.map(lv => React.createElement('option', { key: lv, value: lv }, lv))
    );
  }

  // Split a comma-separated string into tokens + return active-token info
  function splitTokens(str) {
    // Preserve trailing empty token so "Emma, " offers fresh suggestions
    const parts = str.split(',');
    return parts.map(p => p.trim());
  }

  function NameAutocomplete({
    value, onChange, names, max, placeholder, className, excludeSelf, autoFocus, multi,
  }) {
    const [open, setOpen] = useState(false);
    const [hover, setHover] = useState(0);
    const [pos, setPos] = useState(null); // {left, top, width} for portal-ish placement
    const inputRef = useRef(null);
    const ddRef = useRef(null);

    const str = value || '';
    const tokens = multi ? splitTokens(str) : [str];
    const active = tokens[tokens.length - 1] || '';
    const selectedLower = new Set(tokens.slice(0, multi ? tokens.length - 1 : 0).map(lc));

    const fullList = Array.isArray(names) ? names : [];
    const matches = fullList
      .filter(n => {
        if (!n) return false;
        if (excludeSelf && lc(n) === lc(excludeSelf)) return false;
        if (selectedLower.has(lc(n))) return false;
        if (!active) return true;
        return lc(n).includes(lc(active));
      })
      .slice(0, 8);

    // measure input → place dropdown (fixed) so it escapes any overflow:auto
    const measure = () => {
      const el = inputRef.current;
      if (!el) return;
      const r = el.getBoundingClientRect();
      setPos({ left: r.left, top: r.bottom + 4, width: r.width });
    };
    useEffect(() => {
      if (!open) return;
      measure();
      const handle = () => measure();
      window.addEventListener('resize', handle);
      window.addEventListener('scroll', handle, true);
      return () => {
        window.removeEventListener('resize', handle);
        window.removeEventListener('scroll', handle, true);
      };
    }, [open]);

    // close when click outside
    useEffect(() => {
      if (!open) return;
      const onDown = (e) => {
        if (inputRef.current && inputRef.current.contains(e.target)) return;
        if (ddRef.current && ddRef.current.contains(e.target)) return;
        setOpen(false);
      };
      document.addEventListener('pointerdown', onDown, true);
      return () => document.removeEventListener('pointerdown', onDown, true);
    }, [open]);

    const commit = (chosen) => {
      let next;
      if (multi) {
        const before = tokens.slice(0, -1);
        const list = [...before, chosen].filter(Boolean);
        const capped = (typeof max === 'number') ? list.slice(0, max) : list;
        next = capped.join(', ') + ((typeof max !== 'number' || capped.length < max) ? ', ' : '');
      } else {
        next = chosen;
      }
      onChange(next);
      setOpen(false);
      setHover(0);
      setTimeout(() => {
        if (inputRef.current) {
          inputRef.current.focus();
          const end = inputRef.current.value.length;
          inputRef.current.setSelectionRange(end, end);
        }
      }, 0);
    };

    const onKey = (e) => {
      if (e.key === 'ArrowDown') { e.preventDefault(); setOpen(true); setHover(h => Math.min((matches.length || 1) - 1, h + 1)); }
      else if (e.key === 'ArrowUp') { e.preventDefault(); setHover(h => Math.max(0, h - 1)); }
      else if (e.key === 'Enter') {
        if (open && matches[hover]) { e.preventDefault(); commit(matches[hover]); }
      } else if (e.key === 'Escape') { setOpen(false); }
    };

    const dropdown = open && matches.length > 0 && pos ? React.createElement('div', {
      ref: ddRef,
      className: 'autocomplete-dd',
      style: { left: pos.left, top: pos.top, width: Math.max(pos.width, 180) },
      onPointerDown: (e) => e.preventDefault(),
    },
      matches.map((n, i) => React.createElement('div', {
        key: n,
        className: 'ac-item' + (i === hover ? ' on' : ''),
        onClick: () => commit(n),
        onMouseEnter: () => setHover(i),
      },
        React.createElement(LucideIcon, { name: 'User', size: 13, strokeWidth: 2.2 }),
        React.createElement('span', { className: 'ac-name' }, n)))
    ) : null;

    return React.createElement(React.Fragment, null,
      React.createElement('input', {
        ref: inputRef,
        type: 'text',
        className: 'autocomplete-input ' + (className || ''),
        value: str,
        placeholder,
        autoFocus,
        onChange: (e) => { onChange(e.target.value); setOpen(true); setHover(0); },
        onFocus: () => { setOpen(true); measure(); },
        onClick: () => { setOpen(true); measure(); },
        onKeyDown: onKey,
      }),
      dropdown && ReactDOM.createPortal
        ? ReactDOM.createPortal(dropdown, document.body)
        : dropdown
    );
  }

  window.AviSelect = AviSelect;
  window.NameAutocomplete = NameAutocomplete;
  window.AVI_LEVELS = AVI_LEVELS;
})();
