// app.jsx — root: layout, state, badges, tweaks panel

const { useState: useAState, useEffect: useEApp, useRef: useRApp, useMemo: useMApp } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "showHints": true,
  "showCommandHints": true,
  "autoAdvance": true,
  "theme": "playful",
  "octoSize": 84
}/*EDITMODE-END*/;

function App() {
  const [state, setState] = useAState(() => createInitialState());
  const [chapterIdx, setChapterIdx] = useAState(0);
  const [stepIdx, setStepIdx] = useAState(0);
  const [lastCommand, setLastCommand] = useAState("");
  const [viewerFile, setViewerFile] = useAState(null);
  const [popupBadge, setPopupBadge] = useAState(null);
  const [confetti, setConfetti] = useAState(null);
  const [shake, setShake] = useAState(null);
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);

  const currentStep = CHAPTERS[chapterIdx]?.steps[stepIdx];
  const suggestion = (tweaks.showCommandHints && currentStep?.suggest) ? currentStep.suggest : "";

  // Auto-fired steps: run a sequence of commands behind the scenes
  // (used to simulate teammate Riley editing on GitHub, etc.) so the
  // student doesn't have to type unrealistic "collab" commands.
  const autoRanRef = useRApp(new Set());
  useEApp(() => {
    if (!currentStep?.auto) return;
    const key = `${chapterIdx}:${stepIdx}`;
    if (autoRanRef.current.has(key)) return;
    autoRanRef.current.add(key);
    const cmds = currentStep.auto;
    const timers = [];
    cmds.forEach((cmd, i) => {
      timers.push(setTimeout(() => {
        setState((prev) => runAny(prev, cmd).state);
      }, 800 * (i + 1)));
    });
    return () => timers.forEach(clearTimeout);
  }, [chapterIdx, stepIdx]);

  const handleEvents = (events, cmdText) => {
    setLastCommand(cmdText);
    for (const e of events) {
      if (e.type === "badge") {
        if (!state.badges.includes(e.id)) {
          setState(s => ({ ...s, badges: [...s.badges, e.id] }));
          setPopupBadge({ id: e.id, name: e.name });
          setConfetti(Date.now());
        }
      }
      if (e.type === "anim") {
        if (e.kind === "commit" || e.kind === "merge") setConfetti(Date.now());
        if (e.kind === "conflict") setShake(Date.now());
      }
      if (e.type === "err") setShake(Date.now());
    }
  };

  const handleNext = () => {
    const ch = CHAPTERS[chapterIdx];
    if (stepIdx + 1 < ch.steps.length) setStepIdx(stepIdx + 1);
    else if (chapterIdx + 1 < CHAPTERS.length) {
      setChapterIdx(chapterIdx + 1);
      setStepIdx(0);
    }
  };
  const handlePrev = () => {
    if (stepIdx > 0) setStepIdx(stepIdx - 1);
    else if (chapterIdx > 0) {
      setChapterIdx(chapterIdx - 1);
      setStepIdx(CHAPTERS[chapterIdx - 1].steps.length - 1);
    }
  };
  const handleJump = (c, s) => {
    if (c !== chapterIdx) {
      // Re-seed prerequisite state so the chapter is independently playable.
      // Without this, jumping to (e.g.) Merge Conflicts before pushing to a
      // remote would crash collab push when it tried to read remote.commits[undefined].
      setState(seedForChapter(c));
      setLastCommand("");
    }
    setChapterIdx(c);
    setStepIdx(s);
  };

  const handleFileClick = (f) => {
    const file = state.workingDir[f];
    if (file) setViewerFile({ name: f, content: file.content, conflict: file.conflict });
  };

  const reset = () => {
    if (confirm("Reset all progress?")) {
      setState(createInitialState());
      setChapterIdx(0); setStepIdx(0); setLastCommand("");
    }
  };

  const totalCommits = Object.keys(state.commits).length;
  const totalBadges = state.badges.length;

  return (
    <div style={{
      width: "100vw",
      height: "100vh",
      display: "grid",
      gridTemplateRows: "auto 1fr",
      gap: 10,
      padding: 10,
      animation: shake ? "shake 0.3s" : "none",
    }} key={shake}>
      {/* Top bar */}
      <div className="panel panel-lg" style={{
        background: "var(--paper)",
        padding: "10px 16px",
        display: "flex",
        alignItems: "center",
        gap: 14,
        flexWrap: "wrap",
      }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10, flexShrink: 0 }}>
          <div style={{
            width: 40, height: 40,
            background: "var(--octo)",
            border: "2.5px solid var(--ink)",
            borderRadius: 10,
            display: "flex", alignItems: "center", justifyContent: "center",
            fontSize: 22,
            boxShadow: "var(--shadow-sm)",
          }}>🐙</div>
          <div>
            <div style={{ fontWeight: 700, fontSize: 18, lineHeight: 1 }}>Git Playground</div>
            <div style={{ fontSize: 11, opacity: 0.6 }}>learn github by doing</div>
          </div>
        </div>

        <div style={{ flex: 1, minWidth: 200 }}>
          <ChapterNav chapterIdx={chapterIdx} stepIdx={stepIdx} onJump={handleJump} badges={state.badges} />
        </div>

        <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
          <div className="chip" style={{ background: "var(--commit-bg)" }}>
            ◉ {totalCommits} commits
          </div>
          <div className="chip" style={{ background: "var(--joy)" }}>
            🏆 {totalBadges} badges
          </div>
          <button className="btn" onClick={reset} style={{ fontSize: 11 }}>↺ reset</button>
        </div>
      </div>

      {/* Body grid */}
      <div style={{
        display: "grid",
        gridTemplateColumns: "1fr 1fr",
        gridTemplateRows: "auto minmax(440px, 1fr) minmax(160px, 220px)",
        gap: 10,
        minHeight: 0,
        overflow: "auto",
      }}>
        {/* Story spans both columns */}
        <div style={{ gridColumn: "1 / -1" }}>
          <StoryPanel
            chapterIdx={chapterIdx}
            stepIdx={stepIdx}
            onNext={handleNext}
            onPrev={handlePrev}
            onJump={handleJump}
            lastCommand={lastCommand}
            state={state}
            hintsOn={tweaks.showHints}
          />
        </div>

        {/* Local column */}
        <div style={{ minHeight: 0, height: "100%", overflow: "hidden", display: "flex" }}>
          <LocalColumn state={state} onFileClick={handleFileClick} />
        </div>

        {/* Remote column */}
        <div style={{ minHeight: 0, height: "100%", overflow: "hidden", display: "flex" }}>
          <RemoteColumn state={state} />
        </div>

        {/* Terminal spans both columns */}
        <div style={{ gridColumn: "1 / -1", minHeight: 0, height: "100%", display: "flex" }}>
          <Terminal
            state={state}
            setState={setState}
            onEvents={handleEvents}
            suggestion={suggestion}
            onCommand={setLastCommand}
          />
        </div>
      </div>

      {/* Overlays */}
      <FileViewer
        filename={viewerFile?.name}
        content={viewerFile?.content}
        conflict={viewerFile?.conflict}
        onClose={() => setViewerFile(null)}
      />
      <BadgePopup badge={popupBadge} onDismiss={() => setPopupBadge(null)} />
      {confetti && <Confetti key={confetti} />}

      {/* Tweaks panel */}
      <TweaksPanel title="Tweaks">
        <TweakSection title="Lesson">
          <TweakToggle
            label="Show Octo's spoken hints"
            value={tweaks.showHints}
            onChange={v => setTweak("showHints", v)}
          />
          <TweakToggle
            label="Show command suggestions ($)"
            value={tweaks.showCommandHints}
            onChange={v => setTweak("showCommandHints", v)}
          />
          <TweakToggle
            label="Auto-advance on success"
            value={tweaks.autoAdvance}
            onChange={v => setTweak("autoAdvance", v)}
          />
        </TweakSection>
        <TweakSection title="Skip ahead">
          <TweakSelect
            label="Jump to chapter"
            value={chapterIdx}
            options={CHAPTERS.map((c, i) => ({ value: i, label: c.title }))}
            onChange={v => handleJump(parseInt(v), 0)}
          />
          <TweakButton onClick={reset}>Reset all progress</TweakButton>
        </TweakSection>
        <TweakSection title="Quick scenarios">
          <TweakButton onClick={() => {
            // seed: initialized + a couple of commits
            let s = createInitialState();
            s.initialized = true;
            s.workingDir = { "README.md": { content: "# Robotics Club" } };
            s.staging = { "README.md": "# Robotics Club" };
            const { state: s2 } = runAny(s, 'git commit -m "init"');
            setState(s2);
            setChapterIdx(2); setStepIdx(0);
          }}>Seed: ready for branches</TweakButton>
          <TweakButton onClick={() => {
            setChapterIdx(7); setStepIdx(0);
          }}>Jump to Sandbox</TweakButton>
        </TweakSection>
      </TweaksPanel>
    </div>
  );
}

// ---------- Confetti ----------
function Confetti() {
  const colors = ["#FFD93D", "#FF6B9D", "#6366F1", "#7FE07F", "#FF7A45"];
  const pieces = Array.from({ length: 30 }, (_, i) => ({
    id: i,
    left: Math.random() * 100,
    color: colors[i % colors.length],
    delay: Math.random() * 0.3,
    duration: 1.4 + Math.random() * 0.8,
    size: 6 + Math.random() * 8,
  }));
  return (
    <div style={{
      position: "fixed",
      top: 0, left: 0, right: 0,
      height: 200,
      pointerEvents: "none",
      zIndex: 700,
      overflow: "hidden",
    }}>
      {pieces.map(p => (
        <div key={p.id} style={{
          position: "absolute",
          left: `${p.left}%`,
          top: -20,
          width: p.size, height: p.size,
          background: p.color,
          border: "1.5px solid var(--ink)",
          animation: `confetti-fall ${p.duration}s ease-in ${p.delay}s forwards`,
          borderRadius: Math.random() > 0.5 ? "50%" : "2px",
        }} />
      ))}
    </div>
  );
}

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