/* champions.jsx — 「栄冠」タブ。歴代の1〜3位（公式サイト「栄光の足跡」）を見せる画面。
   データは champions.js（window.KANSAI.CHAMPIONS）。第1回〜第37回・606行。
   上のチップで3つの見方を切り替える：
     ① 学校別 … 優勝（1位）の回数ランキング。男子・女子の内訳つき
     ② 年表   … 回ごとに6種目の優勝校を並べる（新しい回が上）
     ③ 種目別 … 種目を選ぶと、その種目の1〜3位が回ごとに並ぶ
   ※高校生の大会なので、載せるのは公式が公表している情報だけ。
     選手名はシングルスカルの分だけ（原典に載っているもの）を出す。 */

// 学校名の末尾の「高校／高等学校」を落とす。原典（栄光の足跡）と今大会の名簿で
// 書き方が違うので、突き合わせるときはこの形にそろえる。
function chBase(s) {
  return String(s || "").replace(/(高等学校|高校)$/, "").replace(/中学・$/, "");
}
// 数えるとき用のキー。原典の書き方のゆれ（見方＝美方 など）は meta.alias でまとめる。
function chKey(s, alias) {
  const b = chBase(s);
  return (alias && alias[b]) || b;
}
// "M:SS.dd" → 秒。並べ替え用。
function chSec(t) {
  const m = /^(\d+):(\d+)\.(\d+)$/.exec(String(t || ""));
  return m ? Number(m[1]) * 60 + Number(m[2]) + Number("0." + m[3]) : null;
}
// 種目キーの頭文字で男女を分ける（M4X+ → 男子）
const chCat = (ev) => (String(ev).charAt(0) === "M" ? "m" : "w");

// 1つの回の中で種目を並べる順（大きい艇から小さい艇へ）。
// 第1回だけ舵手つきフォアなので、クォドルプルと同じ位置に来るようにしてある。
const CH_ROW_ORDER = ["M4X+", "W4X+", "M4+", "W4+", "M2X", "W2X", "M1X", "W1X"];
const chRowSort = (a, b) => CH_ROW_ORDER.indexOf(a.ev) - CH_ROW_ORDER.indexOf(b.ev);

// 今大会のエントリーに同じ学校があれば、その名簿どおりの名前を返す（チームタブへ飛ぶため）。
// 「加茂」と「美濃加茂」のような取り違えを避けるため、部分一致は4文字以上のときだけ許す。
function chTeamOf(school) {
  const RW = window.RW;
  if (!RW || !RW.TEAM_NAMES) return null;
  const b = chBase(school);
  if (!b) return null;
  let hit = RW.TEAM_NAMES.find((t) => chBase(t) === b);
  if (!hit && b.length >= 4) hit = RW.TEAM_NAMES.find((t) => chBase(t).endsWith(b));
  if (!hit && b.length >= 4) hit = RW.TEAM_NAMES.find((t) => chBase(t).length >= 4 && b.endsWith(chBase(t)));
  return hit || null;
}

// 種目コードのバッジ（男子＝青／女子＝赤。既存の .code をそのまま使う）
function ChCode({ ev, meta }) {
  return <span className={"code" + (chCat(ev) === "w" ? " w" : "")}>{(meta.evCode && meta.evCode[ev]) || ev}</span>;
}

// 1行ぶんの「学校（都道府県）＋選手名＋タイム」。順位の色は呼び出し側で決める。
// 種目コード（M4X+）→ サイトの種目キー（m4xc）。年表で印を出すために逆引きする。
const CH_KEY_OF = { "M4X+": "m4xc", "W4X+": "w4xc", "M2X": "m2x", "W2X": "w2x", "M1X": "m1x", "W1X": "w1x" };

function ChLine({ r, meta, gold }) {
  // 1位の行に「初優勝」「N連覇」などの印。その回の時点で判定する（curEd = r.ed）。
  const note = (gold && r.rank === 1 && CH_KEY_OF[r.ev]) ? chWinNote(CH_KEY_OF[r.ev], r.school, r.ed) : null;
  return (
    <React.Fragment>
      <span className="ch-nm">
        <b className={gold ? "ch-gold" : ""}>{r.school}</b>
        {note && <em className={"chnote " + note.kind}>{note.text}</em>}
        {r.athlete ? <span className="ch-ath">{r.athlete}</span> : null}
        {r.pref ? <span className="ch-pref">{r.pref}</span> : null}
      </span>
      <span className="ch-sp" />
      <span className={"ch-t" + (gold ? " g" : "")}>{r.t}</span>
    </React.Fragment>
  );
}

