// GameForge portfolio — single-page interactive prototype
const { useState, useEffect, useRef } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "green",
  "fontScheme": "pixel-mix"
}/*EDITMODE-END*/;

const ACCENTS = {
  green:   { hex: "#00e69a", glow: "rgba(0,230,154,.18)", ink: "#03110a" },
  violet:  { hex: "#a78bfa", glow: "rgba(167,139,250,.20)", ink: "#0e0820" },
  orange:  { hex: "#ff8a3d", glow: "rgba(255,138,61,.20)", ink: "#1a0a02" },
  magenta: { hex: "#ff4fb1", glow: "rgba(255,79,177,.22)", ink: "#1a0212" },
};

const FONT_SCHEMES = {
  "pixel-mix": { display: '"Space Grotesk", system-ui, sans-serif', body: '"Inter", system-ui, sans-serif', mono: '"JetBrains Mono", ui-monospace, monospace', pixel: '"Silkscreen", "Press Start 2P", monospace' },
  "all-serif": { display: '"Fraunces", Georgia, serif', body: '"Source Serif 4", Georgia, serif', mono: '"JetBrains Mono", ui-monospace, monospace', pixel: '"Fraunces", Georgia, serif' },
  "all-sans":  { display: '"Space Grotesk", system-ui, sans-serif', body: '"Inter", system-ui, sans-serif', mono: '"JetBrains Mono", ui-monospace, monospace', pixel: '"Space Grotesk", system-ui, sans-serif' },
};

const FORGES = [
  {
    id: "scene", name: "SceneForge",
    promise: "Describe a level. Get a playable scene.",
    sub: "The agent paints the scene and marks where the player can walk. The engine renders it as a playable level.",
    img: "assets/products/sceneforge.png",
    video: "https://pub-f770ddba5aa74582b565fd4599315cd5.r2.dev/scene.webm",
    chips: [],
  },
  {
    id: "assets", name: "SpriteForge",
    promise: "Describe a character. Get an animated sprite.",
    sub: "The agent generates every frame for idle, walk, attack, and die animations, auto-slices the sprite sheet, and removes backgrounds.",
    img: "assets/products/spriteforge.png",
    video: "https://pub-f770ddba5aa74582b565fd4599315cd5.r2.dev/sprite.webm",
    chips: [],
  },
  {
    id: "map", name: "MapForge",
    promise: "Describe a tower-defense map. Get playable paths.",
    sub: "The agent paints the map and marks the walkable paths. An algorithm then extracts the path graph the engine needs — entry points, forks, and waypoints.",
    img: "assets/products/mapforge.png",
    video: "https://pub-f770ddba5aa74582b565fd4599315cd5.r2.dev/map.webm",
    chips: [],
  },
];

const NAV = [
  { id: "hero", label: "Top" },
  { id: "what", label: "What" },
  { id: "scene", label: "Scene" },
  { id: "assets", label: "Sprites" },
  { id: "map", label: "Maps" },
  { id: "next", label: "Next" },
];

// ---------- helpers ----------
function useInView(threshold = 0.2) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(([e]) => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } }, { threshold });
    io.observe(ref.current);
    return () => io.disconnect();
  }, [threshold]);
  return [ref, seen];
}

function Reveal({ children, delay = 0 }) {
  const [ref, seen] = useInView(0.12);
  return (
    <div ref={ref} style={{
      opacity: seen ? 1 : 0,
      transform: seen ? "translateY(0)" : "translateY(14px)",
      transition: `opacity 700ms ${delay}ms cubic-bezier(.2,.7,.2,1), transform 700ms ${delay}ms cubic-bezier(.2,.7,.2,1)`,
    }}>{children}</div>
  );
}

// ---------- HERO ----------
const DEMO_VIDEO_URL = "https://pub-f770ddba5aa74582b565fd4599315cd5.r2.dev/GameForge_web_1080p.mp4";

