/* game-bowling.jsx — Bowling: 10 frames, strike/spare/bonus scoring. */
const { useState: useBowl, useEffect: useBowlFX, useRef: useBowlRef } = React;

/* ---- Bowling logic ---- */
function getFrameStart(rolls, f) {
  let idx = 0;
  for (let i = 0; i < f; i++) {
    if (rolls[idx] === 10) idx++;       // strike
    else idx += 2;
  }
  return idx;
}
function calcFrameScore(rolls, f) {
  const ri = getFrameStart(rolls, f);
  if (f === 9) { // 10th frame: sum of up to 3 rolls
    return (rolls[ri] || 0) + (rolls[ri + 1] || 0) + (rolls[ri + 2] || 0);
  }
  if (rolls[ri] === 10) return 10 + (rolls[ri + 1] || 0) + (rolls[ri + 2] || 0); // strike
  const s = (rolls[ri] || 0) + (rolls[ri + 1] || 0);
  if (s === 10) return 10 + (rolls[ri + 2] || 0); // spare
  return s;
}
function calcCumulativeScores(rolls) {
  const cum = [];
  let total = 0;
  for (let f = 0; f < 10; f++) {
    const ri = getFrameStart(rolls, f);
    const hasAllRolls = f === 9
      ? rolls.length > ri + (rolls[ri] === 10 || (rolls[ri] || 0) + (rolls[ri + 1] || 0) === 10 ? 2 : 1)
      : (rolls[ri] === 10 ? rolls.length > ri + 2 : rolls.length > ri + 1) &&
        (rolls[ri] === 10 ? rolls[ri + 2] !== undefined : true);
    if (!hasAllRolls) { cum.push(null); continue; }
    total += calcFrameScore(rolls, f);
    cum.push(total);
  }
  return cum;
}
function isFrameDone(rolls, f) {
  const ri = getFrameStart(rolls, f);
  if (f === 9) {
    if (rolls[ri] === 10) return rolls.length >= ri + 3;      // strike in 10th: 3 rolls
    if ((rolls[ri] || 0) + (rolls[ri + 1] || 0) === 10) return rolls.length >= ri + 3; // spare in 10th: 3 rolls
    return rolls.length >= ri + 2;                            // normal 10th: 2 rolls
  }
  if (rolls[ri] === 10) return true; // strike: 1 roll
  return rolls.length >= ri + 2;     // normal: 2 rolls
}
function currentFrameAndRoll(rolls) {
  for (let f = 0; f < 10; f++) {
    if (!isFrameDone(rolls, f)) {
      const ri = getFrameStart(rolls, f);
      return { f, roll: rolls.length - ri };
    }
  }
  return { f: 10, roll: 0 }; // done
}
function maxPinsForRoll(rolls, f) {
  if (f >= 10) return 0;
  const ri = getFrameStart(rolls, f);
  if (f === 9) {
    const r0 = rolls[ri] || 0, r1 = rolls[ri + 1];
    if (rolls.length === ri) return 10;
    if (rolls.length === ri + 1) return r0 === 10 ? 10 : 10 - r0;
    if (rolls.length === ri + 2) {
      if (r0 === 10 && r1 === 10) return 10;
      if (r0 === 10) return 10 - (r1 || 0);
      return 10; // spare bonus: any
    }
    return 10;
  }
  if (rolls[ri] === 10) return 0; // shouldn't call
  return 10 - (rolls[ri] || 0);
}
function frameDisplayRolls(rolls, f) {
  const ri = getFrameStart(rolls, f);
  const r = [rolls[ri], rolls[ri + 1], rolls[ri + 2]].filter((v) => v !== undefined);
  if (f === 9) {
    return r.map((v, i) => {
      if (v === 10) return "X";
      if (i > 0 && (r[i - 1] !== 10 || i > 1) && (r[i - 1] + v === 10)) return "/";
      if (v === 0) return "-";
      return String(v);
    });
  }
  if (r[0] === 10) return ["X"];
  if (r.length >= 2 && r[0] + r[1] === 10) return [r[0] === 0 ? "-" : String(r[0]), "/"];
  return r.map((v) => v === 0 ? "-" : String(v));
}

