/* global React, Icon */
const { useState: useStateSR, useEffect: useEffectSR, useRef: useRefSR, useMemo: useMemoSR } = React;

// ---- mock corpus -----------------------------------------------------------
const SEARCH_CORPUS = [
  // Active (Team 2 ward 1A)
  { kind: 'patient', bed: '1A-01', name: 'Turner, Margaret',  urn: '179347', dob: '27/10/1938', ward: '1A', status: 'active', dischargedOn: null,        flag: 'review' },
  { kind: 'patient', bed: '1A-02', name: 'Kovacs, Stefan',    urn: '184902', dob: '14/03/1957', ward: '1A', status: 'active', dischargedOn: null,        flag: 'draft' },
  { kind: 'patient', bed: '1A-03', name: 'Nguyen, Phuong',    urn: '192551', dob: '02/11/1962', ward: '1A', status: 'active', dischargedOn: null },
  { kind: 'patient', bed: '1A-05', name: 'Walsh, Brendan',    urn: '201338', dob: '08/09/1971', ward: '1A', status: 'active', dischargedOn: null,        flag: 'draft' },
  { kind: 'patient', bed: '1A-06', name: 'Singh, Rajesh',     urn: '188776', dob: '30/12/1955', ward: '1A', status: 'active', dischargedOn: null },
  // Inactive – recent
  { kind: 'patient', bed: '—',     name: 'Patel, Anjali',     urn: '156402', dob: '11/04/1944', ward: '1A', status: 'inactive', dischargedOn: '2026-02-13' },
  { kind: 'patient', bed: '—',     name: 'Brooks, Jonathan',  urn: '173819', dob: '19/08/1962', ward: '1A', status: 'inactive', dischargedOn: '2026-02-11' },
  { kind: 'patient', bed: '—',     name: 'Tanaka, Hiroshi',   urn: '198255', dob: '03/02/1958', ward: '1A', status: 'inactive', dischargedOn: '2026-02-10' },
  { kind: 'patient', bed: '—',     name: 'Cohen, Rebecca',    urn: '149887', dob: '22/03/1947', ward: '1B', status: 'inactive', dischargedOn: '2026-01-29' },
  { kind: 'patient', bed: '—',     name: 'Hamid, Sami',       urn: '208112', dob: '17/07/1976', ward: '1A', status: 'inactive', dischargedOn: '2026-01-22' },
  // Cross-ward
  { kind: 'patient', bed: '2C-04', name: 'Okafor, Nneka',     urn: '212904', dob: '12/05/1981', ward: '2C', status: 'active', dischargedOn: null },
  { kind: 'patient', bed: '3B-12', name: 'Davies, Owen',      urn: '177013', dob: '05/06/1953', ward: '3B', status: 'active', dischargedOn: null },
  // Wards
  { kind: 'ward', label: 'Ward 1A',  detail: 'General Medicine · 24 beds · Team 2', ward: '1A' },
  { kind: 'ward', label: 'Ward 1B',  detail: 'General Medicine · 22 beds · Team 1', ward: '1B' },
  { kind: 'ward', label: 'Ward 2C',  detail: 'Cardiology · 18 beds · Team 4',       ward: '2C' },
  { kind: 'ward', label: 'Ward 3B',  detail: 'Respiratory · 20 beds · Team 3',      ward: '3B' },
];

// ---- query parsing ---------------------------------------------------------
// Tokens: key:value (with quoting). Recognised keys → typed filter chips,
// everything else folds into freeText for fuzzy matching.
const TYPED_KEYS = new Set(['ward', 'urn', 'bed', 'name', 'before', 'after', 'status', 'team']);

