/* rules.jsx — ルール ◯✕クイズ。各問1回だけ回答可能。
   回答・解説は localStorage に保存し、リセットを押すまで残り続ける。
   出典：2026年度関西選手権『レースに当たっての審判上の注意』 */
const QUIZ_KEY = "kansai2026_quiz_v1";

const QUIZ = [
  { q: "出漕クルーは発艇定刻の2分前までに、所定の発艇位置（ステイクボート）に着かなければならない。", a: true,
    exp: "正しい。2分前までに着けないとイエローカード、技量未熟で発艇時刻から3分以上遅れるとレッドカードの対象です。" },
  { q: "バウナンバープレートは、ガンネル（舷側）に装着してもよい。", a: false,
    exp: "誤り。艇首付近に装着します。ガンネルへの装着は認められず、未装着はレッドカードの対象になることがあります。" },
  { q: "舵手（コックス）を欠いたままフィニッシュラインに到達した場合は失格となる。", a: true,
    exp: "正しい。漕手が故意でなく落水しそのまま到達した場合は着順を認めますが、舵を欠いての到達は失格です。" },
  { q: "本コースの回漕水域には、コースとの境界ブイが設置されている。", a: false,
    exp: "誤り。本コースの回漕水域には境界ブイがありません。航行の際は他艇に十分注意してください。" },
  { q: "レース中、コースに沿って自転車でクルーに伴走してもよい。", a: false,
    exp: "誤り。伴走はいかなる場合も厳禁です。発見された場合、関係クルーは失格となります。" },
  { q: "発艇時、発艇猶予を求めるための挙手は原則として認められない。", a: true,
    exp: "正しい。各クルーは2分前までに準備を完了し、ロールコール後はいつでも発艇できるように。発艇号令は英語です。" },
  { q: "舵手計量のとき、帽子や靴下を着用したまま計量してもよい。", a: false,
    exp: "誤り。計量はユニフォーム及び一部の認められた装備のみ。帽子・アンダーシャツ・アンダーレギンス・靴下などは着用できません。" },
  { q: "同一ラウンド内でイエローカードを2回受けると、レッドカード（除外）となる。", a: true,
    exp: "正しい。イエロー2回でレッドカード、レッドカードを受けると除外です。警告は白旗が上がった時点で解消されます。" },
  { q: "レースに関する異議申し立ては、口頭でいつでも受け付けてもらえる。", a: false,
    exp: "誤り。裁決に不服の場合は1時間以内に、所属団体の代表者等を通じて『書面』で不服審査委員会へ。所定方式以外は受け付けられません。" },
  { q: "レース中、艇外と無線でデータの送受信が確認されると、失格になることがある。", a: true,
    exp: "正しい。タイム等の許可データを艇内で収集するのは可ですが、艇外との交信・送受信が確認されると失格となることがあります。" },
  { q: "クイックリリースフットストレッチャー（一動作で靴が外れる仕組み）を備えていなくてもよい。", a: false,
    exp: "誤り。沈・転覆時に速やかに離脱できるよう装備が必要です。ヒールロープの長さ調整を含め、違反は失格までの罰則対象です。" },
  { q: "デッドウェイト（舵手計量の補重）の最大重量は15kgである。", a: true,
    exp: "正しい。デッドウェイトは必要な場合に主催者側が用意し、携行クルーはレースに携行、終了後は速やかに返却します。" },
  { q: "練習時は、コースを反時計回りで航行する。", a: true,
    exp: "正しい。浜寺水路の練習航行は反時計回り。出艇・帰艇時はコースを垂直に横断します。" },
  { q: "桟橋への帰艇は、ゴール（フィニッシュ）側から行ってよい。", a: false,
    exp: "誤り。練習時の帰艇はスタート側から。ゴール側からの帰艇は厳禁です。" },
  { q: "レース時、コースの中で自由に練習してよい。", a: false,
    exp: "誤り。コース内での練習は禁止。発艇の審判から呼び込みを受けたクルーのみ、自分のレーンで練習できます。" },
];

