// ─── Wave 12-B — AdmissionsRollBlock ──────────────────────────────────────────
// Displays "已录取学长榜" — a list of real alumni admission cases near the user's
// score (±20 points). Data is fetched from /data/admissions-roll/<province>/<year>.json
// and filtered client-side.
//
// Props:
//   province     (string)  — province code e.g. 'HI'
//   year         (number)  — gaokao year e.g. 2024
//   score        (number)  — user's gaokao score
//   subjectCombo (string)  — subject combo e.g. '物化生', '政史地'
//   lang         (string)  — 'zh' | 'en'
//
// data-testid: "admissions-roll-block" / "roll-card-{caseId}"

// F7 silent 404 fallback: known available years for admissions-roll. Must
// stay in sync with the inline `_DATA_BY_PROVINCE_YEAR` map inside
// lib/gaokao-admissions-roll-loader.js. When the requested year is not
// listed here the component skips the HTTP fetch entirely, avoiding red
// 404 entries in the browser console.
const ADMISSIONS_ROLL_AVAILABLE_YEARS = {
  HI: [2024],
};

const AdmissionsRollBlock = ({ province, year, score, subjectCombo, lang }) => {
  const [cases, setCases] = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [showAll, setShowAll] = React.useState(false);

  const prov = (province || 'HI').toUpperCase();
  const yr = Number(year) || 2024;
  const targetScore = Number(score);
  const SCORE_WINDOW = 20;
  const INITIAL_DISPLAY = 5;

  const dict = React.useMemo(() => {
    const d = (window.I18N && window.I18N[lang] && window.I18N[lang].gk && window.I18N[lang].gk.admissionsRoll)
      || (window.I18N && window.I18N.zh && window.I18N.zh.gk && window.I18N.zh.gk.admissionsRoll)
      || {};
    return {
      eyebrow:     d.eyebrow     || (lang === 'zh' ? '真实录取案例' : 'Real admission cases'),
      title:       d.title       || (lang === 'zh' ? '已录取学长榜' : 'Alumni Admissions Roll'),
      subtitle:    d.subtitle    || (lang === 'zh' ? `与你分数相近（±${SCORE_WINDOW} 分）的学长学姐录取案例` : `Alumni admitted within ±${SCORE_WINDOW} pts of your score`),
      scoreLabel:  d.scoreLabel  || (lang === 'zh' ? '分' : 'pts'),
      rankLabel:   d.rankLabel   || (lang === 'zh' ? '位次' : 'rank'),
      major:       d.major       || (lang === 'zh' ? '专业' : 'Major'),
      school:      d.school      || (lang === 'zh' ? '学校' : 'School'),
      batch:       d.batch       || (lang === 'zh' ? '批次' : 'Batch'),
      origin:      d.origin      || (lang === 'zh' ? '来源' : 'Origin'),
      showMore:    d.showMore    || (lang === 'zh' ? '查看更多案例' : 'Show more cases'),
      showLess:    d.showLess    || (lang === 'zh' ? '收起' : 'Show less'),
      noData:      d.noData      || (lang === 'zh' ? '该分段暂无公开录取案例' : 'No public cases found for this score range'),
      sourceNote:  d.sourceNote  || (lang === 'zh' ? '* 案例基于教育考试院公开数据推导，仅供参考' : '* Cases derived from public exam bureau data for reference only'),
      bioLabel:    d.bioLabel    || (lang === 'zh' ? '学生背景' : 'Student profile'),
    };
  }, [lang, SCORE_WINDOW]);

  React.useEffect(() => {
    if (!Number.isFinite(targetScore) || targetScore <= 0) return;

    // F7 silent 404 fallback: skip the fetch entirely for years that have no
    // data on disk. A fetch().catch() can swallow the rejected promise but
    // cannot suppress the browser's red 404 console entry, so we have to
    // not issue the request at all.
    const availableYears = ADMISSIONS_ROLL_AVAILABLE_YEARS[prov] || [];
    if (!availableYears.includes(yr)) {
      setCases([]);
      setLoading(false);
      setError(false);
      return;
    }

    setLoading(true);
    setError(null);

    fetch(`/data/admissions-roll/${prov}/${yr}.json`)
      .then((res) => {
        // Defensive: any non-2xx (including a stray 404 from a CDN edge or
        // a year that was on the AVAILABLE_YEARS list but truly missing in
        // prod) silently resolves to an empty dataset. No throw, no console
        // error from this code path.
        if (!res.ok) return [];
        return res.json();
      })
      .then((data) => {
        if (!Array.isArray(data)) { setCases([]); setLoading(false); return; }

        // Filter by score window ±20 and optionally match subjectCombo
        let filtered = data.filter((c) => {
          if (!c || typeof c.score !== 'number') return false;
          return Math.abs(c.score - targetScore) <= SCORE_WINDOW;
        });

        // Soft-prefer same subjectCombo but don't hard-filter (show all in window)
        const combo = (subjectCombo || '').trim();
        if (combo) {
          // Sort: same combo first, then by score proximity
          filtered.sort((a, b) => {
            const aMatch = (a.subjectCombo || '').includes(combo) ? 0 : 1;
            const bMatch = (b.subjectCombo || '').includes(combo) ? 0 : 1;
            if (aMatch !== bMatch) return aMatch - bMatch;
            return Math.abs(a.score - targetScore) - Math.abs(b.score - targetScore);
          });
        } else {
          filtered.sort((a, b) => Math.abs(a.score - targetScore) - Math.abs(b.score - targetScore));
        }

        setCases(filtered);
        setLoading(false);
      })
      .catch(() => {
        // Silent fallback: a transient network/parse error renders as
        // "no cases" rather than triggering an error banner.
        setCases([]);
        setLoading(false);
      });
  }, [prov, yr, targetScore, subjectCombo]);

  // Don't render if score not entered yet
  if (!Number.isFinite(targetScore) || targetScore <= 0) return null;
  // Don't render on error (fail silently)
  if (error) return null;
  // Don't render while loading (no spinner to keep UI clean)
  if (loading) return null;
  // Don't render if no cases found but don't crash
  if (cases.length === 0) return null;

  const displayed = showAll ? cases : cases.slice(0, INITIAL_DISPLAY);

  return (
    <div
      data-testid="admissions-roll-block"
      className="pb-card"
      style={{ padding: '28px 32px', display: 'flex', flexDirection: 'column', gap: 20 }}
    >
      {/* Header */}
      <div>
        <div
          className="pb-eyebrow"
          style={{ color: 'var(--pb-gold-700)', marginBottom: 8 }}
        >
          {dict.eyebrow}
        </div>
        <h4
          style={{
            fontFamily: 'var(--pb-serif)',
            fontSize: 20,
            fontWeight: 600,
            margin: '0 0 6px',
            color: 'var(--pb-fg)',
          }}
        >
          {dict.title}
          <span
            style={{
              display: 'inline-block',
              marginLeft: 10,
              padding: '2px 10px',
              fontSize: 12,
              fontFamily: 'var(--pb-mono)',
              fontWeight: 500,
              background: 'var(--pb-gold-100, rgba(212,175,55,0.12))',
              color: 'var(--pb-gold-700)',
              borderRadius: 100,
              verticalAlign: 'middle',
            }}
          >
            {cases.length}
          </span>
        </h4>
        <p style={{ fontSize: 13, color: 'var(--pb-fg-muted)', margin: 0, lineHeight: 1.6 }}>
          {dict.subtitle}
        </p>
      </div>

      {/* Cards */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        {displayed.map((c) => {
          const scoreDiff = c.score - targetScore;
          const diffLabel = scoreDiff > 0 ? `+${scoreDiff}` : String(scoreDiff);
          const diffColor = scoreDiff > 0 ? '#4caf74' : scoreDiff < 0 ? '#e05252' : '#9ca3af';

          return (
            <div
              key={c.caseId}
              data-testid={`roll-card-${c.caseId}`}
              style={{
                background: 'var(--pb-surface-alt, var(--pb-paper))',
                border: '1px solid var(--pb-border)',
                borderRadius: 'var(--pb-radius)',
                padding: '16px 20px',
                display: 'flex',
                flexDirection: 'column',
                gap: 8,
              }}
            >
              {/* Row 1: school + major */}
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12, flexWrap: 'wrap' }}>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <span
                    style={{
                      fontFamily: 'var(--pb-serif)',
                      fontSize: 15,
                      fontWeight: 600,
                      color: 'var(--pb-fg)',
                      display: 'block',
                      marginBottom: 2,
                    }}
                  >
                    {c.schoolName}
                  </span>
                  <span style={{ fontSize: 13, color: 'var(--pb-fg-muted)' }}>
                    {c.major}
                  </span>
                </div>
                {/* Score badge */}
                <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 2, flexShrink: 0 }}>
                  <span
                    style={{
                      fontFamily: 'var(--pb-mono)',
                      fontSize: 18,
                      fontWeight: 700,
                      color: 'var(--pb-fg)',
                      lineHeight: 1,
                    }}
                  >
                    {c.score}
                    <span style={{ fontSize: 12, fontWeight: 400, marginLeft: 2 }}>{dict.scoreLabel}</span>
                  </span>
                  <span style={{ fontFamily: 'var(--pb-mono)', fontSize: 11, color: diffColor, fontWeight: 600 }}>
                    {diffLabel} {lang === 'zh' ? '分' : 'pts'}
                  </span>
                </div>
              </div>

              {/* Row 2: chips */}
              <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                {c.subjectCombo && (
                  <span style={chipStyle('#6366f1', 0.12)}>
                    {c.subjectCombo}
                  </span>
                )}
                {c.batch && (
                  <span style={chipStyle('#0ea5e9', 0.12)}>
                    {c.batch}
                  </span>
                )}
                {c.rank && (
                  <span style={chipStyle('#64748b', 0.10)}>
                    {dict.rankLabel} #{c.rank.toLocaleString()}
                  </span>
                )}
                {c.origin && (
                  <span style={chipStyle('#8b5cf6', 0.10)}>
                    {c.origin}
                  </span>
                )}
              </div>

              {/* Row 3: student bio (optional) */}
              {c.studentBio && (
                <div style={{ fontSize: 12, color: 'var(--pb-fg-muted)', lineHeight: 1.5 }}>
                  <span style={{ fontWeight: 600, marginRight: 4 }}>
                    {lang === 'zh' ? '学生背景：' : 'Profile:'}
                  </span>
                  {c.studentBio}
                </div>
              )}
            </div>
          );
        })}
      </div>

      {/* Show more / show less */}
      {cases.length > INITIAL_DISPLAY && (
        <button
          type="button"
          onClick={() => setShowAll((v) => !v)}
          style={{
            alignSelf: 'center',
            background: 'transparent',
            border: '1px solid var(--pb-border)',
            borderRadius: 100,
            padding: '7px 20px',
            fontSize: 13,
            fontWeight: 500,
            color: 'var(--pb-fg-muted)',
            cursor: 'pointer',
            transition: 'border-color 0.15s, color 0.15s',
          }}
          onMouseEnter={(e) => {
            e.currentTarget.style.borderColor = 'var(--pb-gold-500)';
            e.currentTarget.style.color = 'var(--pb-gold-700)';
          }}
          onMouseLeave={(e) => {
            e.currentTarget.style.borderColor = 'var(--pb-border)';
            e.currentTarget.style.color = 'var(--pb-fg-muted)';
          }}
        >
          {showAll ? dict.showLess : `${dict.showMore} (${cases.length - INITIAL_DISPLAY})`}
        </button>
      )}

      {/* Source note */}
      <div
        style={{
          borderTop: '1px solid var(--pb-border)',
          paddingTop: 12,
          fontSize: 11,
          color: 'var(--pb-fg-muted)',
          lineHeight: 1.5,
        }}
      >
        {dict.sourceNote}
      </div>
    </div>
  );
};

// Shared chip style helper (pure function, no hook)
function chipStyle(color, alpha) {
  return {
    display: 'inline-flex',
    alignItems: 'center',
    padding: '2px 8px',
    fontSize: 11,
    fontWeight: 500,
    borderRadius: 100,
    background: `${color}${Math.round(alpha * 255).toString(16).padStart(2, '0')}`,
    color: color,
    letterSpacing: '0.02em',
  };
}

window.AdmissionsRollBlock = AdmissionsRollBlock;