/* ============================================================ */
function BowlingGame({ sess, account, nav, onChange, lang, setLang }) {
  const [showResults, setShowResults] = useBowl(sess.status === "finished");
  const [showRules, setShowRules] = useBowl(false);
  const [toast, setToast] = useBowl("");
  useBowlFX(() => { if (!toast) return; const tm = setTimeout(() => setToast(""), 1700); return () => clearTimeout(tm); }, [toast]);
  useBowlFX(() => { if (sess.status === "finished") setShowResults(true); }, [sess.status]);

  const n = sess.players.length;
  const cp = sess.currentPlayer;
  const rolls = sess.allRolls[cp] || [];
  const { f: curFrame } = currentFrameAndRoll(rolls);
  const maxPins = curFrame < 10 ? maxPinsForRoll(rolls, curFrame) : 0;
  const finished = sess.status === "finished";

  function patch(updater) {
    const next = JSON.parse(JSON.stringify(sess));
    updater(next);
    onChange(next);
  }

  function submitRollValue(pins) {
    if (pins < 0 || pins > maxPins) { setToast(`Max: ${maxPins}`); return; }
    patch((s) => {
      s.allRolls[cp].push(pins);
      const { f } = currentFrameAndRoll(s.allRolls[cp]);
      if (f >= 10) {
        // player done — advance
        const nextP = (cp + 1) % n;
        if (nextP === 0 || s.players.slice(nextP).every((_, i) => currentFrameAndRoll(s.allRolls[nextP + i]).f >= 10)) {
          // Check if all done
          const allDone = s.allRolls.every((pr) => currentFrameAndRoll(pr).f >= 10);
          if (allDone) {
            s.status = "finished";
            const scores = s.allRolls.map((pr) => {
              const cum = calcCumulativeScores(pr);
              return cum[9] || 0;
            });
            s.winner = scores.indexOf(Math.max(...scores));
          } else {
            s.currentPlayer = nextP;
          }
        } else {
          s.currentPlayer = nextP;
        }
      }
    });
  }

  const cum = sess.allRolls.map(calcCumulativeScores);
  const playerTotals = cum.map((c) => c[9] || 0);
  const leader = playerTotals.indexOf(Math.max(...playerTotals));

  return (
    <div className="app">
      <AppHeader account={account} nav={nav} onSignOut={() => {}} crumb={t("game.bowling.name")} lang={lang} setLang={setLang} />
      <main className="wrap" style={{ flex: 1, paddingBottom: 80 }}>
        <div className="game-top">
          <button className="btn ghost sm" onClick={() => nav("#/")} style={{ paddingLeft: 6 }}><Icon name="back" size={16} />{t("nav.dashboard")}</button>
          {!finished && <span className="round-pill">{t("bowling.frame")} {Math.min(curFrame + 1, 10)}/10</span>}
          {finished && <span className="tag live">🏆 {sess.players[sess.winner].name}</span>}
          <span style={{ flex: 1 }}></span>
          <button className="btn sm" onClick={() => setShowRules(true)}><Icon name="book" size={15}/>{t("game.rules")}</button>
        </div>

        {/* Player chips */}
        <div className="player-rail" style={{ marginBottom: 16 }}>
          {sess.players.map((p, i) => (
            <div key={i} className={"pchip" + (i === cp && !finished ? " active" : "") + (i === leader ? " lead" : "")}>
              <div className="ptop">
                <Avatar name={p.name} size="sm" idx={i} />
                <span className="pname">{p.name}</span>
                {i === leader && playerTotals[i] > 0 && <span className="crown"><Icon name="crown" size={15} /></span>}
                {i === cp && !finished && <span className="turn-dot"></span>}
              </div>
              <div className="score">{playerTotals[i]}</div>
            </div>
          ))}
        </div>

        {/* Per-player frame grids */}
        {sess.players.map((p, pi) => (
          <div key={pi} style={{ marginBottom: 14 }}>
            <div style={{ fontSize: 13, fontWeight: 700, marginBottom: 6, display: "flex", gap: 8, alignItems: "center" }}>
              <Avatar name={p.name} idx={pi} size="sm" />{p.name}
              {pi === cp && !finished && <span className="turn-dot"></span>}
            </div>
            <BowlingFrameGrid rolls={sess.allRolls[pi]} cumulative={cum[pi]} active={pi === cp && !finished} />
          </div>
        ))}

        {!finished && (
          <div className="card" style={{ padding: 20, marginTop: 8 }}>
            <div style={{ fontWeight: 600, marginBottom: 14 }}>
              {sess.players[cp].name} · {t("bowling.frame")} {curFrame + 1} · {t("bowling.roll", { n: (rolls.length - getFrameStart(rolls, curFrame)) + 1 })}
            </div>
            <div style={{ display: "flex", gap: 10, flexWrap: "wrap", justifyContent: "center" }}>
              {Array.from({ length: maxPins + 1 }, (_, v) => {
                const ri = rolls.length - getFrameStart(rolls, curFrame);
                const isStrike = v === 10 && ri === 0;
                const isSpare  = v === maxPins && ri > 0 && maxPins < 10;
                return (
                  <button key={v} className="btn"
                    style={{ minWidth: 52, height: 52, fontSize: 20, fontWeight: 700,
                      ...(isStrike ? { background:"var(--accent)", color:"#fff", border:"none" } : {}),
                      ...(isSpare  ? { background:"var(--good)",   color:"#fff", border:"none" } : {}),
                      ...(v === 0  ? { color: "var(--muted)" } : {}) }}
                    onClick={() => submitRollValue(v)}>
                    {isStrike ? "X" : isSpare ? "/" : v === 0 ? "–" : v}
                  </button>
                );
              })}
            </div>
          </div>
        )}

        {finished && (
          <div className="card" style={{ padding: 24, textAlign: "center" }}>
            <div style={{ color: "var(--gold)" }}><Icon name="crown" size={32} /></div>
            <h3 style={{ marginTop: 8 }}>{sess.players[sess.winner].name} wins with {playerTotals[sess.winner]}!</h3>
            <button className="btn primary" style={{ marginTop: 16 }} onClick={() => nav("#/new/bowling")}>{t("res.newgame")}</button>
          </div>
        )}
      </main>
      <Toast msg={toast} />
    </div>
  );
}