function parseQuery(q) {
  const tokens = [];
  const free = [];
  // crude tokenizer: split on whitespace, preserve "quoted phrases"
  const parts = (q.match(/"[^"]*"|\S+/g) || []).map(t => t.replace(/^"|"$/g, ''));
  for (const p of parts) {
    const m = p.match(/^([a-z]+):(.*)$/i);
    if (m && TYPED_KEYS.has(m[1].toLowerCase()) && m[2].length) {
      tokens.push({ key: m[1].toLowerCase(), value: m[2] });
    } else {
      free.push(p);
    }
  }
  return { tokens, freeText: free.join(' ').trim().toLowerCase() };
}

function matchesQuery(item, parsed) {
  const { tokens, freeText } = parsed;
  for (const t of tokens) {
    const v = t.value.toLowerCase();
    if (t.key === 'ward'   && (item.ward || '').toLowerCase() !== v) return false;
    if (t.key === 'urn'    && !(item.urn || '').includes(v)) return false;
    if (t.key === 'bed'    && !(item.bed || '').toLowerCase().includes(v)) return false;
    if (t.key === 'name'   && !(item.name || item.label || '').toLowerCase().includes(v)) return false;
    if (t.key === 'status' && (item.status || '').toLowerCase() !== v) return false;
    if (t.key === 'team'   && !((item.detail || '').toLowerCase().includes('team ' + v))) return false;
    if (t.key === 'before' && item.dischargedOn && item.dischargedOn >= v) return false;
    if (t.key === 'before' && !item.dischargedOn && v) {/* no discharge → exclude from before: */ return false;}
    if (t.key === 'after'  && item.dischargedOn && item.dischargedOn <= v) return false;
    if (t.key === 'after'  && !item.dischargedOn && v) return false;
  }
  if (freeText) {
    const hay = [item.name, item.label, item.urn, item.bed, item.detail, item.ward]
      .filter(Boolean).join(' ').toLowerCase();
    if (!hay.includes(freeText)) return false;
  }
  return true;
}

// ---- chip ------------------------------------------------------------------
function FilterChip({ k, v, onRemove }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 4,
      background: 'var(--primary-muted)', color: 'var(--primary)',
      border: '1px solid #d6e4dc', borderRadius: 4, padding: '1px 4px 1px 6px',
      fontSize: 11, fontFamily: 'var(--font-mono)', whiteSpace: 'nowrap', flexShrink: 0
    }}>
      <span style={{ opacity: 0.65 }}>{k}:</span>
      <span style={{ fontWeight: 600 }}>{v}</span>
      <button onClick={onRemove} aria-label={`Remove ${k}:${v}`}
        style={{ background: 'transparent', border: 0, color: 'var(--primary)', cursor: 'pointer', padding: 0, display: 'flex', alignItems: 'center' }}>
        <Icon name="x" size={11} />
      </button>
    </span>
  );
}