function Hero({ onPlayDemo }) {
  const posterRef = React.useRef(null);
  return (
    <section id="hero" className="hero-section">
      <div className="hero-grid">
        <div className="hero-copy">
          <h1 className="hero-title">
            Describe a game.<br/>
            <span className="hero-title-em">AI builds it.</span>
          </h1>
          <p className="hero-sub">
            GameForge is a 2D game maker. You describe a game in one sentence; an
            AI agent generates the art, gameplay code, music, and sound effects,
            runs the build, and recovers from its own errors. The result is a
            playable game in your browser.
          </p>
          <div className="hero-cta-row">
            <a href="#scene" className="btn-ghost">See how it works ↓</a>
          </div>
        </div>

        <div className="hero-demo-wrap">
          <button className="hero-demo" onClick={onPlayDemo} aria-label="Play demo">
            <div className="hero-demo-chrome">
              <div className="hero-demo-dots"><span></span><span></span><span></span></div>
              <div className="hero-demo-url">gameforge / play</div>
              <div className="hero-demo-badge">▶ PLAY</div>
            </div>
            <div className="hero-demo-stage">
              <video
                ref={posterRef}
                className="hero-demo-video"
                src={DEMO_VIDEO_URL}
                muted
                loop
                playsInline
                preload="metadata"
                autoPlay
              />
              <div className="hero-demo-vignette" />
            </div>
          </button>
          <div className="hero-demo-caption">
            <span className="dot" /> Recorded from GameForge — art, code, and audio generated by the agent.
          </div>
        </div>
      </div>
    </section>
  );
}

function VideoLightbox({ open, onClose }) {
  React.useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", onKey);
      document.body.style.overflow = "";
    };
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div className="lightbox" onClick={onClose} role="dialog" aria-modal="true">
      <button className="lightbox-close" onClick={onClose} aria-label="Close">×</button>
      <div className="lightbox-frame" onClick={(e) => e.stopPropagation()}>
        <video
          className="lightbox-video"
          src={DEMO_VIDEO_URL}
          controls
          autoPlay
          playsInline
        />
      </div>
    </div>
  );
}

// ---------- WHAT IT IS ----------
function WhatItIs() {
  return (
    <section id="what" className="what-section">
      <div className="container">
        <h2 className="h2">An agent on the left. A live game on the right.</h2>
        <p className="lede">You chat with the agent on the left, and the game runs on the right. The agent plans the build, calls tools to generate art, code, and audio, runs the engine, and debugs itself when something breaks.</p>
        <Reveal>
          <div className="what-shot">
            <img src="assets/products/workspace.png" alt="GameForge workspace — chat on the left, live game preview on the right" />
            <div className="forge-stage-shine" />
          </div>
        </Reveal>
      </div>
    </section>
  );
}

// ---------- FORGE SECTION ----------
function ForgeSection({ forge, dark }) {
  return (
    <section id={forge.id} className={`forge-section ${dark ? "is-dark" : "is-shell"}`}>
      <div className="container">
        <div className="forge-head">
          <div>
            <div className="forge-name">{forge.name}</div>
            <h2 className="h2 quoted">“{forge.promise}”</h2>
            <p className="lede">{forge.sub}</p>
          </div>
        </div>

        <Reveal>
          <div className="forge-stage">
            <div className="forge-stage-frame">
              {forge.video ? (
                <video
                  className="forge-media"
                  src={forge.video}
                  poster={forge.img}
                  autoPlay
                  loop
                  muted
                  playsInline
                  preload="metadata"
                />
              ) : (
                <img src={forge.img} alt={forge.name} className="forge-media" />
              )}
              <div className="forge-stage-shine" />
            </div>
          </div>
        </Reveal>
      </div>
    </section>
  );
}