// 航行ルール（出典：2026関西選手権 航行ルール図／浜寺水路）
const NAV = [
  { t: "練習時", icon: "ti-arrow-back-up", rows: [
    "コースは反時計回りで航行する",
    "桟橋への帰艇はスタート側から（ゴール側からの帰艇は厳禁）",
    "出艇時、桟橋での船首はフィニッシュ向き",
    "出艇・帰艇時はコースを垂直に横断する",
    "日の出前・日の入り後の出艇は不可",
    "干潮時は浅瀬に注意／高石漁港に近付かない",
  ]},
  { t: "レース時", icon: "ti-flag", rows: [
    "回漕水域：レース前は桟橋からスタート側のみ、レース後はフィニッシュ側のみ使用可",
    "レース艇が通過するまで停止（スタートライン上では停止しない）",
    "練習水域・クールダウン水域は右側通行（中央に仕切りが無く衝突注意）",
    "コース内での練習禁止（審判の呼び込みを受けたクルーのみ自レーンで可）",
    "ワイヤーに注意。ステイクボート間の通り抜け不可",
    "出艇・帰艇時はコースを垂直に横断（レース艇に注意）",
    "帰艇はコース外の西側を通り、桟橋の南側から近付く（コース内侵入禁止）",
    "日の出前・日の入り後の出艇は不可／干潮時は浅瀬に注意",
  ]},
];

// 進み方フロー（予選→敗者戦→準決→B決勝/A決勝）。配色はteams.jsxの.tsc-r系（heat/cr/semi/bfinal/afinal）に合わせる
const GUIDE_FLOW = [
  { kind: "heat", label: "予選", desc: "組ごとにタイムを競う最初のレース" },
  { kind: "cr", label: "敗者戦", desc: "予選で上位に入れなかったクルーの再挑戦（1500m。今年から敗者復活に代わって導入）" },
  { kind: "semi", label: "準決", desc: "上位が決勝へ進出" },
  { kind: "bfinal", label: "B決勝", desc: "7〜12位を決定" },
  { kind: "afinal", label: "A決勝", desc: "1〜6位・メダルを決定するレース" },
];

// 簡易ボート図（艇種の解説専用。実名簿は使わずシート数・位置だけを図示する）
function BoatDiagram({ code, label }) {
  const hasCox = code.indexOf("+") >= 0;
  const n = code.indexOf("8") >= 0 ? 8 : code.indexOf("4") >= 0 ? 4 : code.indexOf("2") >= 0 ? 2 : 1;
  const seats = (hasCox ? ["C"] : []).concat(Array.from({ length: n }, (_, i) => i === 0 ? "S" : (i === n - 1 ? "B" : String(n - i))));
  const CY = 30;
  // 少人数艇は実艇に合わせて中央寄せ（1x=真ん中、2-=中央付近に2つ）。それ以外は全長に分散
  let xs;
  if (seats.length === 1) xs = [100];
  else if (seats.length === 2 && !hasCox) xs = [78, 122];
  else { const x0 = hasCox ? 26 : 34, x1 = 176, step = (x1 - x0) / (seats.length - 1); xs = seats.map((_, i) => x0 + i * step); }
  return (
    <div className="boatdiagram">
      <svg viewBox="0 0 200 60" width="100%" aria-hidden="true">
        <path d={`M8 ${CY} C 34 ${CY - 9}, 168 ${CY - 9}, 192 ${CY} C 168 ${CY + 9}, 34 ${CY + 9}, 8 ${CY} Z`}
              fill="var(--surface-2)" stroke="var(--line)" strokeWidth="1.2" />
        {seats.map((s, i) => {
          const x = xs[i];
          return (
            <g key={i}>
              <circle cx={x} cy={CY} r="9" fill={s === "C" ? "var(--navy)" : "var(--surface)"}
                      stroke="var(--line)" strokeWidth="1.2" />
              <text x={x} y={CY + 3} textAnchor="middle" fontFamily="var(--cond)" fontWeight="800" fontSize="8"
                    fill={s === "C" ? "#fff" : "var(--ink)"}>{s}</text>
            </g>
          );
        })}
      </svg>
      <div className="boatdiagram-lbl">{label}</div>
    </div>
  );
}