/* ---------------- ① 学校別 優勝回数ランキング ---------------- */
function ChSchoolRank({ C, onOpenTeam }) {
  const [cat, setCat] = React.useState("all");
  const [open, setOpen] = React.useState(null);
  const [all, setAll] = React.useState(false);

  // 学校ごとに1〜3位の行を集める（1回だけ計算する）
  const bySchool = React.useMemo(() => {
    const map = {};
    C.rows.forEach((r) => {
      const k = chKey(r.school, C.meta.alias);
      if (!map[k]) map[k] = { key: k, pref: "", rows: [] };
      map[k].rows.push(r);
      if (!map[k].pref && r.pref) map[k].pref = r.pref;   // 行は新しい回から並んでいる
    });
    return Object.keys(map).map((k) => map[k]);
  }, [C]);

  // 男女フィルタをかけて、優勝回数で並べ替える
  const list = React.useMemo(() => {
    const out = [];
    bySchool.forEach((it) => {
      const rows = it.rows.filter((r) => cat === "all" || chCat(r.ev) === cat);
      const wins = rows.filter((r) => r.rank === 1);
      if (!wins.length) return;
      out.push({
        key: it.key, pref: it.pref,
        wins: wins,
        n: wins.length,
        m: wins.filter((r) => chCat(r.ev) === "m").length,
        w: wins.filter((r) => chCat(r.ev) === "w").length,
        n2: rows.filter((r) => r.rank === 2).length,
        n3: rows.filter((r) => r.rank === 3).length,
        last: wins[0],
      });
    });
    out.sort((a, b) => b.n - a.n || b.n2 - a.n2 || b.last.ed - a.last.ed || a.key.localeCompare(b.key, "ja"));
    return out;
  }, [bySchool, cat]);

  if (!list.length) return <div className="empty">記録がありません。</div>;
  const max = list[0].n;
  const shown = all ? list : list.slice(0, 20);

  return (
    <React.Fragment>
      <div className="chips">
        {[["all", "男女あわせて"], ["m", "男子"], ["w", "女子"]].map(([c, l]) => (
          <button key={c} type="button" className={"chip" + (cat === c ? " on" : "")} onClick={() => { setCat(c); setOpen(null); setAll(false); }}>{l}</button>
        ))}
      </div>

      {cat === "all" && (
        <div className="ch-legend">
          <span><i className="ch-dot m" />男子の優勝</span>
          <span><i className="ch-dot w" />女子の優勝</span>
        </div>
      )}

      <div className="mbt-chart">
        {shown.map((it, i) => {
          const isOpen = open === it.key;
          const team = chTeamOf(it.key);
          return (
            <div className={"mbt-item" + (isOpen ? " open" : "")} key={it.key}>
              <div className="ch-row" onClick={() => setOpen(isOpen ? null : it.key)}>
                <span className="mbt-rk">{i + 1}</span>
                <span className="ch-tm">
                  <b>{it.key}</b>
                  {it.pref ? <span className="ch-pref">{it.pref}</span> : null}
                </span>
                <span className="ch-bar">
                  <span className="ch-fill" style={{ width: Math.round((it.n / max) * 100) + "%" }}>
                    {it.m > 0 && <i className="ch-seg m" style={{ flexGrow: it.m }} />}
                    {it.w > 0 && <i className="ch-seg w" style={{ flexGrow: it.w }} />}
                  </span>
                </span>
                <span className="ch-cnt"><b>{it.n}</b>回</span>
              </div>

              {isOpen && (
                <div className="ch-det">
                  <div className="ch-detline">
                    優勝 {it.n}回{cat === "all" && (it.m > 0 || it.w > 0) ? "（男子 " + it.m + "・女子 " + it.w + "）" : ""}
                    　2位 {it.n2}回　3位 {it.n3}回
                  </div>
                  <div className="ch-wchips">
                    {it.wins.map((r, k) => (
                      <span className="ch-wchip" key={k}>
                        <b>第{r.ed}回</b><i className="ch-wyr">（{r.year}年）</i>{(C.meta.evCode && C.meta.evCode[r.ev]) || r.ev}
                      </span>
                    ))}
                  </div>
                  {team && onOpenTeam && (
                    <button type="button" className="ch-golink" onClick={() => onOpenTeam(team)}>
                      {team}（今大会も出場）のページを見る ›
                    </button>
                  )}
                </div>
              )}
            </div>
          );
        })}
      </div>

      {!all && list.length > shown.length && (
        <button type="button" className="ch-more" onClick={() => setAll(true)}>
          残り{list.length - shown.length}校を表示（優勝した学校は全部で{list.length}校）
        </button>
      )}
      <p className="ch-src">
        1位になった回数で並べています。行をタップすると、優勝した回と種目が出ます。<br />
        原典で書き方が違う学校名（例：「熊学大付属」と「熊本学園大学付属」）は、同じ学校としてまとめて数えています。
      </p>
    </React.Fragment>
  );
}