// ---- result row ------------------------------------------------------------
function ResultRow({ item, active, onSelect }) {
  return (
    <button onClick={onSelect}
      onMouseEnter={(e) => { if (!active) e.currentTarget.style.background = 'var(--sage-50)'; }}
      onMouseLeave={(e) => { if (!active) e.currentTarget.style.background = 'transparent'; }}
      style={{
        background: active ? 'var(--primary-muted)' : 'transparent', border: 0,
        textAlign: 'left', padding: '6px 10px', cursor: 'pointer',
        display: 'flex', alignItems: 'center', gap: 10, width: '100%',
        fontFamily: 'var(--font-sans)'
      }}>
      {item.kind === 'patient' ? (
        <>
          <span style={{
            fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--sage-500)',
            background: 'var(--sage-100)', borderRadius: 3, padding: '1px 5px',
            minWidth: 44, textAlign: 'center', flexShrink: 0
          }}>{item.bed}</span>
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--sage-800)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{item.name}</div>
            <div style={{ fontSize: 10.5, color: 'var(--sage-500)', fontFamily: 'var(--font-mono)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
              URN {item.urn} · DOB {item.dob} · Ward {item.ward}{item.dischargedOn ? ` · disch ${item.dischargedOn}` : ''}
            </div>
          </div>
          {item.flag === 'review' && <span title="Needs review" style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--primary)' }} />}
          {item.flag === 'draft'  && <span title="Draft note" style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--sage-300)' }} />}
        </>
      ) : (
        <>
          <span style={{ width: 22, height: 22, borderRadius: 4, background: 'var(--sage-100)', color: 'var(--sage-600)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
            <Icon name="archive" size={12} />
          </span>
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--sage-800)' }}>{item.label}</div>
            <div style={{ fontSize: 10.5, color: 'var(--sage-500)' }}>{item.detail}</div>
          </div>
        </>
      )}
    </button>
  );
}

// ---- main searchbar --------------------------------------------------------
function SearchBar() {
  const [focused, setFocused] = useStateSR(false);
  const [q, setQ] = useStateSR('');
  const [activeIdx, setActiveIdx] = useStateSR(0);
  const inputRef = useRefSR(null);
  const wrapRef = useRefSR(null);

  // ⌘K / Ctrl-K to focus, Esc to dismiss
  useEffectSR(() => {
    function onKey(e) {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
        e.preventDefault();
        inputRef.current?.focus();
      } else if (e.key === 'Escape' && focused) {
        inputRef.current?.blur();
        setFocused(false);
      }
    }
    function onFocusEvent() {
      inputRef.current?.focus();
    }
    window.addEventListener('keydown', onKey);
    window.addEventListener('focusGlobalSearch', onFocusEvent);
    return () => {
      window.removeEventListener('keydown', onKey);
      window.removeEventListener('focusGlobalSearch', onFocusEvent);
    };
  }, [focused]);

  // close on outside click
  useEffectSR(() => {
    if (!focused) return;
    function onDown(e) {
      if (wrapRef.current && !wrapRef.current.contains(e.target)) setFocused(false);
    }
    window.addEventListener('mousedown', onDown);
    return () => window.removeEventListener('mousedown', onDown);
  }, [focused]);

  const parsed = useMemoSR(() => parseQuery(q), [q]);
  const results = useMemoSR(() => {
    if (!q.trim()) return [];
    return SEARCH_CORPUS.filter(it => matchesQuery(it, parsed));
  }, [q, parsed]);

  const grouped = useMemoSR(() => {
    const g = { active: [], inactive: [], ward: [] };
    for (const r of results) {
      if (r.kind === 'ward') g.ward.push(r);
      else if (r.status === 'active') g.active.push(r);
      else g.inactive.push(r);
    }
    return g;
  }, [results]);

  const flatResults = useMemoSR(
    () => [...grouped.active, ...grouped.inactive, ...grouped.ward],
    [grouped]
  );

  function removeToken(idx) {
    const parts = (q.match(/"[^"]*"|\S+/g) || []);
    let typedSeen = -1;
    const next = parts.filter(p => {
      const m = p.match(/^([a-z]+):/i);
      if (m && TYPED_KEYS.has(m[1].toLowerCase())) {
        typedSeen += 1;
        return typedSeen !== idx;
      }
      return true;
    }).join(' ');
    setQ(next.trim() ? next + (next.endsWith(' ') ? '' : ' ') : '');
    inputRef.current?.focus();
  }

  function onKeyDown(e) {
    if (e.key === 'ArrowDown') { e.preventDefault(); setActiveIdx(i => Math.min(flatResults.length - 1, i + 1)); }
    else if (e.key === 'ArrowUp')   { e.preventDefault(); setActiveIdx(i => Math.max(0, i - 1)); }
    else if (e.key === 'Enter' && flatResults[activeIdx]) { /* mock select */ setQ(''); inputRef.current?.blur(); setFocused(false); }
    else if (e.key === 'Backspace' && q === '' && parsed.tokens.length) {
      removeToken(parsed.tokens.length - 1);
    }
  }

  const expanded = focused;

  return (
    <div ref={wrapRef} style={{ position: 'relative' }}>
      <div style={{
        display: 'flex', alignItems: 'center', gap: 6,
        background: expanded ? '#fff' : 'var(--sage-100)',
        border: expanded ? '1px solid var(--primary)' : '1px solid transparent',
        boxShadow: expanded ? '0 0 0 3px var(--primary-muted)' : 'none',
        borderRadius: 6, padding: '4px 8px',
        width: expanded ? 520 : 200,
        transition: 'width 200ms cubic-bezier(.2,.8,.2,1), background 120ms, border-color 120ms, box-shadow 120ms',
        cursor: 'text'
      }} onClick={() => inputRef.current?.focus()}>
        <Icon name="search" size={13} />
        {/* token chips */}
        {parsed.tokens.length > 0 && expanded && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0, maxWidth: '60%', overflow: 'hidden' }}>
            {parsed.tokens.map((t, i) => <FilterChip key={i} k={t.key} v={t.value} onRemove={() => removeToken(i)} />)}
          </div>
        )}
        <input
          ref={inputRef}
          value={q}
          onChange={(e) => { setQ(e.target.value); setActiveIdx(0); }}
          onFocus={() => setFocused(true)}
          onKeyDown={onKeyDown}
          placeholder={expanded ? 'patient, urn, ward:1A, before:2026-02-10…' : 'Search…'}
          style={{
            flex: 1, minWidth: 40, border: 0, outline: 'none', background: 'transparent',
            fontSize: 12, fontFamily: 'var(--font-sans)', color: 'var(--sage-800)'
          }}
        />
        {!expanded && (
          <span style={{ marginLeft: 'auto', padding: '1px 5px', background: '#fff', border: '1px solid var(--sage-200)', borderRadius: 3, fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--sage-500)', flexShrink: 0 }}>⌘K</span>
        )}
        {expanded && q && (
          <button onClick={(e) => { e.stopPropagation(); setQ(''); inputRef.current?.focus(); }}
            aria-label="Clear" style={{ background: 'transparent', border: 0, color: 'var(--sage-500)', cursor: 'pointer', padding: 2, display: 'flex' }}>
            <Icon name="x" size={13} />
          </button>
        )}
      </div>

      {expanded && (
        <div style={{
          position: 'absolute', top: 'calc(100% + 6px)', right: 0, width: 520,
          background: '#fff', border: '1px solid var(--sage-200)', borderRadius: 8,
          boxShadow: '0 12px 32px rgba(15, 33, 27, 0.14), 0 2px 6px rgba(15, 33, 27, 0.06)',
          maxHeight: 440, overflowY: 'auto', zIndex: 30, fontFamily: 'var(--font-sans)'
        }}>
          {q.trim() === '' ? (
            <SearchTips />
          ) : flatResults.length === 0 ? (
            <div style={{ padding: 16, fontSize: 12, color: 'var(--sage-500)' }}>
              No matches. Try a different term or remove a filter.
            </div>
          ) : (
            <>
              <ResultGroup title={`Active patients · ${grouped.active.length}`} items={grouped.active}
                offset={0} activeIdx={activeIdx} onSelect={() => { setQ(''); setFocused(false); }} />
              <ResultGroup title={`Inactive patients · ${grouped.inactive.length}`} items={grouped.inactive}
                offset={grouped.active.length} activeIdx={activeIdx} onSelect={() => { setQ(''); setFocused(false); }} />
              <ResultGroup title={`Wards · ${grouped.ward.length}`} items={grouped.ward}
                offset={grouped.active.length + grouped.inactive.length} activeIdx={activeIdx} onSelect={() => { setQ(''); setFocused(false); }} />
              <div style={{
                display: 'flex', alignItems: 'center', gap: 12,
                padding: '6px 10px', borderTop: '1px solid var(--sage-100)',
                fontSize: 10.5, color: 'var(--sage-500)', fontFamily: 'var(--font-mono)'
              }}>
                <span>↑↓ nav</span><span>↵ open</span><span>esc close</span>
                <span style={{ marginLeft: 'auto' }}>{flatResults.length} result{flatResults.length === 1 ? '' : 's'}</span>
              </div>
            </>
          )}
        </div>
      )}
    </div>
  );
}

