
// ─── Wave 9-D — GaokaoCharterSearchBlock (E8) ────────────────────────────────
// Full-text search over data/admission-rules/HI/2024.json `detail` fields.
// Renders a search box; matching restriction entries are listed with highlights.
// Embedded in page-gaokao.jsx next to FAQ chip via "查章程" chip.

const GaokaoCharterSearchBlock = ({ lang }) => {
  const [open, setOpen] = React.useState(false);
  const [query, setQuery] = React.useState('');
  const [results, setResults] = React.useState([]);
  const [rulesData, setRulesData] = React.useState(null);
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);

  const labelZh = {
    chip: '查章程',
    title: '章程全文检索',
    subtitle: '在海南 2024 年招生章程限报条款中搜索',
    placeholder: '输入关键词，如"色盲"、"英语"、"身高"…',
    noResults: '未找到匹配条款',
    close: '关闭',
    source: '来源：2024 年各校招生章程',
    type_physical: '体检限报',
    type_score: '单科要求',
    severity_hard: '硬限制',
    severity_soft: '建议',
  };
  const labelEn = {
    chip: 'Charter',
    title: 'Admission Charter Search',
    subtitle: 'Full-text search across HI 2024 admission charter restrictions',
    placeholder: 'Search keyword, e.g. "色盲", "英语", "height"…',
    noResults: 'No matching clauses found',
    close: 'Close',
    source: 'Source: 2024 school admission charters',
    type_physical: 'Physical exam',
    type_score: 'Subject score',
    severity_hard: 'Hard limit',
    severity_soft: 'Advisory',
  };
  const L = lang === 'zh' ? labelZh : labelEn;

  // Lazy-load rules data when panel opens
  React.useEffect(() => {
    if (!open || rulesData) return;
    setLoading(true);
    fetch('/data/admission-rules/HI/2024.json')
      .then((r) => r.json())
      .then((data) => {
        setRulesData(Array.isArray(data) ? data : []);
        setLoading(false);
      })
      .catch(() => {
        setError(lang === 'zh' ? '章程数据加载失败' : 'Failed to load charter data');
        setLoading(false);
      });
  }, [open, rulesData, lang]);

  // Run search whenever query or data changes
  React.useEffect(() => {
    if (!rulesData || !query.trim()) {
      setResults([]);
      return;
    }
    const q = query.trim().toLowerCase();
    const hits = [];
    for (const school of rulesData) {
      if (!Array.isArray(school.restrictions)) continue;
      for (const r of school.restrictions) {
        if (!r || typeof r.detail !== 'string') continue;
        if (r.detail.toLowerCase().includes(q) ||
            (r.majorPattern && r.majorPattern.toLowerCase().includes(q))) {
          hits.push({ school, restriction: r });
        }
      }
    }
    setResults(hits);
  }, [query, rulesData]);

  // ESC closes the modal — matches the FAQ / events / mock-tracker / cohort
  // convention so users don't have to hunt for the X button (#229.7).
  React.useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
    const onHash = () => setOpen(false); // #323(1) — close on route change so the modal can't intercept clicks after nav
    document.addEventListener('keydown', onKey);
    window.addEventListener('hashchange', onHash);
    return () => { document.removeEventListener('keydown', onKey); window.removeEventListener('hashchange', onHash); };
  }, [open]);

  // Highlight matching text in a string
  function highlight(text) {
    if (!query.trim() || !text) return text;
    const q = query.trim();
    const idx = text.toLowerCase().indexOf(q.toLowerCase());
    if (idx < 0) return text;
    return (
      React.createElement('span', null,
        text.slice(0, idx),
        React.createElement('mark', {
          style: { background: 'rgba(255,200,0,0.35)', borderRadius: 2, padding: '0 1px' }
        }, text.slice(idx, idx + q.length)),
        text.slice(idx + q.length)
      )
    );
  }

  return (
    React.createElement(React.Fragment, null,
      // ── chip trigger ──
      React.createElement('button', {
        'data-testid': 'charter-search-chip',
        onClick: () => setOpen(true),
        style: {
          display: 'inline-flex',
          alignItems: 'center',
          gap: 4,
          padding: '5px 12px',
          borderRadius: 20,
          border: '1px solid var(--pb-border)',
          background: 'var(--pb-surface-alt)',
          color: 'var(--pb-fg-muted)',
          fontSize: 12,
          fontWeight: 600,
          cursor: 'pointer',
          whiteSpace: 'nowrap',
        }
      }, '📋 ', L.chip),

      // ── modal overlay — portalled to body to escape sticky stacking context (#258) ──
      open && ReactDOM.createPortal(React.createElement('div', {
        'data-testid': 'charter-search-modal',
        role: 'dialog',
        'aria-modal': 'true',
        'aria-label': L.title,
        style: {
          position: 'fixed', inset: 0, zIndex: 2147483647,
          background: 'rgba(0,0,0,0.45)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          padding: '24px 16px',
          overflowY: 'auto',
        },
        onClick: (e) => { if (e.target === e.currentTarget) setOpen(false); }
      },
        React.createElement('div', {
          'data-testid': 'charter-search-dialog',
          style: {
            background: 'var(--pb-surface)',
            borderRadius: 12,
            width: '100%',
            maxWidth: 680,
            maxHeight: 'calc(100vh - 64px)',
            boxShadow: '0 20px 60px rgba(0,0,0,0.25)',
            display: 'flex',
            flexDirection: 'column',
            overflow: 'hidden',
          }
        },
          // header
          React.createElement('div', {
            style: {
              padding: '20px 24px 16px',
              borderBottom: '1px solid var(--pb-border)',
              display: 'flex',
              justifyContent: 'space-between',
              alignItems: 'flex-start',
            }
          },
            React.createElement('div', null,
              React.createElement('div', {
                className: 'pb-eyebrow',
                style: { marginBottom: 4, color: 'var(--pb-navy-700)' }
              }, 'E8 · ' + L.title),
              React.createElement('p', {
                style: { margin: 0, fontSize: 13, color: 'var(--pb-fg-muted)', lineHeight: 1.5 }
              }, L.subtitle)
            ),
            React.createElement('button', {
              'data-testid': 'charter-search-close',
              'aria-label': lang === 'zh' ? '关闭章程检索' : 'Close charter search',
              onClick: () => setOpen(false),
              style: {
                alignItems: 'center',
                background: 'none',
                border: 'none',
                borderRadius: 18,
                color: 'var(--pb-fg-muted)',
                cursor: 'pointer',
                display: 'inline-flex',
                fontSize: 20,
                height: 36,
                justifyContent: 'center',
                lineHeight: 1,
                padding: 0,
                width: 36,
              }
            }, '×')
          ),

          // search input
          React.createElement('div', {
            style: { padding: '16px 24px', borderBottom: '1px solid var(--pb-border)' }
          },
            React.createElement('input', {
              'data-testid': 'charter-search-input',
              type: 'text',
              className: 'pb-input',
              placeholder: L.placeholder,
              value: query,
              onChange: (e) => setQuery(e.target.value),
              autoFocus: true,
              style: { width: '100%', boxSizing: 'border-box' },
            })
          ),

          // body
          React.createElement('div', {
            style: { flex: '1 1 auto', minHeight: 0, overflowY: 'auto', padding: '8px 0' }
          },
            loading && React.createElement('div', {
              style: { padding: '32px', textAlign: 'center', color: 'var(--pb-fg-muted)', fontSize: 13 }
            }, lang === 'zh' ? '加载中…' : 'Loading…'),

            error && React.createElement('div', {
              style: { padding: '16px 24px', color: 'var(--pb-danger)', fontSize: 13 }
            }, error),

            !loading && !error && query.trim() && results.length === 0 && React.createElement('div', {
              style: { padding: '32px', textAlign: 'center', color: 'var(--pb-fg-muted)', fontSize: 13 }
            }, L.noResults),

            !loading && !error && results.map((hit, i) =>
              React.createElement('div', {
                key: i,
                'data-testid': `charter-result-${i}`,
                style: {
                  padding: '12px 24px',
                  borderBottom: '1px solid var(--pb-border)',
                  display: 'flex',
                  flexDirection: 'column',
                  gap: 4,
                }
              },
                React.createElement('div', {
                  style: { display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }
                },
                  React.createElement('span', {
                    style: { fontWeight: 600, fontFamily: 'var(--pb-serif)', fontSize: 14 }
                  }, hit.school.schoolName),
                  React.createElement('span', {
                    style: {
                      fontSize: 10, fontWeight: 600, padding: '1px 6px', borderRadius: 4,
                      background: hit.restriction.type === 'physical'
                        ? 'rgba(239,68,68,0.1)' : 'rgba(59,130,246,0.1)',
                      color: hit.restriction.type === 'physical'
                        ? 'var(--pb-danger,#ef4444)' : '#2563eb',
                    }
                  }, hit.restriction.type === 'physical' ? L.type_physical : L.type_score),
                  hit.restriction.severity === 'hard' && React.createElement('span', {
                    style: {
                      fontSize: 10, fontWeight: 600, padding: '1px 6px', borderRadius: 4,
                      background: 'rgba(239,68,68,0.08)',
                      color: 'var(--pb-danger,#ef4444)',
                      border: '1px solid rgba(239,68,68,0.2)',
                    }
                  }, L.severity_hard)
                ),
                React.createElement('div', {
                  style: { fontSize: 12, color: 'var(--pb-fg-muted)' }
                },
                  React.createElement('strong', null, lang === 'zh' ? '限报专业：' : 'Majors: '),
                  hit.restriction.majorPattern
                ),
                React.createElement('div', {
                  'data-testid': `charter-detail-${i}`,
                  style: { fontSize: 13, color: 'var(--pb-fg)', lineHeight: 1.5 }
                }, highlight(hit.restriction.detail))
              )
            )
          ),

          // footer
          React.createElement('div', {
            style: {
              padding: '12px 24px',
              borderTop: '1px solid var(--pb-border)',
              fontSize: 11,
              color: 'var(--pb-fg-muted)',
              display: 'flex',
              justifyContent: 'space-between',
              alignItems: 'center',
            }
          },
            React.createElement('span', null, L.source),
            React.createElement('button', {
              className: 'pb-btn pb-btn-link pb-btn-sm',
              onClick: () => setOpen(false),
            }, L.close)
          )
        )
      ), document.body)
    )
  );
};

window.GaokaoCharterSearchBlock = GaokaoCharterSearchBlock;
