// 院校对比页 — A3 + Wave 49 M49.4 (deep-profile mode)
// Two URL modes share the same route:
//   Legacy (A3): /#/gaokao/compare?ids=tsinghua,pku,fudan&province=BJ&year=2024&score=658&rank=4217
//                Uses curated client-side gaokao-data.js (PB_SCHOOLS + CUTOFFS).
//   M49.4 codes-mode: /#/gaokao/compare?codes=0001,6001,1101[&province=...&year=...&score=...&rank=...]
//                Lazy-fetches /data/cn-school-ref/profile-detail/<code>.json (894 schools, M49.2).
//   Issue #229 HI bridge: /#/gaokao/compare?ids=6001,6003&province=HI[&...]
//                When all ids are 4-digit codes AND province=HI, routes through codes-mode
//                so the legacy A3 "+ 对比" cart on /#/gaokao works for HI candidates.
// Max 4 schools, min 2. No new API endpoints — codes-mode reads static JSON from CF Pages.

const GaokaoComparePage = () => {
  const lang = useLang();
  const t = useT();

  // ── Parse URL params ───────────────────────────────────────────────────────
  const getParams = () => {
    const hash = window.location.hash || '';
    const qi = hash.indexOf('?');
    if (qi < 0) return {};
    const q = new URLSearchParams(hash.slice(qi + 1));
    return {
      ids: (q.get('ids') || '').split(',').filter(Boolean),
      codes: (q.get('codes') || '').split(',').filter(Boolean),
      province: q.get('province') || 'BJ',
      year: parseInt(q.get('year') || '2024', 10),
      score: parseInt(q.get('score') || '0', 10),
      rank: parseInt(q.get('rank') || '0', 10),
    };
  };

  const [params, setParams] = React.useState(getParams);

  React.useEffect(() => {
    const onHash = () => setParams(getParams());
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);

  // Direct visits to /#/gaokao/compare carry no query string, so getParams()
  // returns {} — every field needs a default or rawIds.length crashes the
  // whole page into the ErrorBoundary before the empty-state below can render.
  const { ids: rawIds = [], codes: rawCodes = [], province = 'BJ', year = 2024, score = 0, rank = 0 } = params;

  // ── M49.4 codes-mode: active when ?codes= present and ?ids= empty ─────────
  // Issue #229 (F1): Legacy entry points (`buildCompareUrl()` in page-gaokao.jsx
  // and a few other places) build `?ids=<4-digit codes>&province=HI` for HI
  // candidates. Those 4-digit codes aren't curated client-side in PB_SCHOOLS,
  // so the legacy ids-mode would render "未知院校:<id>". Route HI ids-mode URLs
  // through codes-mode so the deep-profile dataset (cn-school-ref/profile-detail
  // /<code>.json) drives rendering. Restrict the routing to ids that LOOK like
  // 4-digit codes — slug ids (e.g. tsinghua/pku) stay in legacy curated path
  // even if province=HI is later selected via the dropdown.
  const _looksLikeCode = (s) => typeof s === 'string' && /^\d{4}$/.test(s);
  const _allIdsAreCodes = rawIds.length >= 1 && rawIds.every(_looksLikeCode);
  const _isHiIdsLegacy = _allIdsAreCodes && rawCodes.length === 0 && province === 'HI';
  const codesMode = (rawCodes.length >= 1 && rawIds.length === 0) || _isHiIdsLegacy;
  const _effectiveCodes = _isHiIdsLegacy ? rawIds : rawCodes;
  const codes = React.useMemo(() => _effectiveCodes.slice(0, 4), [_effectiveCodes.join(',')]);
  const codesTruncated = _effectiveCodes.length > 4;

  // ── M49.4 — lazy-fetch profile-detail per code, cache in state ────────────
  const [profileData, setProfileData] = React.useState({}); // code → data | null (null = not found / fetch error)
  React.useEffect(() => {
    if (!codesMode) return;
    for (const code of codes) {
      if (profileData[code] !== undefined) continue; // cached (success or known-miss)
      fetch('/data/cn-school-ref/profile-detail/' + encodeURIComponent(code) + '.json')
        .then((r) => (r.ok ? r.json() : null))
        .then((d) => setProfileData((prev) => ({ ...prev, [code]: d || null })))
        .catch(() => setProfileData((prev) => ({ ...prev, [code]: null })));
    }
  }, [codes.join(',')]);

  // ── Truncate to 4 with warning ─────────────────────────────────────────────
  const [truncated, setTruncated] = React.useState(false);
  const ids = React.useMemo(() => {
    if (rawIds.length > 4) {
      setTruncated(true);
      return rawIds.slice(0, 4);
    }
    setTruncated(false);
    return rawIds;
  }, [rawIds.join(',')]);

  // ── CUTOFFS data from gaokao-data.js (loaded as plain <script> in index.html)
  // We read window.PB_SCHOOLS / window.PB_CUTOFFS set by a small inline bridge
  // defined at the bottom of this file and injected via index.html.
  // Fallback: use the module-style export if available.
  const SCHOOLS = (window.PB_SCHOOLS || []);
  const CUTOFFS = (window.PB_CUTOFFS || {});

  const schoolById = React.useMemo(() => {
    const m = {};
    for (const s of SCHOOLS) m[s.id] = s;
    return m;
  }, [SCHOOLS.length]);

  // ── Years to show in bar chart (last 3) ───────────────────────────────────
  const chartYears = [String(year - 2), String(year - 1), String(year)];

  // ── Subject compatibility ──────────────────────────────────────────────────
  const _pbs = window.PBSubjects;
  const currentCombos = _pbs ? _pbs.getCombosForProvince(province, year) : [];
  const [subjectComboId, setSubjectComboId] = React.useState(() => {
    const combos = _pbs ? _pbs.getCombosForProvince(province, year) : [];
    return combos[0] ? combos[0].id : '33_456';
  });
  const currentCombo = currentCombos.find(c => c.id === subjectComboId) || currentCombos[0];

  const subjectCompat = (reqStr, combo) => {
    const req = String(reqStr || '').replace(/0+$/, '').replace(/^0+/, '');
    if (!req || req === '0') return true;
    const userSubjects = combo ? new Set(combo.codes.split('')) : new Set(['4','5','6']);
    for (const ch of req) {
      if (!userSubjects.has(ch)) return false;
    }
    return true;
  };

  // ── Compute probability for a school given user rank & province cutoffs ───
  const getProbability = (schoolId) => {
    if (!rank) return null;
    const provCutoffs = (CUTOFFS[province] || {})[schoolId];
    if (!provCutoffs) return null;
    const yearData = provCutoffs[String(year)] || provCutoffs[String(year - 1)];
    if (!yearData) return null;
    const cutoffRank = yearData[1];
    const ratio = rank / cutoffRank;
    if (ratio <= 0.85) return { prob: Math.min(98, Math.round(85 + (0.85 - ratio) * 100)), bucket: 'safety' };
    if (ratio <= 1.15) return { prob: Math.round(85 - (ratio - 0.85) * 100), bucket: 'match' };
    if (ratio <= 1.5) return { prob: Math.max(15, Math.round(50 - (ratio - 1.15) * 100)), bucket: 'reach' };
    return { prob: 5, bucket: 'reach' };
  };

  // ── Get 3-year cutoff rows ────────────────────────────────────────────────
  const getCutoffRows = (schoolId) => {
    const provCutoffs = (CUTOFFS[province] || {})[schoolId] || {};
    return chartYears.map(yr => ({
      year: yr,
      score: provCutoffs[yr] ? provCutoffs[yr][0] : null,
      rank: provCutoffs[yr] ? provCutoffs[yr][1] : null,
    }));
  };

  // ── Province selector ─────────────────────────────────────────────────────
  // Issue #229 (F3): HI must be selectable. HI is the primary launch market;
  // listed first so the dropdown defaults to HI when navigated from a HI plan.
  const PROVINCE_LIST = [
    { code: 'HI', zh: '海南' },
    { code: 'BJ', zh: '北京' },
    { code: 'SH', zh: '上海' },
    { code: 'GD', zh: '广东' },
    { code: 'ZJ', zh: '浙江' },
    { code: 'JS', zh: '江苏' },
    { code: 'SD', zh: '山东' },
  ];

  const updateUrl = (newIds, newProvince, newYear, newScore, newRank) => {
    const params = new URLSearchParams();
    params.set('ids', newIds.join(','));
    params.set('province', newProvince);
    params.set('year', String(newYear));
    if (newScore) params.set('score', String(newScore));
    if (newRank) params.set('rank', String(newRank));
    window.location.hash = '#/gaokao/compare?' + params.toString();
  };

  // ── Remove a school from compare ─────────────────────────────────────────
  const removeSchool = (id) => {
    const next = ids.filter(x => x !== id);
    updateUrl(next, province, year, score, rank);
  };

  // ── Tier badge color ──────────────────────────────────────────────────────
  const tierColor = { reach: 'var(--pb-danger)', match: 'var(--pb-navy-700)', safety: 'var(--pb-success)' };
  const tierLabel = {
    reach: lang === 'zh' ? '冲刺' : 'Reach',
    match: lang === 'zh' ? '匹配' : 'Match',
    safety: lang === 'zh' ? '保底' : 'Safety',
  };

  // ── Inline mini bar chart (pure CSS divs, no echarts dependency) ──────────
  const MiniBarChart = ({ rows, province }) => {
    const scores = rows.map(r => r.score).filter(Boolean);
    const maxScore = scores.length ? Math.max(...scores) : 750;
    const minScore = scores.length ? Math.min(...scores) - 20 : 550;
    const range = maxScore - minScore || 1;
    return (
      <div style={{ display: 'flex', alignItems: 'flex-end', gap: 8, height: 60, padding: '0 8px' }}>
        {rows.map(r => {
          const h = r.score ? Math.max(4, Math.round(((r.score - minScore) / range) * 50)) : 0;
          return (
            <div key={r.year} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2 }}>
              <div style={{ fontSize: 9, color: 'var(--pb-fg-muted)', fontFamily: 'var(--pb-mono)', fontWeight: 600 }}>
                {r.score || '—'}
              </div>
              <div style={{
                width: '100%', height: h,
                background: r.score ? 'var(--pb-navy-700)' : 'var(--pb-border)',
                borderRadius: '2px 2px 0 0',
                minHeight: r.score ? 4 : 2,
                opacity: r.score ? 1 : 0.3,
              }}/>
              <div style={{ fontSize: 9, color: 'var(--pb-fg-muted)', fontFamily: 'var(--pb-mono)' }}>
                {r.year.slice(2)}
              </div>
            </div>
          );
        })}
      </div>
    );
  };

  // ── Tier tag badge ────────────────────────────────────────────────────────
  const TierBadge = ({ tier }) => {
    const colors = {
      '985-A': { bg: '#fef3c7', color: '#92400e' },
      '985':   { bg: '#dbeafe', color: '#1e40af' },
      '211':   { bg: '#d1fae5', color: '#065f46' },
    };
    const style = colors[tier] || { bg: 'var(--pb-surface-alt)', color: 'var(--pb-fg-muted)' };
    return (
      <span style={{ padding: '2px 7px', fontSize: 10, fontWeight: 600, borderRadius: 4, background: style.bg, color: style.color, letterSpacing: '0.03em' }}>
        {tier}
      </span>
    );
  };

  // ─────────────────────────────────────────────────────────────────────────
  // M49.4 codes-mode rendering — branch BEFORE legacy ids-mode early returns
  // ─────────────────────────────────────────────────────────────────────────
  if (codesMode) {
    const cp = ((window.I18N && window.I18N[lang] && window.I18N[lang].gk && window.I18N[lang].gk.compareProfile)
      || (window.I18N && window.I18N.zh && window.I18N.zh.gk && window.I18N.zh.gk.compareProfile)
      || {});

    // Empty / single-code edge states
    if (codes.length === 0) {
      return (
        <div className="pb-scroll">
          <PBNav active="gaokao" />
          <section style={{ padding: '80px 48px', textAlign: 'center' }}>
            <div data-testid="compare-codes-empty" style={{ maxWidth: 520, margin: '0 auto' }}>
              <div style={{ fontFamily: 'var(--pb-serif)', fontSize: 28, fontWeight: 600, marginBottom: 16 }}>
                {lang === 'zh' ? '请先在测算页选择院校' : 'Select schools on the calculator page first'}
              </div>
              <button className="pb-btn pb-btn-primary" onClick={() => navigateTo('/gaokao')}>
                {lang === 'zh' ? '去测算页 →' : 'Go to calculator →'}
              </button>
            </div>
          </section>
          <PBFooter />
        </div>
      );
    }
    if (codes.length === 1) {
      return (
        <div className="pb-scroll">
          <PBNav active="gaokao" />
          <section style={{ padding: '80px 48px', textAlign: 'center' }}>
            <div data-testid="compare-codes-need-more" style={{ maxWidth: 520, margin: '0 auto' }}>
              <div style={{ fontFamily: 'var(--pb-serif)', fontSize: 28, fontWeight: 600, marginBottom: 16 }}>
                {cp.cartHintMin || (lang === 'zh' ? '至少选 2 校' : 'Pick at least 2')}
              </div>
              <button className="pb-btn pb-btn-primary" onClick={() => navigateTo('/gaokao')}>
                {lang === 'zh' ? '继续添加院校 →' : 'Add more schools →'}
              </button>
            </div>
          </section>
          <PBFooter />
        </div>
      );
    }

    // ── Main codes-mode grid ────────────────────────────────────────────────
    const colCount = codes.length;
    const formatEval = (data) => {
      if (!data || !data.dimensions || !data.dimensions['学科评估']) return [];
      const ev = data.dimensions['学科评估'];
      const list = Array.isArray(ev.disciplines) ? ev.disciplines : [];
      // Keep A+/A only, top 5
      return list
        .filter((d) => typeof d.grade === 'string' && /^A/.test(d.grade))
        .slice(0, 5);
    };
    const truncate = (s, n) => (typeof s === 'string' && s.length > n ? s.slice(0, n) + '…' : (s || ''));
    const firstSectionText = (sections) =>
      (Array.isArray(sections) && sections.length > 0 && typeof sections[0].text === 'string')
        ? sections[0].text
        : '';

    return (
      <div className="pb-scroll" data-testid="compare-page-codes">
        <PBNav active="gaokao" />

        {/* Header */}
        <section style={{ padding: '48px 48px 32px', background: 'var(--pb-paper)', borderBottom: '1px solid var(--pb-border)' }}>
          <div style={{ maxWidth: 1280, margin: '0 auto' }}>
            <div className="pb-eyebrow" style={{ marginBottom: 12 }}>
              {cp.eyebrowDeep || (lang === 'zh' ? 'M49.4 · 院校深度档案' : 'M49.4 · School Deep Profile')}
            </div>
            <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', flexWrap: 'wrap', gap: 16 }}>
              <h1 style={{ fontFamily: 'var(--pb-serif)', fontSize: 36, fontWeight: 600, margin: 0 }}>
                {lang === 'zh' ? `${codes.length} 所院校深度档案对比` : `Deep Profile Comparison: ${codes.length} Schools`}
              </h1>
              <button className="pb-btn pb-btn-link pb-btn-sm" onClick={() => navigateTo('/gaokao')}>
                {lang === 'zh' ? '← 返回测算' : '← Back to calculator'}
              </button>
            </div>
            {codesTruncated && (
              <div data-testid="compare-codes-truncated-notice" style={{ marginTop: 12, padding: '8px 14px', background: '#fef3c7', border: '1px solid #f59e0b', borderRadius: 6, fontSize: 13, color: '#92400e' }}>
                {cp.cartHintMax || (lang === 'zh' ? '最多 4 校（超出已忽略）' : 'Max 4 (extras ignored)')}
              </div>
            )}
          </div>
        </section>

        {/* Grid of school deep-profile cards */}
        <section style={{ padding: '32px 48px 80px', background: 'var(--pb-bg)' }}>
          <div style={{ maxWidth: 1280, margin: '0 auto' }}>
            <style>{`
              .pb-compare-codes-grid {
                display: grid;
                grid-template-columns: repeat(${colCount}, 1fr);
                gap: 20px;
              }
              @media (max-width: 900px) { .pb-compare-codes-grid { grid-template-columns: repeat(2, 1fr); } }
              @media (max-width: 540px) { .pb-compare-codes-grid { grid-template-columns: 1fr; } }
            `}</style>
            <div className="pb-compare-codes-grid" data-testid="compare-codes-grid">
              {codes.map((code) => {
                const data = profileData[code];
                const loading = data === undefined;
                const missing = data === null;
                // Missing profile → don't put the bare code in the serif title
                // slot (a serif "0810" reads as "o81o"); label it 院校 <code>
                // and let the mono sub-line carry the digits.
                const schoolName = (data && data.schoolName)
                  || (lang === 'zh' ? `院校 ${code}` : `School ${code}`);
                const dims = (data && data.dimensions) || {};
                const is985 = !!(dims['985&211'] && dims['985&211'].is985);
                const is211 = !!(dims['985&211'] && dims['985&211'].is211);
                const isShuangyiliu = !!(dims['双一流吗'] && dims['双一流吗'].isShuangyiliu);
                const isPublic = !!(dims['公办民办'] && dims['公办民办'].isPublic);
                const isPrivate = !!(dims['公办民办'] && dims['公办民办'].isPrivate);
                const evalList = formatEval(data);
                const empSections = (dims['就业情况'] && dims['就业情况'].sections) || [];
                const empText = truncate(firstSectionText(empSections), 140);
                const feeRanges = (dims['收费标准'] && dims['收费标准'].tuitionRanges) || [];
                const dormFee = (dims['收费标准'] && dims['收费标准'].dormFee) || '';
                const feeText = truncate(feeRanges[0] || dormFee, 120);
                const addrSections = (dims['校区地址'] && dims['校区地址'].sections) || [];
                const addrText = truncate(firstSectionText(addrSections) || ((dims['校区地址'] && dims['校区地址'].addresses) || [])[0] || '', 120);
                const introParas = (dims['院校介绍'] && dims['院校介绍'].paragraphs) || [];
                const introText = truncate(introParas[0] || '', 140);

                return (
                  <div key={code} className="pb-card" style={{ padding: 0, overflow: 'hidden', position: 'relative' }}
                       data-testid={`compare-codes-col-${code}`}>
                    {/* Remove button — drop code from URL */}
                    <button
                      onClick={() => {
                        const next = codes.filter((c) => c !== code);
                        const q = new URLSearchParams();
                        q.set('codes', next.join(','));
                        if (province) q.set('province', province);
                        if (year) q.set('year', String(year));
                        if (score) q.set('score', String(score));
                        if (rank) q.set('rank', String(rank));
                        window.location.hash = '#/gaokao/compare?' + q.toString();
                      }}
                      data-testid={`compare-codes-remove-${code}`}
                      title={lang === 'zh' ? '移除' : 'Remove'}
                      style={{
                        position: 'absolute', top: 10, right: 10, zIndex: 2,
                        width: 24, height: 24, borderRadius: 12, border: 'none',
                        background: 'var(--pb-surface-alt)', color: 'var(--pb-fg-muted)',
                        cursor: 'pointer', display: 'grid', placeItems: 'center', fontSize: 14,
                      }}
                    >×</button>

                    {/* Card header */}
                    <div style={{ padding: '20px 20px 14px', borderBottom: '1px solid var(--pb-border)', background: 'var(--pb-paper)' }}>
                      <div style={{
                        width: 44, height: 44, borderRadius: 8, marginBottom: 10,
                        background: 'var(--pb-navy-900)', color: 'var(--pb-gold-500)',
                        display: 'grid', placeItems: 'center',
                        fontFamily: 'var(--pb-serif)', fontSize: 18, fontWeight: 700,
                      }}>
                        {(data && data.schoolName) ? String(schoolName).slice(0, 1) : '#'}
                      </div>
                      <div style={{ fontFamily: 'var(--pb-serif)', fontSize: 17, fontWeight: 600, lineHeight: 1.3, paddingRight: 24 }}>
                        {schoolName}
                      </div>
                      <div style={{ fontFamily: 'var(--pb-mono)', fontSize: 11, color: 'var(--pb-fg-muted)', marginTop: 4 }}>
                        Code: {code}
                      </div>
                    </div>

                    {loading && (
                      <div style={{ padding: 24, fontSize: 13, color: 'var(--pb-fg-muted)' }} data-testid={`compare-codes-loading-${code}`}>
                        {cp.loadingProfile || (lang === 'zh' ? '档案加载中…' : 'Loading profile…')}
                      </div>
                    )}
                    {missing && (
                      <div style={{ padding: 24, fontSize: 13, color: 'var(--pb-fg-muted)' }} data-testid={`compare-codes-missing-${code}`}>
                        {cp.profileNotFound || (lang === 'zh' ? '该校档案数据待补全' : 'Profile data not yet ingested')}
                      </div>
                    )}
                    {!loading && !missing && (
                      <React.Fragment>
                        {/* Tags row */}
                        <div style={{ padding: '14px 16px', borderBottom: '1px solid var(--pb-border)' }}>
                          <div style={{ fontSize: 10, color: 'var(--pb-fg-muted)', marginBottom: 6, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                            {cp.sectionTagsLabel || '院校标签'}
                          </div>
                          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }} data-testid={`compare-codes-tags-${code}`}>
                            {is985 && <span style={{ padding: '2px 7px', fontSize: 11, fontWeight: 600, borderRadius: 4, background: '#fef3c7', color: '#92400e' }}>{cp.tag985 || '985'}</span>}
                            {is211 && <span style={{ padding: '2px 7px', fontSize: 11, fontWeight: 600, borderRadius: 4, background: '#dbeafe', color: '#1e40af' }}>{cp.tag211 || '211'}</span>}
                            {isShuangyiliu && <span style={{ padding: '2px 7px', fontSize: 11, fontWeight: 600, borderRadius: 4, background: '#d1fae5', color: '#065f46' }}>{cp.tagShuangyiliu || '双一流'}</span>}
                            {isPublic && <span style={{ padding: '2px 7px', fontSize: 11, fontWeight: 600, borderRadius: 4, background: 'var(--pb-surface-alt)', color: 'var(--pb-fg-muted)' }}>{cp.tagPublic || '公办'}</span>}
                            {isPrivate && <span style={{ padding: '2px 7px', fontSize: 11, fontWeight: 600, borderRadius: 4, background: 'var(--pb-surface-alt)', color: 'var(--pb-fg-muted)' }}>{cp.tagPrivate || '民办'}</span>}
                          </div>
                        </div>

                        {/* 学科评估 */}
                        <div style={{ padding: '14px 16px', borderBottom: '1px solid var(--pb-border)' }}>
                          <div style={{ fontSize: 10, color: 'var(--pb-fg-muted)', marginBottom: 6, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                            {cp.sectionEvalLabel || '学科评估（top 5 A+/A）'}
                          </div>
                          {evalList.length === 0 ? (
                            <div style={{ fontSize: 12, color: 'var(--pb-fg-muted)' }} data-testid={`compare-codes-eval-empty-${code}`}>
                              {/* QA 2026-06-10 — "暂无数据"读起来像缺数据；实为本库只收录
                                  A 类（A+/A/A-），非 A 类院校属正常情况，文案改诚实。 */}
                              {cp.evalEmpty || '第四轮学科评估中无 A 类学科（本库仅收录 A+/A/A- 级）'}
                            </div>
                          ) : (
                            <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }} data-testid={`compare-codes-eval-${code}`}>
                              {evalList.map((d, j) => (
                                <div key={j} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', fontSize: 12 }}>
                                  <span>{d.name}</span>
                                  <span style={{ padding: '1px 6px', fontSize: 10, fontWeight: 700, borderRadius: 3, background: d.grade === 'A+' ? '#dcfce7' : '#dbeafe', color: d.grade === 'A+' ? '#15803d' : '#1d4ed8' }}>
                                    {d.grade}
                                  </span>
                                </div>
                              ))}
                            </div>
                          )}
                        </div>

                        {/* 就业 */}
                        <div style={{ padding: '14px 16px', borderBottom: '1px solid var(--pb-border)' }}>
                          <div style={{ fontSize: 10, color: 'var(--pb-fg-muted)', marginBottom: 6, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                            {cp.sectionEmploymentLabel || '就业概况'}
                          </div>
                          <div style={{ fontSize: 12, lineHeight: 1.55, color: empText ? 'inherit' : 'var(--pb-fg-muted)' }} data-testid={`compare-codes-employment-${code}`}>
                            {empText || cp.employmentEmpty || '暂无就业摘要'}
                          </div>
                        </div>

                        {/* 学费 */}
                        <div style={{ padding: '14px 16px', borderBottom: '1px solid var(--pb-border)' }}>
                          <div style={{ fontSize: 10, color: 'var(--pb-fg-muted)', marginBottom: 6, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                            {cp.sectionFeeLabel || '学费 / 奖助学金'}
                          </div>
                          <div style={{ fontSize: 12, lineHeight: 1.55, color: feeText ? 'inherit' : 'var(--pb-fg-muted)' }} data-testid={`compare-codes-fee-${code}`}>
                            {feeText || cp.feeEmpty || '暂无收费标准'}
                          </div>
                        </div>

                        {/* 校区地址 */}
                        <div style={{ padding: '14px 16px', borderBottom: '1px solid var(--pb-border)' }}>
                          <div style={{ fontSize: 10, color: 'var(--pb-fg-muted)', marginBottom: 6, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                            {cp.sectionAddressLabel || '校区地址'}
                          </div>
                          <div style={{ fontSize: 12, lineHeight: 1.55, color: addrText ? 'inherit' : 'var(--pb-fg-muted)' }} data-testid={`compare-codes-address-${code}`}>
                            {addrText || cp.addressEmpty || '暂无地址信息'}
                          </div>
                        </div>

                        {/* 简介 */}
                        <div style={{ padding: '14px 16px' }}>
                          <div style={{ fontSize: 10, color: 'var(--pb-fg-muted)', marginBottom: 6, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                            {cp.sectionIntroLabel || '院校简介'}
                          </div>
                          <div style={{ fontSize: 12, lineHeight: 1.55, color: introText ? 'inherit' : 'var(--pb-fg-muted)' }} data-testid={`compare-codes-intro-${code}`}>
                            {introText || cp.introEmpty || '暂无院校简介'}
                          </div>
                        </div>
                      </React.Fragment>
                    )}

                    {/* Data source */}
                    <div style={{ padding: '10px 16px', fontSize: 10, color: 'var(--pb-fg-muted)', lineHeight: 1.5, borderTop: '1px solid var(--pb-border)', background: 'var(--pb-paper)' }}>
                      {lang === 'zh' ? '来源：公开院校档案（M49.2 院校深度档案聚合）' : 'Source: Public school profile (M49.2 aggregated)'}
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
        </section>

        <PBFooter />
      </div>
    );
  }

  // ── Empty / edge-state renders ────────────────────────────────────────────
  if (ids.length === 0) {
    return (
      <div className="pb-scroll">
        <PBNav active="gaokao" />
        <section style={{ padding: '80px 48px', textAlign: 'center' }}>
          <div data-testid="compare-empty-no-ids" style={{ maxWidth: 520, margin: '0 auto' }}>
            <div style={{ fontFamily: 'var(--pb-serif)', fontSize: 28, fontWeight: 600, marginBottom: 16 }}>
              {lang === 'zh' ? '请先在测算页选择院校' : 'Select schools on the calculator page first'}
            </div>
            <p style={{ fontSize: 15, color: 'var(--pb-fg-muted)', lineHeight: 1.65, marginBottom: 28 }}>
              {lang === 'zh'
                ? '在测算结果中点击「加入对比」，最多 4 所，然后点击顶部对比栏跳转到本页。'
                : 'Click "Add to compare" in calculator results (up to 4 schools), then click the top bar to arrive here.'}
            </p>
            <button className="pb-btn pb-btn-primary" onClick={() => navigateTo('/gaokao')}>
              {lang === 'zh' ? '去测算页 →' : 'Go to calculator →'}
            </button>
          </div>
        </section>
        <PBFooter />
      </div>
    );
  }

  if (ids.length === 1) {
    return (
      <div className="pb-scroll">
        <PBNav active="gaokao" />
        <section style={{ padding: '80px 48px', textAlign: 'center' }}>
          <div data-testid="compare-empty-one-school" style={{ maxWidth: 520, margin: '0 auto' }}>
            <div style={{ fontFamily: 'var(--pb-serif)', fontSize: 28, fontWeight: 600, marginBottom: 16 }}>
              {lang === 'zh' ? '至少选择 2 所院校' : 'Select at least 2 schools'}
            </div>
            <p style={{ fontSize: 15, color: 'var(--pb-fg-muted)', lineHeight: 1.65, marginBottom: 28 }}>
              {lang === 'zh' ? '对比需要 2–4 所院校，当前仅选了 1 所。' : 'Comparison requires 2–4 schools. You have only 1 selected.'}
            </p>
            <button className="pb-btn pb-btn-primary" onClick={() => navigateTo('/gaokao')}>
              {lang === 'zh' ? '继续添加院校 →' : 'Add more schools →'}
            </button>
          </div>
        </section>
        <PBFooter />
      </div>
    );
  }

  // ── Main compare layout ────────────────────────────────────────────────────
  const colCount = ids.length;

  return (
    <div className="pb-scroll" data-testid="compare-page">
      <PBNav active="gaokao" />

      {/* Header + controls */}
      <section style={{ padding: '48px 48px 32px', background: 'var(--pb-paper)', borderBottom: '1px solid var(--pb-border)' }}>
        <div style={{ maxWidth: 1280, margin: '0 auto' }}>
          <div className="pb-eyebrow" style={{ marginBottom: 12 }}>
            {lang === 'zh' ? '院校对比' : 'School Comparison'}
          </div>
          <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', flexWrap: 'wrap', gap: 16 }}>
            <h1 style={{ fontFamily: 'var(--pb-serif)', fontSize: 36, fontWeight: 600, margin: 0 }}>
              {lang === 'zh' ? `${ids.length} 所院校并列对比` : `Comparing ${ids.length} Schools`}
            </h1>
            <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
              {/* Province selector */}
              <div>
                <label style={{ fontSize: 11, color: 'var(--pb-fg-muted)', display: 'block', marginBottom: 4 }}>
                  {lang === 'zh' ? '省份' : 'Province'}
                </label>
                <select
                  className="pb-select"
                  value={province}
                  onChange={e => updateUrl(ids, e.target.value, year, score, rank)}
                  style={{ fontSize: 13, padding: '6px 10px' }}
                  data-testid="compare-province"
                >
                  {PROVINCE_LIST.map(p => (
                    <option key={p.code} value={p.code}>{lang === 'zh' ? p.zh : p.code}</option>
                  ))}
                </select>
              </div>
              {/* Year selector */}
              <div>
                <label style={{ fontSize: 11, color: 'var(--pb-fg-muted)', display: 'block', marginBottom: 4 }}>
                  {lang === 'zh' ? '年份' : 'Year'}
                </label>
                <select
                  className="pb-select"
                  value={year}
                  onChange={e => updateUrl(ids, province, parseInt(e.target.value), score, rank)}
                  style={{ fontSize: 13, padding: '6px 10px' }}
                  data-testid="compare-year"
                >
                  {[2024, 2023, 2022].map(yr => <option key={yr} value={yr}>{yr}</option>)}
                </select>
              </div>
              {/* Subject combo */}
              {currentCombos.length > 0 && (
                <div>
                  <label style={{ fontSize: 11, color: 'var(--pb-fg-muted)', display: 'block', marginBottom: 4 }}>
                    {lang === 'zh' ? '选科' : 'Subjects'}
                  </label>
                  <select
                    className="pb-select"
                    value={subjectComboId}
                    onChange={e => setSubjectComboId(e.target.value)}
                    style={{ fontSize: 13, padding: '6px 10px' }}
                    data-testid="compare-subject"
                  >
                    {currentCombos.map(c => (
                      <option key={c.id} value={c.id}>{lang === 'zh' ? c.labelZh : c.labelEn}</option>
                    ))}
                  </select>
                </div>
              )}
              <div style={{ alignSelf: 'flex-end' }}>
                <button
                  className="pb-btn pb-btn-link pb-btn-sm"
                  onClick={() => navigateTo('/gaokao')}
                  style={{ marginBottom: 2 }}
                >
                  {lang === 'zh' ? '← 返回测算' : '← Back to calculator'}
                </button>
              </div>
            </div>
          </div>

          {truncated && (
            <div data-testid="compare-truncated-notice" style={{ marginTop: 12, padding: '8px 14px', background: '#fef3c7', border: '1px solid #f59e0b', borderRadius: 6, fontSize: 13, color: '#92400e' }}>
              {lang === 'zh' ? '最多对比 4 所院校，已自动取前 4 所。' : 'Maximum 4 schools for comparison. Showing first 4.'}
            </div>
          )}
        </div>
      </section>

      {/* Comparison grid */}
      <section style={{ padding: '32px 48px 80px', background: 'var(--pb-bg)' }}>
        <div style={{ maxWidth: 1280, margin: '0 auto' }}>
          {/* Responsive grid: up to 4 cols on desktop, 2x2 on ≤768px */}
          <style>{`
            .pb-compare-grid {
              display: grid;
              grid-template-columns: repeat(${colCount}, 1fr);
              gap: 20px;
            }
            @media (max-width: 768px) {
              .pb-compare-grid {
                grid-template-columns: repeat(2, 1fr);
              }
            }
            @media (max-width: 480px) {
              .pb-compare-grid {
                grid-template-columns: 1fr;
              }
            }
          `}</style>

          <div className="pb-compare-grid" data-testid="compare-grid">
            {ids.map((id) => {
              const school = schoolById[id];
              if (!school) {
                return (
                  <div key={id} className="pb-card" style={{ padding: 24, opacity: 0.5 }} data-testid={`compare-col-${id}`}>
                    <div style={{ fontSize: 13, color: 'var(--pb-fg-muted)' }}>
                      {lang === 'zh' ? `未知院校：${id}` : `Unknown school: ${id}`}
                    </div>
                  </div>
                );
              }

              const cutoffRows = getCutoffRows(id);
              const probResult = getProbability(id);
              const latestCutoff = cutoffRows.find(r => r.score);

              return (
                <div key={id} className="pb-card" style={{ padding: 0, overflow: 'hidden', position: 'relative' }} data-testid={`compare-col-${id}`}>
                  {/* Remove button */}
                  <button
                    onClick={() => removeSchool(id)}
                    title={lang === 'zh' ? '移除' : 'Remove'}
                    data-testid={`compare-remove-${id}`}
                    style={{
                      position: 'absolute', top: 10, right: 10, zIndex: 2,
                      width: 24, height: 24, borderRadius: 12, border: 'none',
                      background: 'var(--pb-surface-alt)', color: 'var(--pb-fg-muted)',
                      cursor: 'pointer', display: 'grid', placeItems: 'center', fontSize: 14,
                    }}
                  >×</button>

                  {/* School header */}
                  <div style={{ padding: '20px 20px 16px', borderBottom: '1px solid var(--pb-border)', background: 'var(--pb-paper)' }}>
                    {/* Logo placeholder */}
                    <div style={{
                      width: 44, height: 44, borderRadius: 8, marginBottom: 10,
                      background: 'var(--pb-navy-900)', color: 'var(--pb-gold-500)',
                      display: 'grid', placeItems: 'center',
                      fontFamily: 'var(--pb-serif)', fontSize: 18, fontWeight: 700,
                    }}>
                      {(school.name[lang === 'zh' ? 'zh' : 'en'] || school.name.zh).slice(0, 1)}
                    </div>
                    <div style={{ fontFamily: 'var(--pb-serif)', fontSize: 17, fontWeight: 600, lineHeight: 1.3, marginBottom: 6, paddingRight: 24 }}>
                      {lang === 'zh' ? school.name.zh : school.name.en}
                    </div>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
                      <TierBadge tier={school.tier} />
                      <span style={{ fontSize: 12, color: 'var(--pb-fg-muted)' }}>
                        {lang === 'zh' ? school.location.zh : school.location.en}
                      </span>
                    </div>
                    {/* Tag cloud */}
                    <div style={{ marginTop: 8, display: 'flex', flexWrap: 'wrap', gap: 4 }}>
                      {(school.tags || []).map(tag => (
                        <span key={tag} style={{ padding: '1px 6px', fontSize: 10, borderRadius: 3, background: 'var(--pb-surface-alt)', color: 'var(--pb-fg-muted)', border: '1px solid var(--pb-border)' }}>
                          {tag}
                        </span>
                      ))}
                    </div>
                  </div>

                  {/* 3-year cutoff bar chart */}
                  <div style={{ padding: '16px 16px 8px', borderBottom: '1px solid var(--pb-border)' }}>
                    <div style={{ fontSize: 11, color: 'var(--pb-fg-muted)', marginBottom: 8, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                      {lang === 'zh' ? '投档线（3 年）' : '3-Year Cutoff Score'}
                    </div>
                    <MiniBarChart rows={cutoffRows} province={province} />
                  </div>

                  {/* 3-year rank table */}
                  <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--pb-border)' }}>
                    <div style={{ fontSize: 11, color: 'var(--pb-fg-muted)', marginBottom: 8, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                      {lang === 'zh' ? '投档位次' : 'Cutoff Rank'}
                    </div>
                    <div style={{ display: 'flex', gap: 8 }}>
                      {cutoffRows.map(r => (
                        <div key={r.year} style={{ flex: 1, textAlign: 'center' }}>
                          <div style={{ fontSize: 11, color: 'var(--pb-fg-muted)', marginBottom: 2 }}>{r.year}</div>
                          <div style={{ fontFamily: 'var(--pb-mono)', fontSize: 13, fontWeight: 600 }}>
                            {r.rank ? '#' + r.rank.toLocaleString() : '—'}
                          </div>
                        </div>
                      ))}
                    </div>
                  </div>

                  {/* Admission probability */}
                  <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--pb-border)' }}>
                    <div style={{ fontSize: 11, color: 'var(--pb-fg-muted)', marginBottom: 8, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                      {lang === 'zh' ? '录取概率' : 'Admission Probability'}
                    </div>
                    {!rank ? (
                      <div style={{ fontSize: 12, color: 'var(--pb-fg-muted)' }}>
                        {lang === 'zh' ? '请在 URL 中提供位次' : 'Provide rank in URL'}
                      </div>
                    ) : !probResult ? (
                      <div style={{ fontSize: 12, color: 'var(--pb-fg-muted)' }}>
                        {lang === 'zh' ? `${province} 暂无数据` : `No data for ${province}`}
                      </div>
                    ) : (
                      <div>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
                          <div className="pb-prob-track" style={{ flex: 1 }}>
                            <div className={`pb-prob-fill ${probResult.bucket}`} style={{ width: `${probResult.prob}%` }}/>
                          </div>
                          <span style={{ fontFamily: 'var(--pb-mono)', fontSize: 15, fontWeight: 700, minWidth: 40, textAlign: 'right' }}>{probResult.prob}%</span>
                        </div>
                        <span style={{
                          padding: '2px 8px', fontSize: 10, fontWeight: 600, borderRadius: 4,
                          background: tierColor[probResult.bucket] + '20',
                          color: tierColor[probResult.bucket],
                          textTransform: 'uppercase',
                        }}>
                          {tierLabel[probResult.bucket]}
                        </span>
                      </div>
                    )}
                  </div>

                  {/* Subject compatibility */}
                  <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--pb-border)' }}>
                    <div style={{ fontSize: 11, color: 'var(--pb-fg-muted)', marginBottom: 8, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                      {lang === 'zh' ? '选科兼容' : 'Subject Compat'}
                    </div>
                    {currentCombo ? (() => {
                      // For CUTOFFS-based schools we don't have per-school reqStr in this dataset;
                      // show a generic compat check based on whether school has data in selected province.
                      const hasProvData = !!(CUTOFFS[province] && CUTOFFS[province][id]);
                      return (
                        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                          {hasProvData ? (
                            <span style={{ color: 'var(--pb-success)', fontWeight: 700, fontSize: 16 }}>✓</span>
                          ) : (
                            <span style={{ color: 'var(--pb-danger)', fontWeight: 700, fontSize: 16 }}>✗</span>
                          )}
                          <span style={{ fontSize: 12 }}>
                            {hasProvData
                              ? (lang === 'zh' ? `${province} 有数据` : `${province} data available`)
                              : (lang === 'zh' ? `${province} 暂无数据` : `No data for ${province}`)}
                          </span>
                        </div>
                      );
                    })() : (
                      <div style={{ fontSize: 12, color: 'var(--pb-fg-muted)' }}>—</div>
                    )}
                    {currentCombo && (
                      <div style={{ marginTop: 6, fontSize: 11, color: 'var(--pb-fg-muted)' }}>
                        {lang === 'zh' ? `选科：${currentCombo.labelZh}` : `Combo: ${currentCombo.labelEn}`}
                      </div>
                    )}
                  </div>

                  {/* Data source note */}
                  <div style={{ padding: '10px 16px', fontSize: 10, color: 'var(--pb-fg-muted)', lineHeight: 1.5 }}>
                    {lang === 'zh'
                      ? '来源：各省教育考试院公开投档线 · 近 3 年物理类普通批'
                      : 'Source: Provincial exam bureau — physics-track 普通批, last 3 yrs'}
                  </div>
                </div>
              );
            })}
          </div>

          {/* Score/rank user context card */}
          {(score || rank) && (
            <div className="pb-card" style={{ marginTop: 24, padding: '16px 24px', display: 'flex', gap: 32, alignItems: 'center', flexWrap: 'wrap' }} data-testid="compare-user-context">
              <div style={{ fontSize: 12, color: 'var(--pb-fg-muted)', fontWeight: 600 }}>
                {lang === 'zh' ? '你的成绩' : 'Your scores'}
              </div>
              {score > 0 && (
                <div>
                  <span style={{ fontFamily: 'var(--pb-mono)', fontSize: 22, fontWeight: 700 }}>{score}</span>
                  <span style={{ fontSize: 11, color: 'var(--pb-fg-muted)', marginLeft: 4 }}>{lang === 'zh' ? '分' : 'pts'}</span>
                </div>
              )}
              {rank > 0 && (
                <div>
                  <span style={{ fontFamily: 'var(--pb-mono)', fontSize: 22, fontWeight: 700 }}>#{rank.toLocaleString()}</span>
                  <span style={{ fontSize: 11, color: 'var(--pb-fg-muted)', marginLeft: 4 }}>{lang === 'zh' ? '位次' : 'rank'}</span>
                </div>
              )}
              <div style={{ marginLeft: 'auto' }}>
                <button className="pb-btn pb-btn-link pb-btn-sm" onClick={() => navigateTo('/gaokao')}>
                  {lang === 'zh' ? '← 返回测算页' : '← Back to calculator'}
                </button>
              </div>
            </div>
          )}
        </div>
      </section>

      <PBFooter />
    </div>
  );
};

// Expose to window
Object.assign(window, { GaokaoComparePage });
