import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react';

export interface SearchEntry {
  pageNum: number;
  headingContext: string;
  text: string;
}

interface Props {
  searchIndex: SearchEntry[];
  onNavigate: (pageNum: number) => void;
  onClose: () => void;
}

function escapeHtml(s: string): string {
  return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

function buildSnippetHtml(text: string, q: string): string {
  const lo = text.toLowerCase();
  const idx = lo.indexOf(q);
  if (idx === -1) return escapeHtml(text.slice(0, 140)) + (text.length > 140 ? '…' : '');
  const r = 65;
  const s = Math.max(0, idx - r);
  const e = Math.min(text.length, idx + q.length + r);
  return (
    (s > 0 ? '…' : '') +
    escapeHtml(text.slice(s, idx)) +
    `<mark>${escapeHtml(text.slice(idx, idx + q.length))}</mark>` +
    escapeHtml(text.slice(idx + q.length, e)) +
    (e < text.length ? '…' : '')
  );
}

export default function SearchModal({ searchIndex, onNavigate, onClose }: Props) {
  const [query, setQuery] = useState('');
  const [activeIdx, setActiveIdx] = useState(0);
  const inputRef = useRef<HTMLInputElement>(null);
  const listRef = useRef<HTMLUListElement>(null);

  useEffect(() => { inputRef.current?.focus(); }, []);

  const results = useMemo(() => {
    const q = query.trim().toLowerCase();
    if (q.length < 2) return [];
    const seen: Record<number, number> = {};
    const out: { pageNum: number; headingContext: string; snippetHtml: string }[] = [];
    for (const entry of searchIndex) {
      if (out.length >= 40) break;
      const hitText    = entry.text.toLowerCase().includes(q);
      const hitHeading = entry.headingContext.toLowerCase().includes(q);
      if (!hitText && !hitHeading) continue;
      const count = seen[entry.pageNum] ?? 0;
      if (count >= 2) continue;
      seen[entry.pageNum] = count + 1;
      out.push({
        pageNum: entry.pageNum,
        headingContext: entry.headingContext,
        snippetHtml: buildSnippetHtml(hitText ? entry.text : entry.headingContext, q),
      });
    }
    return out;
  }, [query, searchIndex]);

  useEffect(() => { setActiveIdx(0); }, [results]);

  useEffect(() => {
    const el = listRef.current?.children[activeIdx] as HTMLElement | undefined;
    el?.scrollIntoView({ block: 'nearest' });
  }, [activeIdx]);

  const go = useCallback((pageNum: number) => {
    onNavigate(pageNum);
    onClose();
  }, [onNavigate, onClose]);

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === 'Escape') { onClose(); return; }
    if (e.key === 'ArrowDown') { e.preventDefault(); setActiveIdx(i => Math.min(i + 1, results.length - 1)); }
    if (e.key === 'ArrowUp')   { e.preventDefault(); setActiveIdx(i => Math.max(i - 1, 0)); }
    if (e.key === 'Enter' && results[activeIdx]) go(results[activeIdx].pageNum);
  };

  const q = query.trim();

  return (
    <div className="search-overlay" onClick={onClose}>
      <div className="search-modal" onClick={e => e.stopPropagation()}>
        <input
          ref={inputRef}
          className="search-input"
          type="text"
          placeholder="Search the rulebook…"
          value={query}
          onChange={e => setQuery(e.target.value)}
          onKeyDown={handleKeyDown}
        />
        {q.length < 2 ? (
          <div className="search-empty">Type at least 2 characters</div>
        ) : results.length === 0 ? (
          <div className="search-empty">No results for &ldquo;{q}&rdquo;</div>
        ) : (
          <ul className="search-results" ref={listRef}>
            {results.map((r, i) => (
              <li
                key={i}
                className={`search-result${i === activeIdx ? ' active' : ''}`}
                onClick={() => go(r.pageNum)}
                onMouseEnter={() => setActiveIdx(i)}
              >
                <div className="search-result-meta">
                  <span className="search-result-heading">{r.headingContext || '—'}</span>
                  <span className="search-result-page">p.{r.pageNum}</span>
                </div>
                <div className="search-result-snippet" dangerouslySetInnerHTML={{ __html: r.snippetHtml }} />
              </li>
            ))}
          </ul>
        )}
        <div className="search-footer">
          <span>↑↓ navigate</span>
          <span>↵ go to page</span>
          <span>esc close</span>
        </div>
      </div>
    </div>
  );
}