function GuideSection() {
  const mapsUrl = "https://www.google.com/maps/search/?api=1&query=" + encodeURIComponent("大阪府立漕艇センター");
  return (
    <>
      <div className="shead"><span className="tag"><span>GUIDE</span></span><span className="jp">はじめての観戦ガイド</span></div>

      <div className="navsec">
        <div className="navsec-h">① 大会の進み方</div>
        <div className="guideflow">
          {GUIDE_FLOW.map((s, i) => (
            <React.Fragment key={s.kind}>
              {i > 0 && <div className="guideflow-arrow">↓</div>}
              <div className={"guideflow-step " + s.kind}>
                <b>{s.label}</b>
                <span>{s.desc}</span>
              </div>
            </React.Fragment>
          ))}
        </div>
      </div>

      <div className="navsec">
        <div className="navsec-h">② 種目記号の読み方</div>
        <div className="navcard">
          <ul className="navlist">
            <li><b>M</b> / <b>W</b> ＝ 男子 / 女子</li>
            <li>数字（1・2・4・8）＝ 漕手の人数</li>
            <li><b>×</b>（スカル）＝ 両手に1本ずつオールを持つ</li>
            <li><b>−</b>（スイープ）＝ 片手に1本のオールを持つ、舵手なし</li>
            <li><b>+</b> ＝ 舵手（コックス）つき</li>
          </ul>
          <p className="navsrc" style={{ margin: "8px 2px 0" }}>例：W4×+ ＝ 女子・4人・スカル・舵手つき（女子舵手つきクォドルプル）</p>
        </div>
        <div className="boatdiagram-row">
          <BoatDiagram code="M1x" label="1x（シングルスカル）" />
          <BoatDiagram code="M2-" label="2-（ペア）" />
          <BoatDiagram code="M4+" label="4+（舵手つきフォア）" />
          <BoatDiagram code="M8+" label="8+（エイト）" />
        </div>
      </div>

      <div className="navsec">
        <div className="navsec-h">③ 2000mレースの見方</div>
        <div className="navcard">
          <ul className="navlist">
            <li><b>スタート〜500m</b>：飛び出し。艇のスピードに乗せる区間</li>
            <li><b>中盤（500〜1500m）</b>：コンスタント。ペースを保って我慢する区間</li>
            <li><b>ラスト500m</b>：スパート。順位が入れ替わりやすい見どころ</li>
          </ul>
        </div>
      </div>

      <div className="navsec">
        <div className="navsec-h">④ 会場・持ち物</div>
        <div className="navcard">
          <p style={{ margin: "0 0 8px", fontSize: 12.5, fontWeight: 700, color: "var(--ink)" }}>大阪府立漕艇センター（浜寺水路）</p>
          <a className="guide-mapbtn" href={mapsUrl} target="_blank" rel="noopener noreferrer">
            地図アプリで開く ↗
          </a>
          <p className="navsrc" style={{ margin: "8px 2px 0" }}>アクセス・駐車場の詳細は主催・関西ローイング連盟の公式案内をご確認ください。</p>
          <ul className="navlist" style={{ marginTop: 10 }}>
            <li>帽子・日傘など日差し対策</li>
            <li>飲み物は多めに（水路沿いは日陰が少なめ）</li>
            <li>タオル・冷却グッズ</li>
            <li>日焼け止め</li>
          </ul>
        </div>
      </div>
    </>
  );
}

// 歴代優勝者（一般の部）。data/kansai-past-champions.json（karal.jpアーカイブから集計済み）を読み込んで表示。
const CHAMP_EVENT_ORDER = ["m8+", "m4+", "m4-", "m4x", "m2x", "m2-", "m1x", "w4x", "w4+", "w2x", "w2-", "w1x"];

