// demo-server.jsx -- SERVER MODE: real the ClipGrid engine processing.
//
// When demo-server/server.js is running on localhost:7421 the user uploads a
// real video file, the ClipGrid engine processes it, and the actual scrolling-grid output
// plays back here. ProgressBar is shared with BROWSER MODE (demo.jsx).
//
// Extracted from demo.jsx. Loaded as a Babel <script> BEFORE demo.jsx; exposes
// window.ClipGridServerDemo and window.ClipGridProgressBar.
(function () {
  const DEMO_SERVER = "http://localhost:7421";
  const POLL_MS     = 600;

function ServerDemo() {
  const [phase,      setPhase]      = React.useState("idle");      // idle|uploading|processing|done|error
  const [progress,   setProgress]   = React.useState(0);
  const [phaseLabel, setPhaseLabel] = React.useState("");
  const [eta,        setEta]        = React.useState("--:--:--");
  const [outputUrl,  setOutputUrl]  = React.useState(null);
  const [filename,   setFilename]   = React.useState(null);
  const [error,      setError]      = React.useState(null);
  const [dragOver,   setDragOver]   = React.useState(false);

  const fileInputRef = React.useRef(null);
  const pollRef      = React.useRef(null);

  // Poll /status until done or failed
  function startPolling(id) {
    pollRef.current = setInterval(async () => {
      try {
        const r = await fetch(DEMO_SERVER + "/status/" + id);
        const d = await r.json();
        if (d.status === "running") {
          setProgress(d.progress || 0);
          setPhaseLabel(d.phase || "Processing…");
          setEta(d.eta || "--:--:--");
        } else if (d.status === "done") {
          clearInterval(pollRef.current);
          setProgress(100);
          setPhaseLabel("Done");
          setOutputUrl(DEMO_SERVER + "/output/" + id);
          setPhase("done");
        } else if (d.status === "failed") {
          clearInterval(pollRef.current);
          setError(d.error || "ClipGrid failed. Check the server console.");
          setPhase("error");
        }
      } catch (e) {
        clearInterval(pollRef.current);
        setError("Lost connection to the demo server.");
        setPhase("error");
      }
    }, POLL_MS);
  }

  React.useEffect(() => () => clearInterval(pollRef.current), []);

  async function handleFile(file) {
    if (!file) return;
    setFilename(file.name);
    setError(null);
    setOutputUrl(null);
    setProgress(0);
    setPhaseLabel("Uploading…");
    setPhase("uploading");

    const form = new FormData();
    form.append("video", file);

    try {
      const r = await fetch(DEMO_SERVER + "/process", { method: "POST", body: form });
      if (!r.ok) {
        const d = await r.json().catch(() => ({}));
        throw new Error(d.error || "Server error " + r.status);
      }
      const { jobId } = await r.json();
      setPhase("processing");
      setPhaseLabel("Starting ClipGrid…");
      startPolling(jobId);
    } catch (e) {
      setError(e.message);
      setPhase("error");
    }
  }

  function onDrop(e) {
    e.preventDefault(); setDragOver(false);
    if (phase !== "idle" && phase !== "error" && phase !== "done") return;
    const file = [...(e.dataTransfer.files || [])].find((f) => f.type.startsWith("video/")) || e.dataTransfer.files[0];
    if (file) handleFile(file);
  }

  function reset() {
    clearInterval(pollRef.current);
    setPhase("idle"); setProgress(0); setPhaseLabel(""); setEta("--:--:--");
    setOutputUrl(null); setFilename(null); setError(null);
  }

  return (
    <div className="tf-stage">

      {/* LEFT — drop zone / status */}
      <div
        className={"drop" + (dragOver ? " is-over" : "")}
        onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
        onDragLeave={() => setDragOver(false)}
        onDrop={onDrop}
      >
        <div className="row between center">
          <span className="kicker">Input</span>
          <span className="kicker" style={{ color: "var(--accent-deep)" }}>
            <span style={{ display: "inline-block", width: 6, height: 6, borderRadius: "50%", background: "var(--accent)", marginRight: 8, verticalAlign: "middle" }} />
            Local · nothing uploaded
          </span>
        </div>

        {phase === "idle" && (
          <div className="col gap-4 fill" style={{ justifyContent: "center", paddingBlock: 18 }}>
            <h3 style={{ fontSize: 30, lineHeight: 1.1 }}>Drop your video here.</h3>
            <p className="muted" style={{ maxWidth: "38ch" }}>
              The local demo server is running.{" "}
              <span className="mono" style={{ fontSize: 14 }}>the ClipGrid engine</span> will process your clip and return
              the actual scrolling grid thumbnail — the same output the desktop app produces.
            </p>
            <div className="row gap-3" style={{ marginTop: 8, flexWrap: "wrap" }}>
              <button className="btn" onClick={() => fileInputRef.current.click()}>Choose file</button>
            </div>
            <input
              ref={fileInputRef} type="file" accept="video/*" style={{ display: "none" }}
              onChange={(e) => e.target.files[0] && handleFile(e.target.files[0])}
            />
            <p className="mono" style={{ fontSize: 10, color: "var(--ink-mute)", letterSpacing: ".1em", marginTop: 4 }}>
              MP4 · MOV · MKV · WEBM · AVI — nothing leaves your machine
            </p>
          </div>
        )}

        {phase === "uploading" && (
          <div className="col gap-3 fill" style={{ justifyContent: "center" }}>
            <div className="mono" style={{ fontSize: 11, color: "var(--ink-mute)", letterSpacing: ".14em" }}>UPLOADING TO LOCAL SERVER…</div>
            <ProgressBar indeterminate />
            <p className="muted" style={{ fontSize: 14 }}>{filename}</p>
          </div>
        )}

        {phase === "processing" && (
          <div className="col gap-3 fill" style={{ justifyContent: "center" }}>
            <div className="row between center" style={{ flexWrap: "wrap", gap: 6 }}>
              <div className="mono" style={{ fontSize: 11, color: "var(--ink-mute)", letterSpacing: ".14em" }}>
                {phaseLabel.toUpperCase()}
              </div>
              <div className="mono" style={{ fontSize: 11, color: "var(--ink-mute)" }}>{eta} remaining</div>
            </div>
            <ProgressBar progress={progress} />
            <div className="row between center">
              <p className="muted" style={{ fontSize: 13, maxWidth: "30ch", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                {filename}
              </p>
              <span className="mono" style={{ fontSize: 11, color: "var(--accent-deep)" }}>
                {Math.round(progress)}%
              </span>
            </div>
            <p className="muted" style={{ fontSize: 13, marginTop: 4 }}>
              ClipGrid is building a thumbnail grid sized to your clip and display, then encoding the output. Time varies by clip length and whether CUDA is available.
            </p>
          </div>
        )}

        {phase === "done" && (
          <div className="col gap-3 fill">
            <div className="row between" style={{ gap: 8 }}>
              <div>
                <div className="mono" style={{ fontSize: 11, color: "var(--ink-mute)", letterSpacing: ".12em" }}>OUTPUT READY</div>
                <div className="serif" style={{ fontSize: 22, lineHeight: 1.2, marginTop: 4, maxWidth: "28ch", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {filename}
                </div>
              </div>
              <button className="btn ghost" style={{ fontSize: 11, padding: "8px 12px", alignSelf: "flex-start" }} onClick={reset}>
                New file
              </button>
            </div>
            <p className="muted" style={{ fontSize: 14 }}>
              That's the real ClipGrid output — a scrolling grid of evenly-spaced frames from your source, encoded with translate continuity for a seamless loop.
            </p>
            <a href={outputUrl} download="clipgrid-output.mp4" className="btn ghost" style={{ textAlign: "center" }}>
              Download output ↓
            </a>
          </div>
        )}

        {phase === "error" && (
          <div className="col gap-3 fill" style={{ justifyContent: "center" }}>
            <div className="mono" style={{ fontSize: 11, color: "#c0392b", letterSpacing: ".14em" }}>ERROR</div>
            <p style={{ fontSize: 15 }}>{error}</p>
            <button className="btn ghost" onClick={reset}>Try again</button>
          </div>
        )}
      </div>

      {/* RIGHT — output video / animated placeholder */}
      <div className="col gap-4" style={{ justifyContent: "flex-start" }}>
        <div className="row between center">
          <span className="kicker">Output preview</span>
          <span className="kicker" style={{ color: phase === "done" ? "var(--accent-deep)" : "var(--ink-mute)" }}>
            {phase === "done" ? "● Real ClipGrid output" : "ClipGrid · scrolling grid"}
          </span>
        </div>

        <div className="thumbnail-tile">
          {outputUrl ? (
            <>
              <span className="badge live">● Live</span>
              <video
                src={outputUrl} autoPlay loop muted playsInline
                style={{ width: "100%", height: "100%", objectFit: "contain", display: "block", background: "#000" }}
              />
            </>
          ) : (
            <GridPlaceholder phase={phase} progress={progress} />
          )}
        </div>

        <div className="col gap-2">
          <div className="row between">
            <span className="mono" style={{ fontSize: 11, color: "var(--ink-mute)", letterSpacing: ".12em" }}>EXPORT FORMATS</span>
          </div>
          <div className="row gap-2" style={{ flexWrap: "wrap" }}>
            {["MP4", "AVI", "WebM"].map((f) => (
              <span key={f} className="mono" style={{ fontSize: 11, padding: "6px 10px", border: "1px solid var(--rule)", borderRadius: 8, color: "var(--ink-soft)" }}>{f}</span>
            ))}
          </div>
          <p className="muted" style={{ fontSize: 13, marginTop: 6 }}>
            The demo server outputs MP4 via NVENC H.264. The desktop app lets you set the output format, codec, and grid dimensions through named settings templates.
          </p>
        </div>
      </div>
    </div>
  );
}

// Animated progress bar — solid fill or indeterminate sweep
function ProgressBar({ progress, indeterminate }) {
  if (indeterminate) {
    return (
      <div style={{ height: 4, background: "var(--rule)", borderRadius: 2, overflow: "hidden" }}>
        <div style={{ height: "100%", width: "45%", background: "var(--accent)", animation: "tfBar 1.2s ease-in-out infinite" }} />
      </div>
    );
  }
  return (
    <div style={{ height: 4, background: "var(--rule)", borderRadius: 2, overflow: "hidden" }}>
      <div style={{ height: "100%", width: (progress || 0) + "%", background: "var(--accent)", borderRadius: 2, transition: "width 400ms ease" }} />
    </div>
  );
}

// Placeholder that animates a ClipGrid-like cell grid while processing
function GridPlaceholder({ phase, progress }) {
  const COLS = 10, ROWS = 6, cells = COLS * ROWS;
  const filled = phase === "processing" ? Math.round((progress / 100) * cells) : 0;
  return (
    <div style={{ position: "absolute", inset: 0, background: "#0a0a0a", display: "grid", gridTemplateColumns: "repeat(" + COLS + ", 1fr)", gap: 1, padding: 1 }}>
      {Array.from({ length: cells }).map((_, i) => {
        const t = i / (cells - 1);
        return (
          <div key={i} style={{
            background: i < filled ? ("hsl(" + (210 + t * 30) + ",55%," + (10 + t * 10) + "%)") : "#111",
            transition: "background 300ms ease",
            borderRadius: 1,
          }} />
        );
      })}
      {phase !== "processing" && phase !== "done" && (
        <div style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center", color: "#555", fontFamily: "var(--ff-mono)", fontSize: 11, letterSpacing: ".12em" }}>
          {phase === "idle" ? "AWAITING SOURCE" : "RENDERING…"}
        </div>
      )}
    </div>
  );
}

  window.ClipGridServerDemo  = ServerDemo;
  window.ClipGridProgressBar = ProgressBar;
})();
