/* Kniffle Koi — game engine + UI (React) */
const { useState, useMemo, useCallback } = React;
const KKD = window.KK;
const { VARIETIES, SIZE_NAME, SIZE_BONUS, varietyForNumber, buildBoard, neighborsKeys, hexPoints, bestCombo, schools, rollDie } = KKD;

/* ---------------- small UI bits ---------------- */
function VarietyChip({ v }) {
  const va = VARIETIES[v];
  const nums = [v, v + 6, v + 12].join(" · ");
  return (
    <div className="kk-chip">
      <span className="kk-chip-dot" style={{ background: va.body, boxShadow: "inset 0 0 0 3px " + va.patch }} />
      <span className="kk-chip-name">{va.name}<i>no. {nums}</i></span>
    </div>
  );
}

/* ---------------- main app ---------------- */
function App() {
  const board = useMemo(() => buildBoard(), []);
  const { cells, byKey, view } = board;

  const [dice, setDice] = useState(Array.from({ length: 3 }, () => ({ value: null, held: false })));
  const [rolled, setRolled] = useState(false);
  const [rerollUsed, setRerollUsed] = useState(false);
  const [phase, setPhase] = useState("roll");          // 'roll' | 'spend'
  const [used, setUsed] = useState([]);                // die indices spent this turn
  const [turn, setTurn] = useState(1);

  const [occ, setOcc] = useState({});                  // key -> {type:'koi', id}
  const [kois, setKois] = useState({});
  const [nextId, setNextId] = useState(1);

  const [sel, setSel] = useState([]);                  // selected hand die indices (any values)
  const [mode, setMode] = useState(null);              // {size, number, variety, dieIdxs, pending:[]}
  const [log, setLog] = useState([]);

  /* ---- derived score ---- */
  const score = useMemo(() => {
    let koiBonus = 0;
    Object.values(kois).forEach((k) => (koiBonus += SIZE_BONUS[k.size]));
    const comps = schools(kois, occ);
    let comboPts = 0;
    const comboList = [];
    comps.forEach((comp) => {
      if (comp.length < 2) return;
      const nums = comp.map((id) => kois[id].number);
      const c = bestCombo(nums);
      if (c) { comboPts += c.pts; comboList.push({ ...c, count: comp.length }); }
    });
    comboList.sort((a, b) => b.pts - a.pts);
    return { total: koiBonus + comboPts, koiBonus, comboPts, koi: Object.keys(kois).length, comboList };
  }, [kois, occ]);

  /* ---- hand (unused dice) ---- */
  const hand = dice.map((d, i) => ({ ...d, i })).filter((d) => d.value && !used.includes(d.i));
  const selSum = sel.reduce((s, i) => s + dice[i].value, 0);
  const selVariety = sel.length ? varietyForNumber(selSum) : null;

  /* ---- valid target cells for current mode ---- */
  const validKeys = useMemo(() => {
    if (!mode) return new Set();
    const empties = cells.filter((c) => !occ[c.key]).map((c) => c.key);
    if (mode.pending.length === 0) return new Set(empties);
    const adj = new Set();
    mode.pending.forEach((pk) => neighborsKeys(pk).forEach((nk) => {
      if (byKey[nk] && !occ[nk] && !mode.pending.includes(nk)) adj.add(nk);
    }));
    return adj;
  }, [mode, occ, cells, byKey]);

  /* ---- turn handlers ---- */
  const roll = useCallback(() => {
    if (rolled) return;
    setDice((prev) => prev.map(() => ({ value: rollDie(), held: false })));
    setRolled(true);
  }, [rolled]);

  const toggleHold = (i) => {
    if (!rolled || rerollUsed || phase !== "roll" || !dice[i].value) return;
    setDice((prev) => prev.map((d, k) => (k === i ? { ...d, held: !d.held } : d)));
  };

  const reroll = () => {
    if (!rolled || rerollUsed || phase !== "roll") return;
    setDice((prev) => prev.map((d) => (d.held ? d : { value: rollDie(), held: false })));
    setRerollUsed(true);
  };

  const tend = () => { if (rolled) setPhase("spend"); };

  const newTurn = () => {
    setDice(Array.from({ length: 3 }, () => ({ value: null, held: false })));
    setRolled(false); setRerollUsed(false); setPhase("roll"); setUsed([]);
    setSel([]); setMode(null);
    setTurn((n) => n + 1);
  };

  const pushLog = (msg) => setLog((l) => [msg, ...l].slice(0, 6));

  /* ---- dice selection (compose a koi from any 1-3 dice) ---- */
  const clickHandDie = (i) => {
    if (mode) return;
    setSel((prev) => {
      if (prev.includes(i)) return prev.filter((x) => x !== i);
      if (prev.length >= 3) return prev;
      return [...prev, i];
    });
  };

  const beginKoi = () => {
    if (!sel.length) return;
    setMode({ size: sel.length, number: selSum, variety: selVariety, dieIdxs: sel.slice(), pending: [] });
  };
  const cancelMode = () => setMode(null);

  /* ---- placing on the board ---- */
  const clickHex = (k) => {
    if (!mode || !validKeys.has(k)) return;
    const pending = [...mode.pending, k];
    if (pending.length < mode.size) { setMode({ ...mode, pending }); return; }
    const id = nextId; setNextId(id + 1);
    const koi = { id, variety: mode.variety, size: mode.size, number: mode.number, cells: pending };
    const newOcc = { ...occ }; pending.forEach((pk) => (newOcc[pk] = { type: "koi", id }));
    setOcc(newOcc);
    setKois((m) => ({ ...m, [id]: koi }));
    setUsed((u) => [...u, ...mode.dieIdxs]);
    pushLog(`${SIZE_NAME[mode.size]} koi no.${mode.number} released into the pond (+${SIZE_BONUS[mode.size]})`);
    setSel([]); setMode(null);
  };

  const resetPond = () => {
    setOcc({}); setKois({}); setNextId(1); setLog([]);
    setDice(Array.from({ length: 3 }, () => ({ value: null, held: false })));
    setRolled(false); setRerollUsed(false); setPhase("roll"); setUsed([]);
    setSel([]); setMode(null); setTurn(1);
  };

  /* ---- render board ---- */
  const inPlace = !!mode;
  const canTend = rolled;
  return (
    <div className="kk-wrap">
      {/* ===== POND ===== */}
      <section className="kk-pond">
        <div className="kk-pond-head">
          <div>
            <a className="kk-back" href="/">‹ Games</a>
            <h1>Kniffle&nbsp;Koi <span className="kk-jp">錦鯉</span></h1>
            <p className="kk-tag">Roll the dice, sum the koi, school them into Kniffel combos.</p>
          </div>
          <div className="kk-score">
            <span className="kk-score-num">{score.total}</span>
            <span className="kk-score-lab">points</span>
          </div>
        </div>

        <div className="kk-board-frame">
          <svg className="kk-board" viewBox={`${view.x} ${view.y} ${view.w} ${view.h}`} preserveAspectRatio="xMidYMid meet">
            <defs>
              <radialGradient id="dieFace" cx="38%" cy="32%" r="80%">
                <stop offset="0%" stopColor="#fffdf7" /><stop offset="100%" stopColor="#efe7d4" />
              </radialGradient>
              <radialGradient id="waterFill" cx="42%" cy="38%" r="75%">
                <stop offset="0%" stopColor="#e9f0ee" /><stop offset="60%" stopColor="#dde8e7" /><stop offset="100%" stopColor="#cfdedd" />
              </radialGradient>
              <radialGradient id="sourceFill" cx="50%" cy="46%" r="70%">
                <stop offset="0%" stopColor="#f3ecd6" /><stop offset="100%" stopColor="#e3dcc4" />
              </radialGradient>
              <filter id="koiShadow" x="-40%" y="-40%" width="180%" height="180%">
                <feDropShadow dx="0" dy="3" stdDeviation="3.4" floodColor="#3b4a48" floodOpacity="0.28" />
              </filter>
            </defs>

            {/* water cells */}
            {cells.map((c) => {
              const valid = validKeys.has(c.key);
              const pending = mode && mode.pending && mode.pending.includes(c.key);
              return (
                <g key={c.key} className={"kk-cell" + (valid ? " is-valid" : "") + (inPlace ? " is-placing" : "")}
                  onClick={() => clickHex(c.key)}>
                  <polygon points={hexPoints(c.x, c.y, KKD.R * 0.94)}
                    fill={c.isSource ? "url(#sourceFill)" : "url(#waterFill)"}
                    stroke={c.isSource ? "#caa33f" : "#b9c8c6"} strokeWidth={c.isSource ? 2 : 1.3} />
                  {c.isSource && (<>
                    <circle cx={c.x} cy={c.y} r={KKD.R * 0.34} fill="none" stroke="#caa33f" strokeWidth="1.6" opacity="0.6" />
                    <circle cx={c.x} cy={c.y} r={KKD.R * 0.16} fill="#caa33f" opacity="0.5" />
                  </>)}
                  {valid && <polygon className="kk-valid-ring" points={hexPoints(c.x, c.y, KKD.R * 0.82)} fill="none" stroke="#caa33f" strokeWidth="2.4" strokeDasharray="5 5" />}
                  {pending && <polygon points={hexPoints(c.x, c.y, KKD.R * 0.9)} fill="#caa33f" opacity="0.28" />}
                </g>
              );
            })}

            {/* koi */}
            {Object.values(kois).map((kk) => <window.KKKoi key={kk.id} koi={kk} byKey={byKey} />)}
          </svg>
        </div>

        <div className="kk-log">
          {log.length === 0 ? <span className="kk-log-empty">Roll the dice to begin stocking your pond.</span>
            : log.map((m, i) => <div key={i} className="kk-log-row" style={{ opacity: 1 - i * 0.13 }}>{m}</div>)}
        </div>
      </section>

      {/* ===== CONTROL PANEL ===== */}
      <aside className="kk-panel">
        <div className="kk-turn">Turn {turn} · {phase === "roll" ? (rolled ? (rerollUsed ? "tend the pond" : "keep & reroll once") : "roll to begin") : "stock the pond"}</div>

        {/* dice */}
        <div className="kk-dice">
          {dice.map((d, i) => {
            const isHand = phase === "spend" && d.value && !used.includes(i);
            const spent = phase === "spend" && used.includes(i);
            return (
              <window.KKDie key={i} value={d.value} held={phase === "roll" && d.held}
                selected={isHand && sel.includes(i)} dim={spent}
                idle={phase === "roll" && !rolled}
                onClick={() => (phase === "roll" ? toggleHold(i) : isHand ? clickHandDie(i) : null)} />
            );
          })}
        </div>

        {phase === "roll" && (
          <div className="kk-actions">
            {!rolled ? (
              <button className="kk-btn kk-btn-primary" onClick={roll}>Roll the dice</button>
            ) : (
              <>
                <button className="kk-btn" onClick={reroll} disabled={rerollUsed}>
                  {rerollUsed ? "Reroll spent" : "Reroll the rest (once)"}
                </button>
                <button className="kk-btn kk-btn-primary" onClick={tend} disabled={!canTend}>Tend the pond →</button>
                {!rerollUsed && <p className="kk-hint">Tap dice to <b>keep</b> them, then reroll the rest — once per turn.</p>}
              </>
            )}
          </div>
        )}

        {phase === "spend" && (
          <div className="kk-spend">
            {!mode && (
              <div className="kk-compose">
                <p className="kk-mini">
                  {sel.length
                    ? <>This will be a <b>{SIZE_NAME[sel.length].toLowerCase()}</b> koi numbered <b>{selSum}</b>.</>
                    : <>Pick <b>1–3 dice</b> to raise a koi. Count = size; their <b>sum</b> is the koi's number.</>}
                </p>
                <div className="kk-compose-preview" style={{ visibility: sel.length ? "visible" : "hidden" }}>
                  <span className="kk-prev-dot" style={selVariety ? { background: VARIETIES[selVariety].body, boxShadow: "inset 0 0 0 4px " + VARIETIES[selVariety].patch } : {}} />
                  <span className="kk-prev-num">{selSum || ""}</span>
                  <span className="kk-prev-name">{selVariety ? VARIETIES[selVariety].name + " · " + SIZE_NAME[sel.length] : ""}</span>
                </div>
                <button className="kk-btn kk-btn-primary" disabled={!sel.length} onClick={beginKoi}>
                  Place {sel.length ? SIZE_NAME[sel.length].toLowerCase() + " koi" : "koi"}
                </button>
                {hand.length === 0 && <p className="kk-hint">All dice spent — end the turn.</p>}
              </div>
            )}

            {mode && (
              <div className="kk-placing">
                <p className="kk-mini">
                  Placing a <b>{SIZE_NAME[mode.size].toLowerCase()}</b> koi no.<b>{mode.number}</b> — click {mode.size} connected field{mode.size > 1 ? "s" : ""} ({mode.pending.length}/{mode.size}).
                </p>
                <button className="kk-btn" onClick={cancelMode}>Cancel</button>
              </div>
            )}

            <button className="kk-btn kk-btn-ghost kk-end" onClick={newTurn}>End turn →</button>
          </div>
        )}

        {/* score breakdown */}
        <div className="kk-break">
          <div className="kk-break-row"><span>Koi in pond</span><b>{score.koi}</b></div>
          <div className="kk-break-row"><span>Koi bonus (size)</span><b>+{score.koiBonus}</b></div>
          <div className="kk-break-row"><span>School combos</span><b>+{score.comboPts}</b></div>
        </div>

        {score.comboList.length > 0 && (
          <div className="kk-combos">
            {score.comboList.map((c, i) => (
              <div key={i} className={"kk-combo kk-combo-" + c.key}>
                <span className="kk-combo-label">{c.label}</span>
                <span className="kk-combo-pts">+{c.pts}</span>
              </div>
            ))}
          </div>
        )}

        {/* legend */}
        <details className="kk-legend" open>
          <summary>Koi colour follows the tile number</summary>
          <div className="kk-legend-grid">
            {[1, 2, 3, 4, 5, 6].map((v) => <VarietyChip key={v} v={v} />)}
          </div>
        </details>

        <details className="kk-rules">
          <summary>How it works</summary>
          <ul>
            <li><b>Roll &amp; reroll.</b> Roll 5 dice; keep any, then reroll the rest <i>once</i> per turn.</li>
            <li><b>Raise koi.</b> Spend 1–3 dice on a koi — that many tiles (single / double / triple). The koi's number is the <b>sum</b> of its dice (2 + 5 + 1 → an <b>8</b> koi). Same number ⇒ same colour.</li>
            <li><b>Size bonus.</b> Single <b>+1</b>, double <b>+3</b>, triple <b>+6</b> — bigger koi are worth more.</li>
            <li><b>Kniffel schools.</b> Touching koi form a school. Each school scores its best combo on the koi numbers: pair +2, three +6, four +12, full house +14, small straight +15, large straight +20, <b>Kniffle (five of a kind) +25</b>.</li>
          </ul>
        </details>

        <button className="kk-btn kk-btn-ghost kk-reset" onClick={resetPond}>↺ New pond</button>
      </aside>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