function ChampionsSection() {
  const [data, setData] = React.useState(null);
  const [failed, setFailed] = React.useState(false);
  const [ev, setEv] = React.useState("m8+");
  const secRef = React.useRef(null);
  React.useEffect(() => {
    fetch("./data/kansai-past-champions.json", { cache: "no-store" })
      .then((r) => { if (!r.ok) throw new Error("http " + r.status); return r.json(); })
      .then(setData).catch(() => setFailed(true));
  }, []);
  // ホームの「歴代優勝者を見る」から来た時はこのセクションまでスクロール
  React.useEffect(() => {
    if (!window.__openChampions) return;
    window.__openChampions = false;
    setTimeout(() => { if (secRef.current) secRef.current.scrollIntoView({ behavior: "instant", block: "start" }); }, 120);
  }, []);
  if (failed) return null;

  const events = data ? data.events : null;
  const evKeys = events ? CHAMP_EVENT_ORDER.filter((k) => events[k]) : [];
  const cur = events && events[ev];
  let rows = [], topTeams = [];
  if (cur) {
    rows = Object.keys(cur.years).sort((a, b) => +b - +a)
      .map((y) => ({ year: y, ...cur.years[y] }));
    const tally = {};
    // 「同志社大学」と「同志社大学A」、「大阪市立大学　薫風/煌」等は同一団体。
    // baseTeam（サイト全体と同じ団体名の正規化：A/B/C接尾辞・艇名・学部を吸収）でまとめて数える。
    rows.forEach((r) => { if (r.championTeam) { const b = window.RW.baseTeam(r.championTeam); tally[b] = (tally[b] || 0) + 1; } });
    const max = Math.max(0, ...Object.values(tally));
    if (max >= 2) topTeams = Object.keys(tally).filter((t) => tally[t] === max).map((t) => ({ team: t, n: max }));
  }
  const washoutNote = data && data.meta && data.meta.specialNotes && data.meta.specialNotes["2013"];

  return (
    <div ref={secRef} style={{ marginTop: 26 }}>
      <div className="shead"><span className="tag"><span>CHAMPIONS</span></span><span className="jp">歴代優勝者</span><span className="sp" /><span className="meta">2007–2026・一般の部</span></div>
      <p className="quiz-lead">関西選手権 一般の部12種目のA決勝優勝クルー。出典：karal.jp（関西ローイング連盟）各年度アーカイブ。</p>

      {!data ? (
        <div className="empty">読み込み中…</div>
      ) : (
        <>
          <div className="chips" style={{ flexWrap: "wrap" }}>
            {evKeys.map((k) => (
              <button type="button" key={k} className={"chip" + (ev === k ? " on" : "")} onClick={() => setEv(k)}>{events[k].code}</button>
            ))}
          </div>
          <p className="navsrc" style={{ margin: "2px 2px 8px" }}>{cur ? cur.nameJa : ""}</p>

          {topTeams.length > 0 && (
            <div className="champ-top">
              <span className="champ-top-l">最多優勝<i className="champ-top-note">2007年以降</i></span>
              {topTeams.map((t) => <b key={t.team}>{t.team}（{t.n}回）</b>)}
            </div>
          )}

          <div className="champ-list">
            {rows.map((r) => {
              // 表示も団体名（base）に統一し、A/薫風/教育学部等の細別は小さく併記して残す。
              const ct = (r.championTeam || "").trim();
              const base = ct ? window.RW.baseTeam(ct) : "";
              const sub = (ct && ct !== base) ? ct.slice(base.length).replace(/^[\s　]+/, "") : "";
              return (
                <div className={"champ-row" + (r.year === "2026" ? " latest" : "")} key={r.year}>
                  <span className="champ-yr">{r.year}</span>
                  {r.status === "washout"
                    ? <span className="champ-team washout">荒天のため決勝中止（予選タイムで順位決定）</span>
                    : r.status === "open"
                    ? <span className="champ-team washout">オープン実施のため正式競漕なし</span>
                    : <span className="champ-team">{base || "—"}{sub ? <i>{sub}</i> : null}{r.championName ? <i>{r.championName}</i> : null}</span>}
                </div>
              );
            })}
          </div>
          <p className="navsrc" style={{ marginTop: 8 }}>
            2020年はkaral.jpにアーカイブがないため対象外。{washoutNote ? "2013年は荒天のため決勝中止。" : ""}浜寺杯・マスターズ・中学生の部は含みません。
          </p>
        </>
      )}
    </div>
  );
}