// ---------- COMING SOON ----------
function Next() {
  return (
    <section id="next" className="next-section">
      <div className="container">
        <div className="next-card">
          <div>
            <div className="forge-name dim">UIForge — Coming next</div>
            <h2 className="h2 quoted">“Buttons, panels, HUDs — styled to match the game.”</h2>
            <p className="lede">Once a game has an art style, its UI should match. The same agent loop, generating buttons, panels, and HUDs that fit the game's look.</p>
          </div>
          <div className="next-status">
            <div className="next-status-dot" />
            <div>
              <div className="next-status-k">STATUS</div>
              <div className="next-status-v">In development</div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ---------- NAV ----------
function SideNav() {
  const [active, setActive] = useState("hero");
  useEffect(() => {
    const ids = NAV.map(n => n.id);
    const onScroll = () => {
      let cur = "hero";
      for (const id of ids) {
        const el = document.getElementById(id);
        if (!el) continue;
        if (el.getBoundingClientRect().top < window.innerHeight * 0.4) cur = id;
      }
      setActive(cur);
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return (
    <nav className="sidenav" aria-label="Sections">
      {NAV.map(n => (
        <a key={n.id} href={`#${n.id}`} className={`sidenav-item ${active === n.id ? "is-active" : ""}`}>
          <span className="sidenav-dot" />
          <span className="sidenav-label">{n.label}</span>
        </a>
      ))}
    </nav>
  );
}

function Topbar() {
  return (
    <header className="topbar">
      <div className="topbar-l">
        <div className="brand">
          <div className="brand-mark"><span className="brand-mark-fg">GF</span></div>
          <div className="brand-text">
            <div className="brand-name">GameForge</div>
            <div className="brand-tag">Built by Jay · 2026</div>
          </div>
        </div>
      </div>

    </header>
  );
}

function FooterBar() {
  return (
    <footer className="foot">
      <div className="container foot-inner">
        <div className="foot-l">
          <div className="brand">
            <div className="brand-mark"><span className="brand-mark-fg">GF</span></div>
            <div>
              <div className="brand-name">GameForge</div>
              <div className="brand-tag">An AI agent that builds 2D games.</div>
            </div>
          </div>
        </div>
        <div className="foot-r">
          <span>Built by Jay · 2026</span>
        </div>
      </div>
    </footer>
  );
}

function Tweaks({ tweaks, setTweak }) {
  if (!window.TweaksPanel) return null;
  const TP = window.TweaksPanel, TS = window.TweakSection, TR = window.TweakRadio;
  return (
    <TP title="Tweaks">
      <TS title="Theme">
        <TR label="Accent color" value={tweaks.accent} onChange={(v) => setTweak("accent", v)}
          options={[{value:"green",label:"Green"},{value:"violet",label:"Violet"},{value:"orange",label:"Orange"},{value:"magenta",label:"Magenta"}]} />
      </TS>
      <TS title="Type">
        <TR label="Font scheme" value={tweaks.fontScheme} onChange={(v) => setTweak("fontScheme", v)}
          options={[{value:"pixel-mix",label:"Pixel mix"},{value:"all-sans",label:"All sans"},{value:"all-serif",label:"All serif"}]} />
      </TS>
    </TP>
  );
}

function App() {
  const [demoOpen, setDemoOpen] = useState(false);
  const [tweaks, setTweaksState] = window.useTweaks
    ? window.useTweaks(TWEAK_DEFAULTS)
    : useState(TWEAK_DEFAULTS);
  const setTweak = (k, v) => typeof k === "string" ? setTweaksState({ [k]: v }) : setTweaksState(k);

  useEffect(() => {
    const a = ACCENTS[tweaks.accent] || ACCENTS.green;
    const f = FONT_SCHEMES[tweaks.fontScheme] || FONT_SCHEMES["pixel-mix"];
    const r = document.documentElement;
    r.style.setProperty("--accent", a.hex);
    r.style.setProperty("--accent-glow", a.glow);
    r.style.setProperty("--accent-ink", a.ink);
    r.style.setProperty("--font-display", f.display);
    r.style.setProperty("--font-body", f.body);
    r.style.setProperty("--font-mono", f.mono);
    r.style.setProperty("--font-pixel", f.pixel);
  }, [tweaks.accent, tweaks.fontScheme]);

  return (
    <>
      <Topbar />
      <SideNav />
      <main>
        <Hero onPlayDemo={() => setDemoOpen(true)} />
        <WhatItIs />
        {FORGES.map((f, i) => <ForgeSection key={f.id} forge={f} dark={i % 2 === 0} />)}
        <Next />
      </main>
      <FooterBar />
      <Tweaks tweaks={tweaks} setTweak={setTweak} />
      <VideoLightbox open={demoOpen} onClose={() => setDemoOpen(false)} />
    </>
  );
}

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