/* ---------------- ② 年表（回ごとの優勝校） ---------------- */
function ChTimeline({ C }) {
  const [n, setN] = React.useState(10);

  const items = React.useMemo(() => {
    const gap = {};
    (C.meta.gaps || []).forEach((g) => { gap[g.ed] = g; });
    const has = {};
    C.rows.forEach((r) => { has[r.ed] = true; });
    const out = [];
    for (let e = C.meta.edTo; e >= C.meta.edFrom; e--) {
      if (gap[e]) out.push({ gap: gap[e], ed: e });
      else if (has[e]) out.push({ ed: e });
    }
    return out;
  }, [C]);

  const shown = items.slice(0, n);

  return (
    <React.Fragment>
      {shown.map((it) => {
        if (it.gap) {
          return (
            <div className="ch-gap" key={"g" + it.ed}>
              <span className="ch-edn">第{it.ed}回</span>
              <span className="ch-yr">{it.gap.year}年</span>
              <span className="ch-gaptx">{it.gap.text}</span>
            </div>
          );
        }
        const rows = C.rows.filter((r) => r.ed === it.ed && r.rank === 1).slice().sort(chRowSort);
        const year = rows.length ? rows[0].year : "";
        const dist = rows.length ? rows[0].dist : "";
        const short = (C.meta.shortCourse || []).indexOf(it.ed) >= 0;
        return (
          <div className="ch-ed" key={it.ed}>
            <div className="ch-edhd">
              <span className="ch-edn">第{it.ed}回</span>
              <span className="ch-yr">{year}年</span>
              <span className="ch-sp" />
              {dist ? <span className="ch-dist">{dist}{short ? "（悪天候で短縮）" : ""}</span> : null}
            </div>
            {rows.map((r, k) => (
              <div className="ch-win" key={k}>
                <ChCode ev={r.ev} meta={C.meta} />
                <ChLine r={r} meta={C.meta} gold={true} />
              </div>
            ))}
            {rows.filter((r) => r.note).map((r, k) => (
              <div className="ch-noteline" key={"n" + k}>
                ※{(C.meta.evCode && C.meta.evCode[r.ev]) || r.ev}：{r.note}
              </div>
            ))}
          </div>
        );
      })}

      {n < items.length && (
        <button type="button" className="ch-more" onClick={() => setN(n + 12)}>
          さらに古い回を見る（残り{items.length - n}回）
        </button>
      )}
      <p className="ch-src">
        各回の優勝校だけを並べています。第1回だけ、クォドルプルではなく舵手つきフォアで行われました。<br />
        距離は原典の表のとおりです（第12回以降が2000m、第11回以前は1000mと書かれています）。
      </p>
    </React.Fragment>
  );
}