function BowlingFrameGrid({ rolls, cumulative, active }) {
  return (
    <div style={{ display: "flex", gap: 3, overflowX: "auto" }}>
      {Array.from({ length: 10 }, (_, f) => {
        const dr = frameDisplayRolls(rolls, f);
        const score = cumulative[f];
        const done = isFrameDone(rolls, f);
        const is10 = f === 9;
        return (
          <div key={f} style={{ flex: is10 ? "1.5 0" : "1 0", minWidth: is10 ? 54 : 38, border: "1px solid var(--line)", borderRadius: 8,
            background: active && !done ? "var(--accent-50)" : "var(--surface)", overflow: "hidden" }}>
            <div style={{ display: "flex", borderBottom: "1px solid var(--line)", minHeight: 26 }}>
              {(is10 ? [0,1,2] : [0,1]).map((ri) => (
                <div key={ri} style={{ flex: 1, textAlign: "center", fontSize: 13, fontWeight: 700, borderRight: ri < (is10 ? 2 : 1) ? "1px solid var(--line)" : "none",
                  padding: "4px 0", color: dr[ri] === "X" ? "var(--accent)" : dr[ri] === "/" ? "var(--good)" : "var(--ink)" }}>
                  {dr[ri] || ""}
                </div>
              ))}
            </div>
            <div style={{ textAlign: "center", fontSize: 13, fontFamily: "var(--font-display)", fontWeight: 600, padding: "3px 0", color: done ? "var(--ink)" : "var(--faint)" }}>
              {score !== null ? score : ""}
            </div>
          </div>
        );
      })}
    </div>
  );
}

window.BowlingGame = BowlingGame;
window.getFrameStart = getFrameStart;
window.currentFrameAndRoll = currentFrameAndRoll;
