// Shared browser entry: index.html loads this file directly, so source and served game stay in sync.
import { LEVELS, MODES, ROUND_MS, STORAGE_KEY, localDateKey, shuffled, dailyLevels, scoreAnswer, summarize, recordSession } from "/spill/tactics/tactics-engine.js";
const { useState, useEffect, useRef, useCallback } = React;

function Arrow({ className = "" }) { return <svg className={className} width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M5 12h14m-6-6 6 6-6 6" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/></svg>; }
function Shirt({ number, opponent = false, keeper = false }) {
  return <svg className="player-shirt" viewBox="0 0 44 46" aria-hidden="true"><ellipse cx="22" cy="41" rx="16" ry="4" fill="#071c14" opacity=".4"/><path d="m14 7-7 4-5 10 8 4 3-6v21h18V19l3 6 8-4-5-10-7-4c-4 4-12 4-16 0Z" fill={keeper ? "#f5bd57" : opponent ? "#3d314d" : "#f6eddf"} stroke={opponent ? "#b2a3b6" : "#fff9ed"} strokeWidth="1.2" strokeLinejoin="round"/><path d="M15 7c1 7 13 7 14 0" fill="none" stroke={opponent ? "#d58bb2" : "#bd346f"} strokeWidth="2.2"/><path d="M13 33h18v6H13z" fill={opponent ? "#9f668f" : "#bf3871"} opacity=".85"/>{opponent ? <path d="m18 21 8 8m0-8-8 8" stroke="#e7cce0" strokeWidth="2"/> : <text x="22" y="29" textAnchor="middle" fill="#37232b" fontFamily="Arial,sans-serif" fontWeight="800" fontSize="14">{number}</text>}</svg>;
}
function Pitch({ level, picked = null, revealed = false, onPick, preview = false }) {
  const carrier = level.team[level.ballCarrier], best = level.team[level.best];
  const chosen = picked !== null ? level.team[picked] : null;
  return <div className={`pitch-frame ${preview ? "pitch-preview" : ""}`}>
    <div className="pitch-top"><span><i/> SPACEBERRIES / TRENINGSFELTET</span><span>5-A-SIDE</span></div>
    <div className="pitch" role="group" aria-label={preview ? "Forhåndsvisning av fotballbanen" : `Fotballbane. Spiller ${carrier.n} har ballen. Angrepsretning oppover.`}>
      <svg className="field-lines" viewBox="0 0 100 106" preserveAspectRatio="none" aria-hidden="true">
        <defs><pattern id="net" width="1.5" height="1.5" patternUnits="userSpaceOnUse"><path d="M1.5 0H0v1.5" fill="none" stroke="#d7ecdb" strokeWidth=".15"/></pattern><marker id="pass-arrow" viewBox="0 0 10 10" refX="18" refY="5" markerWidth="5" markerHeight="5" orient="auto-start-reverse"><path d="m0 0 10 5-10 5Z" fill="#bcf5b9"/></marker><marker id="chosen-arrow" viewBox="0 0 10 10" refX="18" refY="5" markerWidth="5" markerHeight="5" orient="auto-start-reverse"><path d="m0 0 10 5-10 5Z" fill="#ffcf79"/></marker></defs>
        <g stroke="#d6e7c9" strokeWidth=".38" fill="none" opacity=".58"><rect x="4" y="4" width="92" height="98" rx=".3"/><path d="M4 53h92"/><circle cx="50" cy="53" r="12"/><circle cx="50" cy="53" r=".6" fill="#d6e7c9"/><path d="M24 4v19h52V4M37 4v7h26V4M24 102V83h52v19M37 102v-7h26v7M40 23a12 12 0 0 0 20 0M40 83a12 12 0 0 1 20 0"/><circle cx="50" cy="17" r=".5" fill="#d6e7c9"/><circle cx="50" cy="89" r=".5" fill="#d6e7c9"/><rect x="42" y="1" width="16" height="3" fill="url(#net)"/><rect x="42" y="102" width="16" height="3" fill="url(#net)"/><path d="M4 7a3 3 0 0 0 3-3M93 4a3 3 0 0 0 3 3M4 99a3 3 0 0 1 3 3M93 102a3 3 0 0 1 3-3"/></g>
        {revealed && <><circle cx={best.x} cy={best.y * 1.06} r="8" fill="#c4fcb6" opacity=".1"/><line className="best-pass" x1={carrier.x} y1={carrier.y * 1.06} x2={best.x} y2={best.y * 1.06} stroke="#bcf5b9" strokeWidth=".8" markerEnd="url(#pass-arrow)"/>{chosen && picked !== level.best && <line x1={carrier.x} y1={carrier.y * 1.06} x2={chosen.x} y2={chosen.y * 1.06} stroke="#ffcf79" strokeWidth=".65" strokeDasharray="1.6 1.3" markerEnd="url(#chosen-arrow)"/>}</>}
      </svg>
      <span className="attack-label" aria-hidden="true">↑ ANGRIP</span>
      <div className="pitch-player opponent keeper" style={{ left: `${level.keeper.x}%`, top: `${level.keeper.y}%` }} aria-hidden="true"><Shirt keeper number="K"/></div>
      {level.opp.map((player, i) => <div className="pitch-player opponent" style={{ left: `${player.x}%`, top: `${player.y}%` }} key={`opp-${i}`} aria-hidden="true"><Shirt opponent/></div>)}
      {level.team.map((player, i) => {
        const isCarrier = i === level.ballCarrier;
        const isBest = revealed && i === level.best;
        const className = `pitch-player teammate ${isCarrier ? "ball-carrier" : ""} ${isBest ? "best-player" : ""} ${revealed && i === picked ? "chosen-player" : ""}`;
        const children = <><Shirt number={player.n}/>{isCarrier && <span className="football" aria-hidden="true"><svg viewBox="0 0 20 20"><circle cx="10" cy="10" r="9" fill="#fff9ec" stroke="#c2bcaf"/><path d="m10 5 4 3-1.5 5h-5L6 8Z" fill="#343236"/><path d="m1 9 4-2M5 17l3-4m7 4-3-4m7-4-5-2M10 1v4" stroke="#343236" strokeWidth="1.4"/></svg></span>}<span className="player-caption">{isCarrier ? "BALL" : isBest ? "BESTE VALG" : player.r}</span></>;
        return preview || isCarrier ? <div className={className} style={{ left: `${player.x}%`, top: `${player.y}%` }} key={player.n} aria-hidden={preview}>{children}</div> : <button type="button" className={className} style={{ left: `${player.x}%`, top: `${player.y}%` }} key={player.n} disabled={revealed} onClick={() => onPick(i)} aria-label={`Spill til nummer ${player.n}, ${roleName(player.r)}${isBest ? ", anbefalt valg" : ""}`}>{children}</button>;
      })}
      <span className="pitch-wordmark" aria-hidden="true">spaceberries</span>
    </div>
    <div className="pitch-legend"><span><i className="legend-team"/> Ditt lag</span><span><i className="legend-opp"/> Motstander</span>{revealed ? <span><i className="legend-pass"/> Anbefalt pasning</span> : <span>Angrepsretning ↑</span>}</div>
  </div>;
}
function roleName(role) { return ({ M: "Midtbane", V: "Venstre", H: "Høyre", VS: "Venstre spiss", HS: "Høyre spiss", S: "Spiss", HB: "Høyreback", VM: "Venstre midtbane", K: "Keeper" })[role] || role; }
function readRecords() { try { return JSON.parse(localStorage.getItem(STORAGE_KEY)) || {}; } catch { return {}; } }
const feedbackTitles = { best: "Godt sett!", ok: "Et brukbart alternativ.", wrong: "Se etter et annet rom.", timeout: "Tiden er ute. La oss se.", skip: "La oss lese spillet sammen." };
const resultSymbols = { best: "✓", ok: "≈", wrong: "·", timeout: "◷", skip: "–" };

export default function TacticsGame5v5() {
  const [page, setPage] = useState("menu");
  const [records, setRecords] = useState(readRecords);
  const [today, setToday] = useState(localDateKey);
  const [session, setSession] = useState(null);
  const [round, setRound] = useState(0);
  const [answers, setAnswers] = useState([]);
  const [remaining, setRemaining] = useState(ROUND_MS);
  const answerLock = useRef(false), startTime = useRef(0), headingRef = useRef(null), feedbackRef = useRef(null), saved = useRef(false);
  const level = session?.levels[round];
  const answer = answers[round];
  const totals = summarize(answers);
  const dailyRecord = records.daily?.[today];

  useEffect(() => {
    const refresh = () => setToday(localDateKey());
    const interval = setInterval(refresh, 30000);
    window.addEventListener("focus", refresh);
    return () => { clearInterval(interval); window.removeEventListener("focus", refresh); };
  }, []);

  const start = mode => {
    const dateKey = localDateKey();
    setToday(dateKey);
    setSession({ mode, dateKey, levels: mode === "daily" ? dailyLevels(dateKey) : mode === "practice" ? [...LEVELS] : shuffled(LEVELS), run: Date.now() });
    setRound(0); setAnswers([]); setRemaining(ROUND_MS); answerLock.current = false; saved.current = false; setPage("play");
  };
  const choose = useCallback((picked, reason) => {
    if (page !== "play" || !level || answerLock.current) return;
    const elapsed = Math.max(0, Date.now() - startTime.current);
    const timedOut = session.mode === "timed" && elapsed >= ROUND_MS;
    answerLock.current = true;
    const result = scoreAnswer(level, timedOut ? null : picked, session.mode, elapsed, summarize(answers).streak, timedOut ? "timeout" : reason);
    setAnswers(previous => [...previous, { ...result, picked: timedOut ? null : picked, level: level.id }]);
  }, [page, level, session, answers]);

  useEffect(() => {
    if (page !== "play" || answer) return;
    answerLock.current = false;
    startTime.current = Date.now();
    setRemaining(ROUND_MS);
    headingRef.current?.focus({ preventScroll: true });
    if (window.matchMedia("(max-width: 650px)").matches) headingRef.current?.scrollIntoView({ block: "start" });
    if (session.mode !== "timed") return;
    const interval = setInterval(() => {
      const left = Math.max(0, ROUND_MS - (Date.now() - startTime.current));
      setRemaining(left);
      if (!left) { clearInterval(interval); choose(null, "timeout"); }
    }, 100);
    return () => clearInterval(interval);
  }, [page, round, session, Boolean(answer)]);

  useEffect(() => { if (answer) feedbackRef.current?.focus({ preventScroll: true }); }, [answer]);
  useEffect(() => {
    if (page !== "play" || answer) return;
    const handleKey = event => {
      if (event.altKey || event.ctrlKey || event.metaKey || event.repeat || /INPUT|TEXTAREA|SELECT/.test(event.target.tagName)) return;
      const index = level.team.findIndex(player => String(player.n) === event.key);
      if (index >= 0 && index !== level.ballCarrier) { event.preventDefault(); choose(index); }
    };
    window.addEventListener("keydown", handleKey);
    return () => window.removeEventListener("keydown", handleKey);
  }, [page, answer, level, choose]);
  useEffect(() => { if (page === "results") headingRef.current?.focus({ preventScroll: true }); }, [page]);

  const next = () => {
    if (!answer) return;
    if (round + 1 < session.levels.length) { setRound(value => value + 1); return; }
    if (!saved.current) {
      saved.current = true;
      const updated = recordSession(records, session.mode, session.dateKey, answers);
      setRecords(updated);
      try { localStorage.setItem(STORAGE_KEY, JSON.stringify(updated)); } catch { /* Play remains available when browser storage is blocked. */ }
    }
    setPage("results");
  };

  return <div className="tactics-app">
    <header className="site-header"><a className="brand" href="/" aria-label="Spaceberries, forsiden"><img src="/brand/mark.svg" width="27" height="29" alt=""/><span>Spaceberries</span></a><a className="back-link" href="/spill/"><span aria-hidden="true">↖</span> Alle spill</a></header>
    <main>
      {page === "menu" && <>
        <section className="tactics-hero">
          <div className="hero-copy"><div className="eyebrow"><span className="status-dot"/> FOTBALL FOR HODET</div><h1>Se rommet.<br/>Spill <em>smartere.</em></h1><p className="hero-description">De beste pasningene starter med et blikk. Tren fotballblikket ditt, ett valg om gangen.</p><div className="hero-actions"><button className="button primary" onClick={() => start("practice")}>Start treningen <Arrow/></button><button className="text-button" onClick={() => start("daily")}>Prøv dagens tre <span aria-hidden="true">↗</span></button></div><div className="hero-meta"><span>5 mot 5</span><span>10 situasjoner</span><span>Ingen innlogging</span></div></div>
          <div className="hero-board"><div className="board-heading"><span>TAKTIKKHJERNEN</span><span className="edition">01 / PÅ TRENINGSFELTET</span></div><Pitch level={LEVELS[3]} revealed preview/><div className="preview-note"><span className="note-icon">↗</span><div><strong>Et lite rom. En stor mulighet.</strong><span>Se pasningen mellom forsvarerne.</span></div></div></div>
        </section>
        <section className="mode-section" aria-labelledby="mode-heading"><div className="section-heading"><div><p className="eyebrow">VELG DIN ØKT</p><h2 id="mode-heading">Samme bane. Ditt tempo.</h2></div><p>Se. Velg. Lær noe nytt.</p></div><div className="mode-grid">
          <button className="mode-card" onClick={() => start("practice")}><span className="mode-number">01 <span>UTEN KLOKKE</span></span><h3>Tren i eget tempo</h3><p>Utforsk alle ti situasjonene. Se anbefalt pasning og forstå hvorfor den fungerer.</p><span className="mode-bottom">Start en treningsøkt <Arrow/></span></button>
          <button className="mode-card daily-card" onClick={() => start("daily")}><span className="mode-number">02 <span>{dailyRecord ? "SPILT I DAG" : "NY HVER DAG"}</span></span><h3>Dagens tre <span className="mini-sun" aria-hidden="true">✳</span></h3><p>Tre situasjoner. Ingen tidspress. Dagens første resultat og beste poengsum lagres her.</p><span className="mode-bottom">{dailyRecord ? `Første: ${dailyRecord.first.score} / 300 · Prøv igjen` : "Ta dagens utfordring"} <Arrow/></span></button>
          <button className="mode-card" onClick={() => start("timed")}><span className="mode-number">03 <span>30 SEK / SITUASJON</span></span><h3>Spill mot klokka</h3><p>Ti situasjoner i tilfeldig rekkefølge. Raske, gode valg gir bonuspoeng.</p><span className="mode-bottom">{records.timed?.played ? `Din rekord: ${records.timed.best} poeng` : "Test fotballblikket"} <Arrow/></span></button>
        </div></section>
        <p className="game-footnote">En liten taktikkøkt fra Spaceberries. Situasjonene er forenklede: vi trener på å se rom og pasningsvalg, og flere løsninger kan fungere i en ekte kamp.</p>
      </>}
      {page === "play" && level && <section className="game-section">
        <div className="game-toolbar"><button className="text-button" onClick={() => setPage("menu")}>← Velg økt</button><span className="game-title">TAKTIKKHJERNEN <span>/ {MODES[session.mode].short}</span></span><button className="text-button restart" onClick={() => start(session.mode)}>Start på nytt ↻</button></div>
        <div className="game-layout"><div className="game-board-column"><div className="round-bar"><span>SITUASJON <strong>{String(round + 1).padStart(2, "0")} <span>/ {String(session.levels.length).padStart(2, "0")}</span></strong></span><div className="round-dots" aria-label={`${answers.filter(item => item).length} svar av ${session.levels.length}`}>{session.levels.map((_, i) => <i key={i} className={`${i === round ? "current" : ""} ${answers[i]?.result || ""}`}>{answers[i] ? resultSymbols[answers[i].result] : ""}</i>)}</div><span className="round-score">{session.mode === "practice" ? "UTEN TIDSPRESS" : `${totals.score} POENG`}</span></div><Pitch level={level} picked={answer?.picked ?? null} revealed={Boolean(answer)} onPick={choose}/></div>
          <div className="coach-panel"><div className="question"><div className="eyebrow">{level.category} <span className="difficulty">{["Grunnspill", "Samspill", "Spilleforståelse"][level.difficulty - 1]}</span></div><h1 ref={headingRef} tabIndex="-1">{level.title}</h1><p>{level.desc}</p><div className="ball-note"><span className="small-shirt">{level.team[level.ballCarrier].n}</span><span>Spiller {level.team[level.ballCarrier].n} har ballen.<br/><strong>Hvem vil du spille til?</strong></span></div></div>
            {session.mode === "timed" && <div className={`timer ${remaining < 6000 ? "urgent" : ""}`}><div><span>{answer ? "RUNDEN ER FERDIG" : "TID IGJEN"}</span><strong aria-label={`${Math.ceil(remaining / 1000)} sekunder igjen`}>{Math.ceil(remaining / 1000)}<small>s</small></strong></div><progress max={ROUND_MS} value={remaining} aria-label="Tid igjen på runden"/></div>}
            <div className="pass-options" aria-label="Velg en medspiller">{level.team.map((player, index) => index === level.ballCarrier ? null : <button key={player.n} className={`pass-option ${answer && index === level.best ? "recommended" : ""} ${answer && index === answer.picked ? "selected" : ""}`} onClick={() => choose(index)} disabled={Boolean(answer)}><span className="option-number">{player.n}</span><span>{roleName(player.r)}{answer && index === level.best && <small>Anbefalt pasning</small>}{answer && index === answer.picked && index !== level.best && <small>Ditt valg</small>}</span><span className="option-arrow" aria-hidden="true">{answer && index === level.best ? "✓" : "↗"}</span></button>)}</div>
            {answer ? <div className={`feedback ${answer.result}`}><div className="feedback-label">{answer.result === "best" ? "GOD SPILLEFORSTÅELSE" : "TRENERENS TIPS"}{session.mode !== "practice" && <span>+{answer.points} poeng</span>}</div><h2 ref={feedbackRef} tabIndex="-1">{feedbackTitles[answer.result]}</h2><p>{level.explanation}</p><div className="concept"><span aria-hidden="true">↗</span>{level.concept}</div><button className="button primary next-button" onClick={next}>{round + 1 === session.levels.length ? "Se resultatet" : "Neste situasjon"}<Arrow/></button></div> : <div className="control-help"><p>Trykk på en spiller eller velg et nummer.<br/><span>På tastatur: bruk spillernummeret.</span></p><button className="text-button" onClick={() => choose(null, "skip")}>{session.mode === "practice" ? "Vis meg løsningen" : "Hopp over og se løsningen"} <span aria-hidden="true">↗</span></button></div>}
          </div>
        </div>
      </section>}
      {page === "results" && <section className="results-section"><div className="eyebrow">{MODES[session.mode].short} / ØKT FULLFØRT</div><div className="result-stamp" aria-hidden="true">✳</div><h1 ref={headingRef} tabIndex="-1">{totals.best === answers.length ? "For et fotballblikk." : totals.best >= answers.length / 2 ? "Du ser mulighetene." : "Hvert blikk er trening."}</h1><p className="result-intro">{session.mode === "practice" ? "Ta med deg det du har lært ut på banen." : session.mode === "daily" ? "Tre situasjoner unnagjort. Et nytt sett venter i morgen." : "Bra økt. Se gjennom valgene dine og prøv igjen."}</p><div className="result-stats"><div><strong>{totals.best}<small>/{answers.length}</small></strong><span>ANBEFALTE VALG</span></div><div><strong>{session.mode === "practice" ? totals.ok : totals.score}</strong><span>{session.mode === "practice" ? "GODE ALTERNATIVER" : "POENG"}</span></div><div><strong>{totals.bestStreak}</strong><span>BESTE REKKE</span></div></div>{session.mode === "daily" && <p className="saved-note">{session.dateKey} · Første forsøk: {records.daily?.[session.dateKey]?.first?.score ?? totals.score} / 300 · Beste: {records.daily?.[session.dateKey]?.best ?? totals.score} / 300</p>}
        <div className="result-review"><h2>Ta med deg dette</h2>{answers.map((item, i) => <details key={item.level}><summary><span className={`result-indicator ${item.result}`}>{resultSymbols[item.result]}</span><span>{session.levels[i].title}<small>{item.result === "best" ? "Anbefalt valg" : item.result === "ok" ? "Et godt alternativ" : item.result === "skip" ? "Løsning vist" : item.result === "timeout" ? "Tiden gikk ut" : "Noe å trene på"}</small></span><span className="review-plus" aria-hidden="true">+</span></summary><p>{session.levels[i].explanation}</p></details>)}</div><div className="result-actions"><button className="button primary" onClick={() => start(session.mode)}>{session.mode === "daily" ? "Prøv dagens tre igjen" : "Ta en ny økt"}<Arrow/></button><button className="button secondary" onClick={() => setPage("menu")}>Velg en annen økt</button></div><p className="game-footnote">Resultatene lagres i denne nettleseren når lagring er tilgjengelig.</p></section>}
    </main>
    <footer className="site-footer"><span>Et lite spill. Et litt skarpere blikk.</span><a href="/spill/">Mer å spille <Arrow/></a></footer>
  </div>;
}

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