/* ---------------- ③ 種目別（歴代の1〜3位） ---------------- */
function ChByEvent({ C }) {
  const evs = React.useMemo(
    () => (C.meta.order || []).filter((ev) => C.rows.some((r) => r.ev === ev)),
    [C]
  );
  const [ev, setEv] = React.useState(evs[0]);
  const [n, setN] = React.useState(8);

  const rows = React.useMemo(() => C.rows.filter((r) => r.ev === ev), [C, ev]);
  const eds = React.useMemo(() => {
    const seen = [];
    rows.forEach((r) => { if (seen.indexOf(r.ed) < 0) seen.push(r.ed); });
    return seen;
  }, [rows]);

  // 距離がそろっている2000mの回だけで、いちばん速い優勝タイムを出す
  const best = React.useMemo(() => {
    let b = null;
    rows.forEach((r) => {
      if (r.rank !== 1 || r.dist !== "2000m") return;
      const s = chSec(r.t);
      if (s !== null && (!b || s < b.s)) b = { s: s, r: r };
    });
    return b;
  }, [rows]);

  const shown = eds.slice(0, n);
  const isFour = ev === "M4+" || ev === "W4+";

  return (
    <React.Fragment>
      <div className="chips">
        {evs.map((k) => (
          <button key={k} type="button" className={"chip" + (ev === k ? " on" : "")}
                  onClick={() => { setEv(k); setN(8); }}>
            {(C.meta.evCode && C.meta.evCode[k]) || k}{(k === "M4+" || k === "W4+") ? "（第1回）" : ""}
          </button>
        ))}
      </div>

      <div className="subhead">
        <span>{(C.meta.evName && C.meta.evName[ev]) || ev}</span>
        <span className="subnote">{eds.length}回ぶん</span>
      </div>

      {best && (
        <div className="ch-stat">
          2000mで行われた回のうち、いちばん速い優勝タイムは
          <b className="ch-t g">{best.r.t}</b>
          （第{best.r.ed}回・{best.r.year}年・{best.r.school}{best.r.pref ? "／" + best.r.pref : ""}）
        </div>
      )}
      {isFour && (
        <div className="ch-stat">第1回だけ行われた種目です。第2回から舵手つきクォドルプルになりました。</div>
      )}

      {shown.map((edn) => {
        const list = rows.filter((r) => r.ed === edn).slice().sort((a, b) => a.rank - b.rank);
        const head = list[0] || {};
        const short = (C.meta.shortCourse || []).indexOf(edn) >= 0;
        return (
          <div className="ch-ed" key={edn}>
            <div className="ch-edhd">
              <span className="ch-edn">第{edn}回</span>
              <span className="ch-yr">{head.year}年</span>
              <span className="ch-sp" />
              {head.dist ? <span className="ch-dist">{head.dist}{short ? "（悪天候で短縮）" : ""}</span> : <span className="ch-dist">距離の記載なし</span>}
            </div>
            {list.map((r, k) => (
              <React.Fragment key={k}>
                <div className="ch-pod">
                  <span className={"ch-prk " + (r.rank === 1 ? "g" : r.rank === 2 ? "s" : "b")}>{r.rank}位</span>
                  <ChLine r={r} meta={C.meta} gold={r.rank === 1} />
                </div>
                {r.note ? <div className="ch-noteline">※{r.note}</div> : null}
              </React.Fragment>
            ))}
          </div>
        );
      })}

      {n < eds.length && (
        <button type="button" className="ch-more" onClick={() => setN(n + 12)}>
          さらに古い回を見る（残り{eds.length - n}回）
        </button>
      )}
      <p className="ch-src">
        シングルスカルの（　）内は、原典に載っている選手名です。<br />
        距離が違う回があるので、タイムをそのまま比べられるのは同じ距離どうしだけです。
      </p>
    </React.Fragment>
  );
}

/* ---------------- 栄冠タブ本体 ---------------- */
/* ── ほかのタブから使う共通ヘルパー ───────────────────────────
   学校ページ（teams.jsx）・大会タブ（results.jsx）・ホーム（home.jsx）から、
   歴代データ（champions.js）を引くための入口。ここに集約して window へ出す。 */

// サイトの種目キー → 歴代データの種目コード。
// 第1回だけの舵手つきフォア（M4+/W4+）は今大会に無いので対応させない。
const CH_EV_OF = { m4xc: "M4X+", w4xc: "W4X+", m2x: "M2X", w2x: "W2X", m1x: "M1X", w1x: "W1X" };
function chEvOf(evKey) { return CH_EV_OF[String(evKey || "")] || null; }

// 今大会の学校名（例「美方高校」）→ その学校の歴代1〜3位。
// 表記ゆれ（見方＝美方、熊学大付属＝熊本学園大学付属 など）は meta.alias でまとめる。
// 「加茂」と「美濃加茂」の取り違えを避けるため、部分一致はしない（完全一致のみ）。
function chRowsForTeam(team) {
  const C = window.KANSAI && window.KANSAI.CHAMPIONS;
  const RW = window.RW;
  if (!C || !C.rows || !team) return null;
  const alias = C.meta && C.meta.alias;
  const k = chKey((RW && RW.baseTeam) ? RW.baseTeam(team) : team, alias);
  if (!k) return null;
  const rows = C.rows.filter((r) => chKey(r.school, alias) === k)
    .sort((a, b) => b.ed - a.ed || CH_ROW_ORDER.indexOf(a.ev) - CH_ROW_ORDER.indexOf(b.ev));
  if (!rows.length) return null;
  const wins = rows.filter((r) => r.rank === 1);
  return {
    key: k, rows, wins,
    n1: wins.length,
    n2: rows.filter((r) => r.rank === 2).length,
    n3: rows.filter((r) => r.rank === 3).length,
    m: wins.filter((r) => chCat(r.ev) === "m").length,
    w: wins.filter((r) => chCat(r.ev) === "w").length,
  };
}

