/* teams.jsx — search, favorites, grouped (大学／高校／クラブ・実業団・その他), detail */
// 五十音ソート用の読み（baseTeam正規化後の団体名→ひらがな）
const TEAM_YOMI = {
  "同志社大学": "とうししや", "京都大学": "きようと", "滋賀大学": "しが", "大阪大学": "おおさか",
  "関西学院大学": "かんせいがくいん", "龍谷大学": "りゆうこく", "関西大学": "かんさい", "大阪公立大学": "おおさかこうりつ",
  "鳥取大学": "とつとり", "南山大学": "なんざん", "名古屋大学": "なごや", "山口大学": "やまぐち",
  "瀬田漕艇クラブ": "せた", "名古屋工業大学": "なごやこうぎよう", "トヨタ自動車RC": "とよたじどうしや",
  "桐蔭高校": "とういん", "金沢大学": "かなざわ", "九州大学": "きゆうしゆう", "広島大学": "ひろしま",
  "立命館大学": "りつめいかん", "岡山大学": "おかやま", "新北市": "しんほくし", "神戸大学": "こうべ",
  "大阪工業大学": "おおさかこうぎよう", "愛媛大学": "えひめ", "岐阜大学": "ぎふ", "追手門学院大学": "おうてもんがくいん",
  "トヨタ紡織": "とよたぼうしよく", "熊本大学": "くまもと", "鹿屋体育大学": "かのや", "鹿児島大学": "かごしま",
  "品川リフラ": "しながわりふら", "ARES": "えーれす", "愛媛・京医・総合研究": "えひめきよういそうごう",
  "関西みらい銀行": "かんさいみらい", "高松青果": "たかまつせいか", "松山大学": "まつやま", "福岡女子大学": "ふくおか",
};
const byYomi = (a, b) => (TEAM_YOMI[a] || a).localeCompare(TEAM_YOMI[b] || b, "ja");
// ラウンド種別→色分けキー。決勝に近いほど鮮やかな配色になるよう段階づけ
const roundKind = (r) => r.isFinalA ? "afinal" : r.round === "B決勝" ? "bfinal" : r.round === "準決" ? "semi" : r.round === "敗者戦" ? "cr" : "heat";
// 進出チップの色は「行き先」に合わせる（準決=紫 / A決勝=金 / B決勝=黄 / 敗者戦=グレー / それ以外=緑）。日程セルの配色と統一。
// karal.jpは「→Ａ決勝」など全角英字で配信するため、判定前に半角へ正規化する。
const zenQ = (s) => String(s || "").replace(/[Ａ-Ｚａ-ｚ０-９]/g, (c) => String.fromCharCode(c.charCodeAt(0) - 0xFEE0));
const progDest = (qRaw) => { const q = zenQ(qRaw); return !q ? "" : /A決勝/.test(q) ? "prog-afinal" : /B決勝/.test(q) ? "prog-bfinal" : /準決/.test(q) ? "prog-semi" : /敗者|敗復/.test(q) ? "prog-cr" : /DNS|棄権/.test(q) ? "" : "go"; };
function TeamDetail({ team, ord, isFav, toggleFav, onClose, onOpenEvent }) {
  const RW = window.RW;
  const ROS = window.KANSAI.ROSTERS || {};
  const minorTeam = RW.isMinorTeam && RW.isMinorTeam(team);  // 高校（未成年）は氏名を出さない
  const t = RW.TEAMS[team];
  const [openK, setOpenK] = React.useState(null);
  React.useEffect(() => { setOpenK(null); }, [team]);
  if (!t) return null;
  // チーム詳細内では基準チーム名は自明なので、クルー表記から団体名を落として A/B/C だけ見せる
  // （例：「同志社大学A」→「A」）。接頭辞が一致しない稀なケースは元の表記をそのまま返す。
  const crewSuffix = (label) => {
    const s = String(label || "").trim();
    if (team && s.startsWith(team)) { const rest = s.slice(team.length).replace(/^[\s　・]+/, ""); return rest || s; }
    return s;
  };
  // group crews by event
  const byEvent = {};
  t.crews.forEach((c) => { (byEvent[c.evKey] = byEvent[c.evKey] || []).push(c); });
  const evKeys = Object.keys(byEvent).sort((a, b) => RW.evOf[a].div.localeCompare(RW.evOf[b].div));
  const finalsWon = evKeys.filter((k) => RW.evOf[k].finalA && ord >= RW.evOf[k].finalA.endOrd);
  const prog = RW.favProgress(team);
  const isAfter = ord >= RW.LAST; // 大会後：日程マスをやめ「最終結果」を出す
  const zenR = (s) => String(s || "").replace(/[Ａ-Ｚａ-ｚ０-９]/g, (c) => String.fromCharCode(c.charCodeAt(0) - 0xFEE0));
  // クルーの到達最終ラウンド＋着順から「最終結果」を作る。決勝は着順を“総合順位”に変換して表示。
  //   今大会は6艇立て（A決勝＝総合1〜6位）。A決勝: 1/2/3=メダル、4〜6=そのまま「N位」。
  //   B決勝: 総合 = 6 + 着順（例 B決勝2位→総合8位）、C決勝: 12 + 着順。「A決勝/B決勝」表記は出さない。
  //   決勝以外（準決・敗者戦・予選）は従来どおり「◯◯敗退」。
  const FINAL_LANES = 6;
  const resultOf = (p) => {
    const q = zenR(p.qualify), r = p.rank, R = p.lastRound;
    if (r == null && /DNS|棄権/.test(q)) return { text: "棄権", cls: "out" };
    if (R === "A決勝") {
      if (r === 1) return { medal: "🥇", text: "優勝", cls: "gold" };
      if (r === 2) return { medal: "🥈", text: "2位", cls: "silver" };
      if (r === 3) return { medal: "🥉", text: "3位", cls: "bronze" };
      return { text: r != null ? r + "位" : "決勝進出", cls: "af" };
    }
    if (R === "B決勝") return { text: r != null ? "総合" + (FINAL_LANES + r) + "位" : "出場", cls: "bf" };
    if (R === "C決勝") return { text: r != null ? "総合" + (FINAL_LANES * 2 + r) + "位" : "出場", cls: "bf" };
    if (R === "準決") return { text: "準決敗退", cls: "sf" };
    if (R === "敗者戦") return { text: "敗者戦敗退", cls: "cr" };
    return { text: (R || "予選") + "敗退", cls: "out" };
  };
  // 土日×午前午後の4マスに、その種目のラウンドを時刻で振り分け（無いマスは「ー」）
  const DOW = [0, 1].map((di) => (RW.FLAT.find((r) => r.dayIndex === di) || {}).dow || (di ? "日" : "土"));
  const scheduleCells = (evKey) => {
    const rounds = RW.FLAT.filter((x) => x.ev.key === evKey);
    return [0, 1].flatMap((di) => [0, 1].map((half) => {
      const items = rounds.filter((r) => r.dayIndex === di && (r.startMin >= 720) === !!half);
      return {
        day: di, dow: DOW[di], ampm: half ? "午後" : "午前",
        rows: items.map((r) => ({ kind: roundKind(r), t: r.t, label: r.isFinalA ? "A決勝" : r.round })),
      };
    }));
  };

  return (
    <div className="tcard">
      <div className="th" onClick={() => onClose && onClose()} style={{ cursor: onClose ? "pointer" : "default" }}>
        <span className="lanes" />
        <div className="thbtns">
          <StarBtn on={isFav} onClick={() => toggleFav(team)} size={24} />
          {onClose && <button className="closebtn" aria-label="閉じる" onClick={(e) => { e.stopPropagation(); onClose(); }}><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M6 6l12 12M18 6L6 18" /></svg></button>}
        </div>
        <h3>{team}</h3>
        <div className="meta"><span>{evKeys.length}種目 · {t.crews.length}エントリー</span></div>
      </div>
      <div className="tbody">
        {evKeys.map((k) => {
          const ev = RW.evOf[k];
          const crews = byEvent[k];
          const ros = ROS[k] || {};
          const op = openK === k;
          const cells = scheduleCells(k);
          const evProg = prog.filter((p) => p.evKey === k);
          return (
            <React.Fragment key={k}>
              <div className="trow clk" onClick={() => setOpenK(op ? null : k)} style={{ cursor: "pointer" }}>
                <span className="tcode"><Code ev={ev} /></span>
                <span className="tnm">{ev.name}{crews.length > 1 ? `（${crews.length}）` : ""}{ev.div !== "general" ? " · " + RW.DIV[ev.div].label : ""}</span>
                <IconChevron dir={op ? "up" : "down"} size={12} />
              </div>
              {isAfter ? (
                /* 大会後：種目ごとの最終結果（決勝はメダル・着順、他は「◯◯敗退」） */
                <div className="tresrow">
                  <span className="treslbl">最終結果</span>
                  {evProg.length ? evProg.map((p, i) => { const R = resultOf(p); return (
                    <span className={"tres " + R.cls} key={i}>
                      {crews.length > 1 && <b className="trescrew">{crewSuffix(p.crewLabel)}</b>}
                      {R.medal && <em className="tresmedal">{R.medal}</em>}{R.text}
                    </span>
                  ); }) : <span className="tres out">結果は結果タブへ</span>}
                </div>
              ) : (
                <React.Fragment>
                  {evProg.length > 0 && (
                    <div style={{ display: "flex", flexWrap: "wrap", gap: 5, margin: "-2px 0 8px" }}>
                      {evProg.map((p, i) => (
                        <span className={"progchip " + progDest(p.qualify)} key={i}>
                          {crews.length > 1 ? crewSuffix(p.crewLabel) + " " : ""}{p.lastRound}{p.grp ? " " + p.grp : ""}{p.rank != null ? " " + p.rank + "位" : ""}{p.qualify ? " " + p.qualify : ""}
                        </span>
                      ))}
                    </div>
                  )}
                  <div className="tsched">
                    {cells.map((c, i) => (
                      <div className={"tsc" + (c.rows.length ? "" : " norace")} key={i}>
                        <div className="tsc-h"><span className={"tsc-d " + (c.day ? "sun" : "sat")}>{c.dow}</span>{c.ampm}</div>
                        {c.rows.length
                          ? c.rows.map((it, j) => (
                              <div className={"tsc-r " + it.kind} key={j}><i>{it.label}</i><b>{it.t}</b></div>
                            ))
                          : <div className="tsc-none">ー</div>}
                      </div>
                    ))}
                  </div>
                </React.Fragment>
              )}
              {op && (
                <div className="trow-ros">
                  {crews.map((c) => {
                    const ms = ros[c.n] || [];
                    return (
                      <div className={"trow-crew" + (c.x ? " scratch" : "")} key={c.n}>
                        {crews.length > 1 && <div className="trow-crewlbl">{crewSuffix(c.label)}{c.x && <span className="rc-dnf" style={{ marginLeft: 6 }}>棄権</span>}</div>}
                        {crews.length === 1 && c.x && <div className="trow-crewlbl"><span className="rc-dnf">棄権</span></div>}
                        {(ms.length && !minorTeam) ? ms.map((m, i) => (
                          <div className="trow-seat" key={i}>
                            {ev.type !== "scull" && <span className="trow-s">{m[0]}</span>}
                            <span className="trow-nm"><RowerName name={m[1]} kana={m[2]} /></span>
                          </div>
                        )) : <div className="trow-seat"><span className="trow-nm">{minorTeam ? c.label : (c.name || c.label)}</span></div>}
                      </div>
                    );
                  })}
                  <button type="button" className="trow-evbtn" onClick={(e) => { e.stopPropagation(); onOpenEvent(k); }}>種目の全クルーを見る →</button>
                </div>
              )}
            </React.Fragment>
          );
        })}
      </div>
    </div>
  );
}

function TeamsView({ ord, favTeams, toggleFav, selectedTeam, setSelectedTeam, onOpenEvent, q, setQ }) {
  const RW = window.RW;
  const ROS = window.KANSAI.ROSTERS || {};
  // 団体の総人数（各クルーの名簿人数、無ければ艇の定員で概算）
  const teamHeads = (t) => RW.TEAMS[t].crews.reduce((n, c) => {
    const r = (ROS[c.evKey] || {})[c.n];
    return n + (r && r.length ? r.length : RW.seatsOf(RW.evOf[c.evKey]));
  }, 0);
  const [sortMode, setSortMode] = React.useState("yomi"); // "yomi"=五十音順 / "heads"=出場者数（多い順）
  const cmp = sortMode === "heads" ? (a, b) => teamHeads(b) - teamHeads(a) || byYomi(a, b) : byYomi;
  const all = RW.TEAM_NAMES;
  const favList = all.filter((t) => favTeams[t]).slice().sort(byYomi);
  const filtered = all.filter((t) => !q || t.includes(q));
  const athleteHits = q ? RW.searchAthletes(q).slice(0, 6) : [];
  const isHigh = (t) => /高校/.test(t);
  const isUniv = (t) => /大学/.test(t) && !isHigh(t);
  const univ = filtered.filter(isUniv).sort(cmp);
  const high = filtered.filter(isHigh).sort(cmp);
  const other = filtered.filter((t) => !isUniv(t) && !isHigh(t)).sort(cmp);

  const TeamBtn = ({ t }) => {
    const T = RW.TEAMS[t];
    return (
      <button className="tbtn" onClick={() => setSelectedTeam(t === selectedTeam ? null : t)}>
        {favTeams[t] && <span className="fav-s"><Star size={11} /></span>}
        <span className="tbtn-nm">{t}</span>
        <span className="tbtn-stats">
          <span className="ts-x ev"><b>{T.evKeys.size}</b>種目</span>
          <span className="ts-x cr"><b>{T.crews.length}</b>クルー</span>
          <span className="ts-x pp"><b>{teamHeads(t)}</b>名</span>
        </span>
      </button>
    );
  };
  const Group = ({ label, list }) => list.length === 0 ? null : (
    <div className="tgroup">
      <div className="tgroup-h">{label}<span className="c">{list.length}</span></div>
      <div className="tlist">{list.map((t) => <TeamBtn key={t} t={t} />)}</div>
    </div>
  );

  return (
    <section className="view">
      <div className="shead"><span className="tag"><span>TEAMS</span></span><span className="jp">チームから探す</span><span className="sp" /><span className="meta">{all.length}団体</span></div>
      <div className="search"><IconSearch size={20} /><input value={q} onChange={(e) => setQ(e.target.value)} placeholder="団体名で検索（例：同志社、京都、瀬田…）" autoComplete="off" /></div>
      {selectedTeam && <TeamDetail team={selectedTeam} ord={ord} isFav={!!favTeams[selectedTeam]} toggleFav={toggleFav} onClose={() => setSelectedTeam(null)} onOpenEvent={onOpenEvent} />}
      {!q && favList.length > 0 && (
        <div className="favsec" style={{ marginTop: 14 }}>
          <div className="favtitle"><Star size={14} color="var(--red)" />お気に入り</div>
          <div className="tlist">{favList.map((t) => <TeamBtn key={t} t={t} />)}</div>
        </div>
      )}
      {q && athleteHits.length > 0 && (
        <div className="favsec" style={{ marginTop: 14 }}>
          <div className="favtitle">選手</div>
          <div className="nextlist">
            {athleteHits.map((a, i) => (
              <div className="nextrow" key={i} style={{ cursor: "pointer" }} onClick={() => setSelectedTeam(RW.baseTeam(a.team))}>
                <div className="nx" style={{ display: "flex", alignItems: "center", gap: 8 }}>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontWeight: 800, fontSize: 13 }}>{a.name}{a.kana && <i className="rn-kana" style={{ marginLeft: 6 }}>{a.kana}</i>}</div>
                    <div className="nm">{a.team}・{a.evs.join(" / ")}</div>
                  </div>
                  <IconArrow size={16} />
                </div>
              </div>
            ))}
          </div>
        </div>
      )}
      {filtered.length > 0 && (
        <div className="team-sort">
          <span className="team-sort-lbl">並び替え</span>
          <button type="button" className={"chip" + (sortMode === "yomi" ? " on" : "")} onClick={() => setSortMode("yomi")}>五十音順</button>
          <button type="button" className={"chip" + (sortMode === "heads" ? " on" : "")} onClick={() => setSortMode("heads")}>出場者数</button>
        </div>
      )}
      <div style={{ marginTop: 10 }}>
        {filtered.length ? (<><Group label="大学" list={univ} /><Group label="高校" list={high} /><Group label="クラブ・実業団・その他" list={other} /></>) : <div className="empty">「{q}」に一致する団体はありません</div>}
      </div>
    </section>
  );
}
Object.assign(window, { TeamsView });