function RulesView() {
  const [ans, setAns] = React.useState(() => {
    try { return JSON.parse(localStorage.getItem(QUIZ_KEY) || "{}"); } catch (e) { return {}; }
  });
  // 回答が変わるたびに保存（リセットするまで残る）
  React.useEffect(() => { try { localStorage.setItem(QUIZ_KEY, JSON.stringify(ans)); } catch (e) {} }, [ans]);
  // 1回だけ回答可。関数型更新で連続タップでも取りこぼさない。
  const choose = (i, val) => setAns((prev) => (i in prev) ? prev : { ...prev, [i]: val });
  const reset = () => setAns({});

  const answered = Object.keys(ans).length;
  const correct = QUIZ.reduce((n, q, i) => n + (((i in ans) && ans[i] === q.a) ? 1 : 0), 0);
  // 大会タブが長いので、未回答のうちはクイズ本体を畳んでおく（回答済みなら開いたまま）
  const [quizOpen, setQuizOpen] = React.useState(answered > 0);

  return (
    <section className="view">
      <GuideSection />

      <div className="shead"><span className="tag"><span>RULES</span></span><span className="jp">航行ルール ＆ ◯✕クイズ</span></div>

      <div className="navsec">
        <div className="navsec-h">⚓ 航行ルール<span className="navsec-note">浜寺水路</span></div>
        <div className="navgrid">
          {NAV.map((b) => (
            <div className={"navcard" + (b.t === "レース時" ? " race" : "")} key={b.t}>
              <div className="navcard-t">{b.t}</div>
              <ul className="navlist">{b.rows.map((x, i) => <li key={i}>{x}</li>)}</ul>
            </div>
          ))}
        </div>
        <p className="navsrc">出典：2026関西選手権 航行ルール図（浜寺水路）。実際の回漕・コースは当日の指示に従ってください。</p>
      </div>

      <div className="shead" style={{ marginTop: 22 }}><span className="tag"><span>QUIZ</span></span><span className="jp">レース ◯✕クイズ</span><span className="sp" /><span className="meta">{answered}/{QUIZ.length}問</span></div>
      <p className="quiz-lead">大会を円滑に進めるための審判ルール◯✕クイズ。<b>各問1回だけ</b>回答できます（リセットするまで結果と解説が残ります）。</p>
      {answered > 0 && <div className="quiz-score">正解 <b>{correct}</b> / {answered}問</div>}

      {!quizOpen ? (
        <div style={{ textAlign: "center", margin: "14px 0 6px" }}>
          <button type="button" className="quiz-startbtn" onClick={() => setQuizOpen(true)}>クイズにチャレンジ　スタート！ ›</button>
        </div>
      ) : (
      <>
      <div className="quiz-list">
        {QUIZ.map((q, i) => {
          const done = i in ans;
          const my = ans[i];
          const ok = done && my === q.a;
          return (
            <div className={"quiz-card" + (done ? (ok ? " ok" : " ng") : "")} key={i}>
              <div className="quiz-q"><span className="quiz-no">Q{i + 1}</span><span>{q.q}</span></div>
              <div className="quiz-btns">
                <button type="button" className={"quiz-b maru" + (done && my === true ? " sel" : "")} disabled={done} onClick={() => choose(i, true)} aria-label="まる">◯</button>
                <button type="button" className={"quiz-b batsu" + (done && my === false ? " sel" : "")} disabled={done} onClick={() => choose(i, false)} aria-label="ばつ">✕</button>
              </div>
              {done && (
                <div className="quiz-res">
                  <div className="quiz-verdict">{ok ? "正解！" : "不正解"}<span className="quiz-ans">正答：{q.a ? "◯" : "✕"}</span></div>
                  <div className="quiz-exp">{q.exp}</div>
                </div>
              )}
            </div>
          );
        })}
      </div>

      <div style={{ textAlign: "center", marginTop: 16 }}>
        <button type="button" className="quiz-reset" onClick={reset}>回答をリセット</button>
      </div>
      </>
      )}
      <p className="quiz-srcnote">出典：2026年度関西選手権『レースに当たっての審判上の注意』／競漕規則・細則の全文は日本ローイング協会 公式サイトをご確認ください。</p>

      <ChampionsSection />
    </section>
  );
}
Object.assign(window, { RulesView });