// 優勝の印（初優勝／N連覇／X年ぶりN回目）。curEd＝今大会の回（第37回なら 37）。
// ・今大会の結果も歴代データに入っているので、ed < curEd で必ず除外する。
// ・中止・記録なしの回（第18・22・31回）は飛ばして連覇を数える。
function chWinNote(evKey, team, curEd) {
  const C = window.KANSAI && window.KANSAI.CHAMPIONS;
  const RW = window.RW;
  const ev = chEvOf(evKey);
  if (!C || !C.rows || !ev || !team) return null;
  const cur = Number(curEd || (C.meta && C.meta.edTo) || 0);
  if (!cur) return null;
  const alias = C.meta && C.meta.alias;
  const k = chKey((RW && RW.baseTeam) ? RW.baseTeam(team) : team, alias);
  if (!k) return null;

  // 記録が無い回（中止・決勝中止）。連覇を数えるときは飛ばす。
  const skip = new Set([].concat((C.meta && C.meta.cancelled) || [], ((C.meta && C.meta.gaps) || []).map((g) => g.ed)));

  const prev = C.rows.filter((r) => r.ev === ev && r.rank === 1 && r.ed < cur && chKey(r.school, alias) === k)
    .sort((a, b) => b.ed - a.ed);

  // 連覇：ひとつ前の回から遡り、同じ学校が1位である限り数える
  let streak = 1;
  for (let ed = cur - 1; ed >= 1; ed--) {
    if (skip.has(ed)) continue;
    const win = C.rows.find((r) => r.ev === ev && r.rank === 1 && r.ed === ed);
    if (win && chKey(win.school, alias) === k) streak++; else break;
  }

  if (streak >= 2) return { kind: "streak", text: streak + "連覇" };
  if (!prev.length) {
    // この種目で初。ほかの種目で優勝していれば「この種目で初優勝」と区別する
    const other = C.rows.some((r) => r.rank === 1 && r.ed < cur && chKey(r.school, alias) === k);
    return other ? { kind: "firstEv", text: "この種目で初優勝" } : { kind: "first", text: "初優勝" };
  }
  const last = prev[0];
  const yrs = (C.rows.find((r) => r.ed === cur) || {}).year - last.year;
  const times = prev.length + 1;
  return { kind: "return", text: (yrs > 0 ? yrs + "年ぶり" : "") + times + "回目" };
}

function ChampionsView({ onOpenTeam }) {
  const C = window.KANSAI && window.KANSAI.CHAMPIONS;
  const [mode, setMode] = React.useState("school");

  if (!C || !C.rows || !C.rows.length) {
    return (
      <section className="view">
        <div className="shead"><span className="tag"><span>CHAMPIONS</span></span><span className="jp">歴代の1〜3位</span></div>
        <div className="empty">歴代の記録を読み込めませんでした。</div>
      </section>
    );
  }

  return (
    <section className="view">
      <div className="shead">
        <span className="tag"><span>CHAMPIONS</span></span>
        <span className="jp">歴代の1〜3位</span>
        <span className="sp" />
        <span className="meta">第{C.meta.edFrom}回〜第{C.meta.edTo}回</span>
      </div>
      <p className="ch-lead">
        1990年の第1回から、いままでの各種目1〜3位です。第18回は大雨で準決勝・決勝が中止、
        第22回と第31回は大会そのものが中止になったため、その回の記録はありません。
      </p>

      <div className="chips">
        {[["school", "学校別"], ["year", "年表"], ["event", "種目別"]].map(([k, l]) => (
          <button key={k} type="button" className={"chip" + (mode === k ? " on" : "")} onClick={() => setMode(k)}>{l}</button>
        ))}
      </div>

      {mode === "school" && <ChSchoolRank C={C} onOpenTeam={onOpenTeam} />}
      {mode === "year" && <ChTimeline C={C} />}
      {mode === "event" && <ChByEvent C={C} />}

      <p className="ch-src">
        出典：{C.meta.source}（<a href={C.meta.url} target="_blank" rel="noopener noreferrer">rowing-szo.com</a>）。
        学校名・タイムは原典のまま載せています。書き方が原典で違っているところには「※」で注を付けました。
      </p>
    </section>
  );
}

Object.assign(window, { ChampionsView, ChSchoolRank, ChTimeline, ChByEvent,
  chBase, chKey, chEvOf, chRowsForTeam, chWinNote });