function ResultGroup({ title, items, offset, activeIdx, onSelect }) {
  if (!items.length) return null;
  return (
    <div>
      <div style={{
        padding: '6px 10px 4px 10px', fontSize: 9.5, fontWeight: 600,
        color: 'var(--sage-500)', textTransform: 'uppercase', letterSpacing: '0.06em'
      }}>{title}</div>
      {items.map((it, i) => (
        <ResultRow key={i} item={it} active={offset + i === activeIdx} onSelect={onSelect} />
      ))}
    </div>
  );
}

function SearchTips() {
  const examples = [
    ['ward:1A',           'Limit to a specific ward'],
    ['urn:179347',        'Look up by URN'],
    ['before:2026-02-10', 'Discharged before a date'],
    ['after:2026-01-01',  'Discharged after a date'],
    ['status:inactive',   'Filter by status'],
    ['turner ward:1A',    'Combine free text + filters'],
  ];
  return (
    <div style={{ padding: '10px 12px' }}>
      <div style={{
        fontSize: 9.5, fontWeight: 600, color: 'var(--sage-500)',
        textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 6
      }}>Search across all patients & wards</div>
      <div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '4px 12px', alignItems: 'baseline' }}>
        {examples.map(([k, v]) => (
          <React.Fragment key={k}>
            <code style={{ fontSize: 11, fontFamily: 'var(--font-mono)', background: 'var(--sage-50)', borderRadius: 3, padding: '1px 5px', color: 'var(--sage-700)', whiteSpace: 'nowrap' }}>{k}</code>
            <span style={{ fontSize: 11.5, color: 'var(--sage-600)' }}>{v}</span>
          </React.Fragment>
        ))}
      </div>
    </div>
  );
}

window.SearchBar = SearchBar;
