// output-screen.jsx — final video preview, timeline, downloads.

const SCENES = [
  { id: 1, label: "Cold open · Cape Canaveral", duration: 5.2, color: "oklch(0.45 0.12 60)" },
  { id: 2, label: "Voyager assembly",          duration: 7.4, color: "oklch(0.38 0.08 80)" },
  { id: 3, label: "Golden record macro",       duration: 6.0, color: "oklch(0.52 0.10 50)" },
  { id: 4, label: "Launch sequence",           duration: 8.1, color: "oklch(0.40 0.14 30)" },
  { id: 5, label: "Deep space transit",        duration: 9.6, color: "oklch(0.28 0.08 280)" },
  { id: 6, label: "Heliopause graphic",        duration: 5.4, color: "oklch(0.45 0.10 240)" },
  { id: 7, label: "Modern radio dish",         duration: 6.8, color: "oklch(0.32 0.06 200)" },
  { id: 8, label: "Voyager — still pinging",   duration: 7.0, color: "oklch(0.50 0.14 70)" },
  { id: 9, label: "Tag — open question",       duration: 4.5, color: "oklch(0.22 0.04 60)" },
];

const TOTAL = SCENES.reduce((a, s) => a + s.duration, 0);

function fmtSec(s) {
  const m = Math.floor(s / 60);
  const r = Math.floor(s % 60);
  return `${m}:${String(r).padStart(2,"0")}`;
}

function OutputScreen({ state, job, onRestart, onUpdateJob, uiLang = "vi" }) {
  const videoUrl = job?.videoUrl || null;
  return (
    <div style={{
      display: "grid",
      gridTemplateColumns: "1fr 380px",
      gap: 18,
      padding: "0 28px 28px",
      maxWidth: 1600,
      margin: "0 auto",
    }}>
      <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
        <VideoPlayer videoUrl={videoUrl} uiLang={uiLang}/>
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
        <SummaryCard state={state} job={job} uiLang={uiLang}/>
        <SubtitleStyleCard state={state} job={job} onUpdateJob={onUpdateJob} uiLang={uiLang}/>
        <DownloadsCard state={state} job={job} uiLang={uiLang}/>
        <ActionsCard onRestart={onRestart} uiLang={uiLang}/>
      </div>
    </div>
  );
}

function VideoPlayer({ videoUrl, uiLang }) {
  return (
    <section style={{
      background: "var(--bg-1)",
      border: "1px solid var(--line)",
      borderRadius: "var(--radius-lg)",
      overflow: "hidden",
    }}>
      <div style={{ position: "relative", aspectRatio: "16 / 9", background: "#000" }}>
        {videoUrl ? (
          <video
            src={videoUrl}
            controls
            autoPlay
            style={{ width: "100%", height: "100%", display: "block", background: "#000" }}
          />
        ) : (
          <div style={{
            position: "absolute", inset: 0,
            display: "flex", alignItems: "center", justifyContent: "center",
            color: "var(--fg-3)", fontSize: 13,
          }} className="mono">{uiLang === "en" ? "Video not ready" : "Video chưa sẵn sàng"}</div>
        )}
      </div>
    </section>
  );
}

function Player({ t, setT, playing, setPlaying, scene, sceneStart, sub }) {
  // dynamic caption — pick a phrase based on scene
  const CAPTIONS = {
    1: "The year is nineteen seventy-seven.",
    2: "NASA assembles two spacecraft.",
    3: "Each carries a golden record.",
    4: "Cape Canaveral. Launch.",
    5: "Voyager 1 and Voyager 2.",
    6: "They are bottle messages.",
    7: "Hurled into the dark.",
    8: "Forty-seven years later, still transmitting.",
    9: "What did they hear back?",
  };
  const caption = CAPTIONS[scene.id] || "";
  const words = caption.split(" ");
  const local = t - sceneStart;
  const wordIdx = Math.min(words.length - 1, Math.floor((local / scene.duration) * words.length));

  return (
    <section style={{
      background: "var(--bg-1)",
      border: "1px solid var(--line)",
      borderRadius: "var(--radius-lg)",
      overflow: "hidden",
    }}>
      {/* viewer */}
      <div style={{
        position: "relative",
        aspectRatio: "16 / 9",
        background: "#000",
        overflow: "hidden",
      }}>
        <SceneCanvas scene={scene} t={t} localT={local}/>

        {/* subtitle */}
        <div style={{
          position: "absolute",
          left: "50%",
          transform: "translateX(-50%)",
          [sub.position === "top" ? "top" : sub.position === "middle" ? "top" : "bottom"]: sub.position === "middle" ? "50%" : 36,
          marginTop: sub.position === "middle" ? "-1em" : 0,
          maxWidth: "90%",
          padding: "8px 16px",
          background: hexToRgba(sub.back),
          borderRadius: 4,
          fontFamily: sub.font === "Arial" ? "Arial, Helvetica, sans-serif" :
                      sub.font === "Geist" ? "Geist, sans-serif" :
                      sub.font === "Inter Tight" ? "'Inter Tight', sans-serif" :
                      sub.font === "Mono" ? "var(--font-mono)" : "Arial",
          fontSize: sub.size * 0.42,
          fontWeight: 700,
          letterSpacing: "0.01em",
          textAlign: "center",
          color: hexToRgba(sub.text),
          textShadow: `
            -1.5px -1.5px 0 ${hexToRgba(sub.outline)},
            1.5px -1.5px 0 ${hexToRgba(sub.outline)},
            -1.5px 1.5px 0 ${hexToRgba(sub.outline)},
            1.5px 1.5px 0 ${hexToRgba(sub.outline)}`,
          whiteSpace: "nowrap",
          transition: "opacity .2s",
          lineHeight: 1.2,
        }}>
          {words.map((w, i) => (
            <span key={i} style={{
              display: "inline-block",
              padding: i === wordIdx ? "2px 8px" : "0",
              margin: "0 3px",
              background: i === wordIdx ? hexToRgba(sub.highlight) : "transparent",
              color: i === wordIdx ? "#0a0a0a" : "inherit",
              borderRadius: 3,
              textShadow: i === wordIdx ? "none" : undefined,
              transition: "background .12s",
            }}>{w}</span>
          ))}
        </div>

        {/* watermark / safe area markers */}
        {[[0,0,1,1],[1,0,-1,1],[0,1,1,-1],[1,1,-1,-1]].map(([x,y,dx,dy], i) => (
          <svg key={i} width="20" height="20"
            style={{ position: "absolute", [x===0?"left":"right"]: 12, [y===0?"top":"bottom"]: 12, opacity: 0.55 }}>
            <path d={`M0 ${y===0?2:18} L0 0 L${x===0?18:2} 0`} fill="none" stroke="white" strokeWidth="1.5"
              transform={`scale(${dx} ${dy}) translate(${dx<0?-20:0}, ${dy<0?-20:0})`}/>
          </svg>
        ))}
      </div>

      {/* transport */}
      <div style={{
        display: "flex", alignItems: "center", gap: 14,
        padding: "10px 14px",
        background: "var(--bg-0)",
        borderTop: "1px solid var(--line)",
      }}>
        <button onClick={() => setT(Math.max(0, t - 5))}
          style={{ color: "var(--fg-1)", padding: 6 }} title="Back 5s">
          <svg width="18" height="18" viewBox="0 0 18 18"><path d="M9 3 V 1 L5 4 L9 7 V 5 a4 4 0 1 1 -4 4" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </button>
        <button onClick={() => setPlaying(!playing)}
          style={{
            width: 38, height: 38, borderRadius: 999,
            background: "var(--accent)", color: "var(--accent-fg)",
            display: "flex", alignItems: "center", justifyContent: "center",
          }}>
          {playing
            ? <svg width="14" height="14" viewBox="0 0 14 14"><rect x="3" y="2" width="3" height="10" fill="currentColor"/><rect x="8" y="2" width="3" height="10" fill="currentColor"/></svg>
            : <svg width="14" height="14" viewBox="0 0 14 14"><path d="M3 2 L12 7 L3 12 Z" fill="currentColor"/></svg>}
        </button>
        <button onClick={() => setT(Math.min(TOTAL, t + 5))}
          style={{ color: "var(--fg-1)", padding: 6 }} title="Forward 5s">
          <svg width="18" height="18" viewBox="0 0 18 18"><path d="M9 3 V 1 L13 4 L9 7 V 5 a4 4 0 1 0 4 4" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </button>

        <div className="mono tabular" style={{ fontSize: 12, color: "var(--fg-1)" }}>
          {fmtSec(t)}<span style={{ color: "var(--fg-4)" }}> / {fmtSec(TOTAL)}</span>
        </div>

        {/* scrubber */}
        <div
          style={{ flex: 1, height: 22, display: "flex", alignItems: "center", cursor: "pointer" }}
          onClick={(e) => {
            const rect = e.currentTarget.getBoundingClientRect();
            const p = (e.clientX - rect.left) / rect.width;
            setT(p * TOTAL);
          }}
        >
          <div style={{ position: "relative", height: 4, background: "var(--bg-3)", borderRadius: 999, width: "100%" }}>
            <div style={{
              position: "absolute", left: 0, top: 0, bottom: 0,
              width: `${(t / TOTAL) * 100}%`,
              background: "var(--accent)",
              borderRadius: 999,
            }}/>
            <div style={{
              position: "absolute",
              left: `${(t / TOTAL) * 100}%`,
              top: "50%",
              width: 12, height: 12,
              transform: "translate(-50%, -50%)",
              background: "var(--fg-0)",
              borderRadius: 999,
              boxShadow: "0 0 0 3px var(--accent-soft)",
            }}/>
          </div>
        </div>

        <div style={{ display: "flex", gap: 8, fontSize: 11 }} className="mono">
          <span style={{ color: "var(--fg-3)" }}>1×</span>
          <span style={{ color: "var(--fg-3)" }}>·</span>
          <span style={{ color: "var(--fg-3)" }}>{state_resolution_label()}</span>
        </div>
      </div>
    </section>
  );
}

function state_resolution_label() { return "1080p"; }

function SceneCanvas({ scene, t, localT }) {
  // procedurally drawn "scene" using gradients + simple shapes.
  // ken-burns zoom on the layer
  const zoom = 1 + (localT / scene.duration) * 0.08;
  return (
    <div style={{
      position: "absolute", inset: 0,
      transform: `scale(${zoom})`,
      transformOrigin: "50% 55%",
      transition: "transform .05s linear",
      background: `radial-gradient(ellipse at 30% 40%, ${scene.color} 0%, transparent 55%),
                   radial-gradient(ellipse at 75% 70%, oklch(0.18 0.04 280) 0%, transparent 60%),
                   linear-gradient(180deg, oklch(0.10 0.005 60), #000)`,
    }}>
      {/* scene-specific accents */}
      {(scene.id === 1 || scene.id === 4) && (
        // launch — vertical light pillar
        <div style={{
          position: "absolute", left: "55%", top: 0, bottom: "20%", width: 6,
          background: "linear-gradient(180deg, oklch(0.95 0.18 70), oklch(0.6 0.15 30), transparent)",
          filter: "blur(2px)",
          opacity: 0.8,
        }}/>
      )}
      {(scene.id === 2 || scene.id === 3 || scene.id === 6) && (
        // grid / schematic
        <svg style={{ position: "absolute", inset: 0, width: "100%", height: "100%", opacity: 0.4 }}>
          <defs>
            <pattern id="g" x="0" y="0" width="32" height="32" patternUnits="userSpaceOnUse">
              <path d="M32 0 L0 0 L0 32" fill="none" stroke="oklch(0.55 0.08 70)" strokeWidth="0.5"/>
            </pattern>
          </defs>
          <rect width="100%" height="100%" fill="url(#g)"/>
        </svg>
      )}
      {(scene.id === 5 || scene.id === 8) && (
        // deep space — stars
        <svg style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }}>
          {Array.from({ length: 80 }).map((_, i) => {
            const x = ((i * 37) % 100);
            const y = ((i * 71) % 100);
            const r = (i % 3 === 0) ? 1.2 : 0.5;
            return <circle key={i} cx={`${x}%`} cy={`${y}%`} r={r} fill="white" opacity={r === 1.2 ? 0.9 : 0.5}/>;
          })}
          {scene.id === 8 && (
            <circle cx="50%" cy="50%" r="3" fill="oklch(0.85 0.18 70)">
              <animate attributeName="r" values="3;6;3" dur="2.4s" repeatCount="indefinite"/>
              <animate attributeName="opacity" values="1;0.4;1" dur="2.4s" repeatCount="indefinite"/>
            </circle>
          )}
        </svg>
      )}
      {scene.id === 7 && (
        // radio dish silhouette
        <svg viewBox="0 0 320 180" style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }}>
          <path d="M100 140 L160 60 L220 140 Z" fill="oklch(0.20 0.02 60)" opacity="0.85"/>
          <circle cx="160" cy="100" r="6" fill="oklch(0.6 0.12 70)"/>
        </svg>
      )}

      {/* film grain */}
      <div style={{
        position: "absolute", inset: 0,
        backgroundImage: "radial-gradient(rgba(255,255,255,0.06) 1px, transparent 1px)",
        backgroundSize: "3px 3px",
        mixBlendMode: "overlay",
      }}/>
    </div>
  );
}

function Timeline({ t, setT, scenes }) {
  return (
    <section style={{
      background: "var(--bg-1)",
      border: "1px solid var(--line)",
      borderRadius: "var(--radius-lg)",
      overflow: "hidden",
    }}>
      <header style={{
        padding: "8px 14px",
        borderBottom: "1px solid var(--line)",
        display: "flex", alignItems: "center", justifyContent: "space-between",
      }}>
        <span className="mono" style={{ fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)" }}>Timeline</span>
        <div style={{ display: "flex", gap: 14, fontSize: 11, color: "var(--fg-3)" }} className="mono">
          <span>{scenes.length} scenes</span>
          <span>{Math.round(TOTAL)}s</span>
          <span>24 fps</span>
        </div>
      </header>

      {/* time ruler */}
      <div style={{ position: "relative", height: 18, background: "var(--bg-0)", borderBottom: "1px solid var(--line)" }}>
        {Array.from({ length: Math.ceil(TOTAL / 5) + 1 }).map((_, i) => {
          const x = (i * 5 / TOTAL) * 100;
          return (
            <div key={i} style={{ position: "absolute", left: `${x}%`, top: 0, bottom: 0, fontSize: 9.5, color: "var(--fg-4)", padding: "3px 4px" }} className="mono">
              {fmtSec(i * 5)}
            </div>
          );
        })}
        {/* playhead in ruler */}
        <div style={{
          position: "absolute", left: `${(t / TOTAL) * 100}%`,
          top: 0, bottom: -200, width: 1.5,
          background: "var(--accent)",
          boxShadow: "0 0 8px var(--accent)",
          pointerEvents: "none",
        }}/>
      </div>

      {/* video track */}
      <Track label="V1" scenes={scenes} onSeek={setT}>
        {(s, x, w) => (
          <div style={{
            position: "absolute", left: `${x}%`, width: `${w}%`,
            top: 4, bottom: 4,
            background: `linear-gradient(135deg, ${s.color}, oklch(0.15 0.02 60))`,
            borderRadius: 3,
            padding: "4px 6px",
            fontSize: 10.5,
            color: "white",
            overflow: "hidden",
            whiteSpace: "nowrap",
            textOverflow: "ellipsis",
            display: "flex", alignItems: "center", gap: 4,
            border: "1px solid rgba(255,255,255,0.08)",
          }}>
            <span style={{ opacity: 0.7, fontSize: 9 }} className="mono">{String(s.id).padStart(2, "0")}</span>
            <span>{s.label}</span>
          </div>
        )}
      </Track>

      {/* audio track */}
      <Track label="A1" scenes={scenes} compact onSeek={setT}>
        {(s, x, w) => (
          <div style={{
            position: "absolute", left: `${x}%`, width: `${w}%`,
            top: 4, bottom: 4,
            background: "oklch(0.25 0.04 200 / 0.7)",
            borderRadius: 3,
            display: "flex", alignItems: "center",
            gap: 1,
            padding: "0 4px",
            overflow: "hidden",
          }}>
            {Array.from({ length: Math.floor(w * 1.6) }).map((_, i) => {
              const h = (Math.sin(i * 0.6 + s.id) * 0.3 + Math.sin(i * 1.3) * 0.2 + 0.5) * 80 + 10;
              return <div key={i} style={{ flex: 1, height: `${h}%`, background: "oklch(0.7 0.12 200)", borderRadius: 0.5 }}/>;
            })}
          </div>
        )}
      </Track>

      {/* subtitle track */}
      <Track label="S1" scenes={scenes} compact onSeek={setT} last>
        {(s, x, w) => (
          <div style={{
            position: "absolute", left: `${x}%`, width: `${w}%`,
            top: 4, bottom: 4,
            background: "oklch(0.78 0.16 70 / 0.18)",
            border: "1px solid oklch(0.78 0.16 70 / 0.5)",
            borderRadius: 3,
            display: "flex", alignItems: "center",
            padding: "0 6px",
            fontSize: 10,
            color: "var(--accent)",
            overflow: "hidden",
          }} className="mono">CC · {s.id}</div>
        )}
      </Track>
    </section>
  );
}

function Track({ label, scenes, children, compact, last, onSeek }) {
  return (
    <div style={{
      display: "flex",
      borderBottom: last ? "none" : "1px solid var(--line)",
      background: "var(--bg-1)",
    }}>
      <div style={{
        width: 42, flexShrink: 0,
        borderRight: "1px solid var(--line)",
        display: "flex", alignItems: "center", justifyContent: "center",
        fontFamily: "var(--font-mono)",
        fontSize: 10, fontWeight: 600,
        color: "var(--fg-2)",
        background: "var(--bg-0)",
      }}>{label}</div>
      <div style={{
        position: "relative", flex: 1,
        height: compact ? 30 : 42,
        cursor: "pointer",
      }}
        onClick={(e) => {
          const r = e.currentTarget.getBoundingClientRect();
          onSeek(((e.clientX - r.left) / r.width) * TOTAL);
        }}
      >
        {(() => {
          let acc = 0;
          return scenes.map((s) => {
            const x = (acc / TOTAL) * 100;
            const w = (s.duration / TOTAL) * 100;
            acc += s.duration;
            return <React.Fragment key={s.id}>{children(s, x, w)}</React.Fragment>;
          });
        })()}
      </div>
    </div>
  );
}

function SummaryCard({ state, job, uiLang }) {
  const jobId = job?.id;
  const stylePreset = STYLE_PRESETS.find(s => s.id === state.settings.style) || {};
  const styleName = translateStylePreset(stylePreset, uiLang).name || state.settings.style;
  const langLabel = LANGUAGES.find(l => l.code === state.settings.language)?.label || state.settings.language;
  const subtitlesVal = state.settings.enableSubtitles !== false 
    ? (uiLang === "en" ? "On" : "Bật") 
    : (uiLang === "en" ? "Off" : "Tắt");

  const fields = uiLang === "en" ? [
    ["Style", styleName],
    ["Language", langLabel],
    ["Aspect", state.settings.aspect],
    ["Subtitles", subtitlesVal],
  ] : [
    ["Phong cách", styleName],
    ["Ngôn ngữ", langLabel === "Vietnamese" ? "Tiếng Việt" : langLabel === "English" ? "Tiếng Anh" : langLabel],
    ["Tỷ lệ", state.settings.aspect],
    ["Phụ đề", subtitlesVal],
  ];

  return (
    <section style={{
      background: "var(--bg-1)",
      border: "1px solid var(--line)",
      borderRadius: "var(--radius-lg)",
      padding: 16,
    }}>
      <div className="mono" style={{ fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)", marginBottom: 12 }}>
        {uiLang === "en" ? "Ready · " : "Sẵn sàng · "}<span style={{ color: "var(--ok)" }}>● {uiLang === "en" ? "delivered" : "đã xuất"}</span>
      </div>
      <div style={{ fontSize: 18, fontWeight: 500, lineHeight: 1.25, marginBottom: 4 }}>
        output.<span style={{ color: "var(--accent)" }}>mp4</span>
      </div>
      <div style={{ fontSize: 12, color: "var(--fg-3)", marginBottom: 14 }} className="mono">
        Job {jobId ? jobId.slice(0, 8) : "—"}
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, fontSize: 12.5 }}>
        {fields.map(([k, v]) => (
          <div key={k}>
            <div style={{ fontSize: 10, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: "0.08em" }} className="mono">{k}</div>
            <div style={{ color: "var(--fg-0)" }}>{v}</div>
          </div>
        ))}
      </div>
    </section>
  );
}

function DownloadsCard({ state, job, uiLang }) {
  const videoUrl = job?.videoUrl || null;
  // Khi user bấm tải, gọi endpoint download-and-purge: BE stream file rồi
  // tự xóa workspace + outputs ngay sau khi response gửi xong.
  const downloadUrl = job?.id ? `/api/jobs/${job.id}/download` : videoUrl;
  const files = videoUrl ? [
    { name: uiLang === "en" ? "Video output" : "Video kết quả", size: "MP4", note: "primary", ext: "mp4", url: downloadUrl },
  ] : [];
  return (
    <section style={{
      background: "var(--bg-1)",
      border: "1px solid var(--line)",
      borderRadius: "var(--radius-lg)",
      padding: 12,
    }}>
      <div className="mono" style={{ fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)", padding: "4px 4px 10px" }}>
        {uiLang === "en" ? "Downloads" : "Tải xuống"}
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
        {files.length === 0 && (
          <div style={{ padding: "10px", fontSize: 12, color: "var(--fg-3)" }} className="mono">
            {uiLang === "en" ? "No output file yet" : "Chưa có file kết quả"}
          </div>
        )}
        {files.map((f) => (
          <a key={f.name}
            href={f.url || "#"}
            download
            style={{
              display: "flex", alignItems: "center", gap: 12,
              padding: "8px 10px",
              borderRadius: "var(--radius)",
              textAlign: "left",
              textDecoration: "none",
              transition: "background .12s",
            }}
            onMouseEnter={(e) => e.currentTarget.style.background = "var(--bg-3)"}
            onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}
          >
            <div style={{
              width: 32, height: 32, borderRadius: 6,
              background: f.note ? "var(--accent)" : "var(--bg-3)",
              color: f.note ? "var(--accent-fg)" : "var(--fg-2)",
              display: "flex", alignItems: "center", justifyContent: "center",
              fontFamily: "var(--font-mono)", fontSize: 9, fontWeight: 700,
              letterSpacing: "0.05em",
              flexShrink: 0,
            }}>{f.ext.toUpperCase()}</div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 13, color: "var(--fg-0)", display: "flex", alignItems: "baseline", gap: 8 }}>
                {f.name}
                {f.note && <span className="mono" style={{ fontSize: 9, color: "var(--accent)", padding: "1px 4px", border: "1px solid var(--accent-line)", borderRadius: 3, letterSpacing: "0.06em", textTransform: "uppercase" }}>{f.note}</span>}
              </div>
              <div className="mono" style={{ fontSize: 11, color: "var(--fg-3)" }}>{f.size}</div>
            </div>
            <svg width="16" height="16" viewBox="0 0 16 16" style={{ color: "var(--fg-2)" }}>
              <path d="M8 2 V11 M4.5 7.5 L8 11 L11.5 7.5" stroke="currentColor" strokeWidth="1.4" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
              <path d="M3 13 H13" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/>
            </svg>
          </a>
        ))}
      </div>
    </section>
  );
}

function ActionsCard({ onRestart, uiLang }) {
  const actions = uiLang === "en" ? [
    { l: "Push to YouTube", note: "Connect channel", icon: "yt" },
    { l: "Open in editor",  note: "Fine-tune scenes", icon: "edit" },
    { l: "Re-render with tweaks", note: "Settings, voice, style", icon: "redo" },
  ] : [
    { l: "Đăng lên YouTube", note: "Kết nối kênh", icon: "yt" },
    { l: "Mở trong trình dựng",  note: "Chỉnh sửa phân cảnh chi tiết", icon: "edit" },
    { l: "Xuất lại với tinh chỉnh", note: "Cấu hình, giọng nói, kiểu dáng", icon: "redo" },
  ];
  return (
    <section style={{
      background: "var(--bg-1)",
      border: "1px solid var(--line)",
      borderRadius: "var(--radius-lg)",
      padding: 12,
      display: "flex", flexDirection: "column", gap: 6,
    }}>
      {actions.map((a) => (
        <button key={a.l}
          style={{
            display: "flex", alignItems: "center", gap: 12,
            padding: "8px 10px",
            borderRadius: "var(--radius)",
            textAlign: "left",
          }}
          onMouseEnter={(e) => e.currentTarget.style.background = "var(--bg-3)"}
          onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}
        >
          <div style={{ width: 28, height: 28, borderRadius: 6, background: "var(--bg-2)",
            display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fg-1)" }}>
            <svg width="14" height="14" viewBox="0 0 16 16">
              {a.icon === "yt" && <path d="M2 4.5 a1.5 1.5 0 0 1 1.5 -1.5 H12.5 a1.5 1.5 0 0 1 1.5 1.5 V11.5 a1.5 1.5 0 0 1 -1.5 1.5 H3.5 a1.5 1.5 0 0 1 -1.5 -1.5 Z M7 6 L10 8 L7 10 Z" fill="currentColor"/>}
              {a.icon === "edit" && <path d="M2 11 L11 2 L14 5 L5 14 H2 Z" stroke="currentColor" strokeWidth="1.3" fill="none" strokeLinejoin="round"/>}
              {a.icon === "redo" && <path d="M13 8 a5 5 0 1 1 -1.8 -3.8 M13 3 V5 H11" stroke="currentColor" strokeWidth="1.4" fill="none" strokeLinecap="round" strokeLinejoin="round"/>}
            </svg>
          </div>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 13, color: "var(--fg-0)" }}>{a.l}</div>
            <div style={{ fontSize: 11, color: "var(--fg-3)" }}>{a.note}</div>
          </div>
        </button>
      ))}
      <div style={{ height: 1, background: "var(--line)", margin: "4px 0" }}/>
      <button onClick={onRestart}
        style={{
          display: "flex", alignItems: "center", gap: 8,
          padding: "10px",
          borderRadius: "var(--radius)",
          color: "var(--fg-2)",
          fontSize: 12.5,
          justifyContent: "center",
        }}
        onMouseEnter={(e) => e.currentTarget.style.background = "var(--bg-3)"}
        onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}
      >
        {uiLang === "en" ? "← Start a new project" : "← Bắt đầu dự án mới"}
      </button>
    </section>
  );
}

function SubtitleStyleCard({ state, job, onUpdateJob, uiLang }) {
  // 'done' if subtitles were burned at render time; otherwise 'idle' → user
  // must opt-in via the CTA below before the styling controls are available.
  const initialPhase = state?.settings?.enableSubtitles ? "done" : "idle";
  const [phase, setPhase] = React.useState(initialPhase);
  const [addError, setAddError] = React.useState(null);
  const [sub, setSub] = React.useState({
    font: "Arial",
    size: 36,
    maxWords: 6,
    position: "bottom",
    marginV: 120,
    color_text: "&H00FFFFFF",
    color_outline: "&H00000000",
    color_back: "&H90000000",
    color_highlight: "&H0000FFFF",
    mode: "capcut", // "capcut" (per-word pill) | "plain" (sentence-only)
  });
  const [loading, setLoading] = React.useState(false);

  const SUBTITLE_MODES = [
    { id: "capcut", label: "CapCut" },
    { id: "plain",  label: "Plain"  },
  ];

  const startAddSubtitles = async () => {
    if (!job?.id) return;
    setAddError(null);
    setPhase("adding");
    try {
      const res = await fetch(`/api/jobs/${job.id}/subtitles/add`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ subtitle_mode: sub.mode }),
      });
      if (!res.ok) {
        const errText = await res.text();
        throw new Error(`API ${res.status}: ${errText}`);
      }
      // Poll status until COMPLETED or FAILED (subtitle pipeline runs in background).
      const maxAttempts = 180; // ~6 min @ 2s
      for (let i = 0; i < maxAttempts; i++) {
        await new Promise(r => setTimeout(r, 2000));
        const r = await fetch(`/api/status/${job.id}`);
        if (!r.ok) throw new Error(`Status ${r.status}`);
        const data = await r.json();
        if (data.status === "COMPLETED") {
          if (data.video_url && onUpdateJob) {
            onUpdateJob({ ...job, videoUrl: data.video_url });
          }
          setPhase("done");
          return;
        }
        if (data.status === "FAILED") {
          throw new Error(data.error || "Subtitle generation failed");
        }
      }
      throw new Error("Timed out waiting for subtitles");
    } catch (e) {
      setAddError(e.message || String(e));
      setPhase("idle");
    }
  };

  const toAssColor = (hex, alpha="00") => {
    const r = hex.slice(1, 3);
    const g = hex.slice(3, 5);
    const b = hex.slice(5, 7);
    return `&H${alpha}${b}${g}${r}`;
  };

  const assToRgba = (ass) => {
    if (!ass || ass.length < 10) return "transparent";
    const a = (255 - parseInt(ass.slice(2, 4), 16)) / 255;
    const b = parseInt(ass.slice(4, 6), 16);
    const g = parseInt(ass.slice(6, 8), 16);
    const r = parseInt(ass.slice(8, 10), 16);
    return `rgba(${r}, ${g}, ${b}, ${a})`;
  };

  const toHex = (ass) => {
    if (!ass || ass.length < 10) return "#ffffff";
    const b = ass.slice(4, 6);
    const g = ass.slice(6, 8);
    const r = ass.slice(8, 10);
    return `#${r}${g}${b}`;
  };

  const handleUpdate = async () => {
    if (!job?.id) return;
    setLoading(true);
    try {
      const payload = {
        font_name: sub.font === "Mono" ? "Geist Mono" : sub.font === "Inter Tight" ? "Inter Tight" : sub.font,
        font_size: sub.size,
        max_words_per_line: sub.maxWords,
        position: sub.position,
        margin_v: sub.marginV,
        color_text: sub.color_text,
        color_outline: sub.color_outline,
        color_back: sub.color_back,
        color_highlight: sub.color_highlight,
        subtitle_mode: sub.mode,
      };
      const res = await fetch(`/api/jobs/${job.id}/subtitles/style`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload)
      });
      if (!res.ok) throw new Error("Failed to update");
      const data = await res.json();
      if (data.video_url && onUpdateJob) {
        onUpdateJob({ ...job, videoUrl: data.video_url });
      }
    } catch (e) {
      alert(e.message);
    } finally {
      setLoading(false);
    }
  };

  const POSITIONS = uiLang === "en" ? [
    { id: "top",    label: "Top" },
    { id: "middle", label: "Mid" },
    { id: "bottom", label: "Bottom" },
  ] : [
    { id: "top",    label: "Trên" },
    { id: "middle", label: "Giữa" },
    { id: "bottom", label: "Dưới" },
  ];

  const COLOR_LABELS = uiLang === "en" ? {
    color_text: "Text",
    color_outline: "Outline",
    color_back: "Background",
    color_highlight: "Highlight",
  } : {
    color_text: "Chữ",
    color_outline: "Viền",
    color_back: "Nền",
    color_highlight: "Nổi bật",
  };

  // ── Phase: idle → user has not added subtitles yet. Show CTA.
  if (phase === "idle") {
    return (
      <section style={{
        background: "var(--bg-1)",
        border: "1px solid var(--line)",
        borderRadius: "var(--radius-lg)",
        padding: 16,
        display: "flex", flexDirection: "column", gap: 12,
      }}>
        <div className="mono" style={{ fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)" }}>
          {uiLang === "en" ? "Subtitles" : "Phụ đề"}
        </div>
        <div style={{ fontSize: 13, color: "var(--fg-1)", lineHeight: 1.5 }}>
          {uiLang === "en" ? "Do you want to add subtitles?" : "Bạn có muốn thêm phụ đề?"}
        </div>
        <div style={{ fontSize: 11.5, color: "var(--fg-3)", lineHeight: 1.5 }}>
          {uiLang === "en" 
            ? "CapCut shows per-word yellow pill highlight; Plain shows the full sentence only. Takes ~1-2 minutes."
            : "CapCut hiển thị nổi bật màu vàng cho từng từ; Plain chỉ hiển thị câu đầy đủ. Mất khoảng 1-2 phút."}
        </div>
        <Field label={uiLang === "en" ? "Style" : "Kiểu"}>
          <Segmented value={sub.mode} onChange={(v) => setSub({ ...sub, mode: v })} options={SUBTITLE_MODES}/>
        </Field>
        {addError && (
          <div style={{ fontSize: 11.5, color: "var(--danger, #ff6b6b)" }}>
            {addError}
          </div>
        )}
        <button onClick={startAddSubtitles} disabled={!job?.id} style={{
          marginTop: 4, width: "100%", padding: "10px", background: "var(--accent)", color: "var(--accent-fg)",
          border: "none", borderRadius: "var(--radius)", fontSize: 13, fontWeight: 600,
          cursor: job?.id ? "pointer" : "not-allowed",
        }}>
          {uiLang === "en" ? "Add subtitles" : "Thêm phụ đề"}
        </button>
      </section>
    );
  }

  // ── Phase: adding → background pipeline running. Show progress.
  if (phase === "adding") {
    return (
      <section style={{
        background: "var(--bg-1)",
        border: "1px solid var(--line)",
        borderRadius: "var(--radius-lg)",
        padding: 16,
        display: "flex", flexDirection: "column", gap: 12,
      }}>
        <div className="mono" style={{ fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)" }}>
          {uiLang === "en" ? "Subtitles" : "Phụ đề"}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 10, fontSize: 13, color: "var(--fg-1)" }}>
          <svg width="16" height="16" viewBox="0 0 16 16" style={{ animation: "spin 1s linear infinite" }}>
            <circle cx="8" cy="8" r="6" fill="none" stroke="currentColor" strokeWidth="2" strokeDasharray="30" strokeDashoffset="20" strokeLinecap="round" />
            <style>{`@keyframes spin { to { transform: rotate(360deg); } }`}</style>
          </svg>
          {uiLang === "en" ? "Transcribing voiceover and burning subtitles…" : "Đang tạo chữ từ lời thoại và ghép phụ đề…"}
        </div>
        <div style={{ fontSize: 11.5, color: "var(--fg-3)" }}>
          {uiLang === "en" ? "The video will reload automatically when ready." : "Video sẽ tự động tải lại khi hoàn chỉnh."}
        </div>
      </section>
    );
  }

  // ── Phase: done → full styling controls (restyle existing subtitles).
  return (
    <section style={{
      background: "var(--bg-1)",
      border: "1px solid var(--line)",
      borderRadius: "var(--radius-lg)",
      padding: 16,
      display: "flex", flexDirection: "column", gap: 14,
    }}>
      <div className="mono" style={{ fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--fg-3)" }}>
        {uiLang === "en" ? "Subtitle Styling" : "Định dạng phụ đề"}
      </div>

      {/* live preview window */}
      <div style={{
        position: "relative",
        aspectRatio: "16 / 9",
        borderRadius: "var(--radius)",
        overflow: "hidden",
        border: "1px solid var(--line)",
        background: `
          radial-gradient(ellipse at 30% 40%, var(--bg-3) 0%, transparent 50%),
          radial-gradient(ellipse at 70% 60%, var(--bg-2) 0%, transparent 60%),
          linear-gradient(180deg, var(--bg-1), var(--bg-0))
        `,
      }}>
        {/* fake film grain */}
        <div style={{
          position: "absolute", inset: 0,
          backgroundImage: "radial-gradient(var(--fg-0) 1px, transparent 1px)",
          backgroundSize: "3px 3px",
          opacity: 0.04,
          pointerEvents: "none",
        }}/>
        {/* fake astronaut silhouette */}
        <svg viewBox="0 0 320 180" style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }}>
          <defs>
            <radialGradient id="planet" cx="0.3" cy="0.4">
              <stop offset="0%" stopColor="var(--fg-4)" stopOpacity="0.4"/>
              <stop offset="65%" stopColor="var(--bg-3)" stopOpacity="1"/>
              <stop offset="100%" stopColor="var(--bg-0)" stopOpacity="1"/>
            </radialGradient>
          </defs>
          <circle cx="240" cy="48" r="36" fill="url(#planet)"/>
          <circle cx="60" cy="30" r="0.8" fill="var(--fg-1)" opacity="0.4"/>
          <circle cx="120" cy="22" r="0.5" fill="var(--fg-1)" opacity="0.3"/>
          <circle cx="180" cy="38" r="0.6" fill="var(--fg-1)" opacity="0.4"/>
          <circle cx="290" cy="20" r="0.4" fill="var(--fg-1)" opacity="0.2"/>
          <circle cx="30" cy="60" r="0.5" fill="var(--fg-1)" opacity="0.3"/>
          {/* satellite silhouette */}
          <g transform="translate(80, 100)" fill="var(--fg-4)" opacity="0.5">
            <rect x="-2" y="-4" width="4" height="8"/>
            <rect x="-12" y="-2" width="8" height="4"/>
            <rect x="4" y="-2" width="8" height="4"/>
            <line x1="0" y1="0" x2="40" y2="40" stroke="var(--fg-4)" strokeWidth="0.5" strokeDasharray="2 2" opacity="0.4"/>
          </g>
        </svg>
        {/* aspect overlay corners */}
        {[[0,0,1,1],[1,0,-1,1],[0,1,1,-1],[1,1,-1,-1]].map(([x,y,dx,dy], i) => (
          <svg key={i} width="14" height="14"
            style={{ position: "absolute", [x===0?"left":"right"]: 8, [y===0?"top":"bottom"]: 8, opacity: 0.2 }}>
            <path d={`M0 ${y===0?1:13} L0 0 L${x===0?13:1} 0`} fill="none" stroke="var(--fg-0)" strokeWidth="1"
              transform={`scale(${dx} ${dy}) translate(${dx<0?-14:0}, ${dy<0?-14:0})`}/>
          </svg>
        ))}

        {/* subtitle bar */}
        <div style={{
          position: "absolute",
          left: "50%", transform: "translateX(-50%)",
          [sub.position === "top" ? "top" : sub.position === "middle" ? "top" : "bottom"]: sub.position === "middle" ? "50%" : 18,
          marginTop: sub.position === "middle" ? "-1em" : 0,
          maxWidth: "90%",
          padding: "6px 12px",
          background: assToRgba(sub.color_back),
          borderRadius: 4,
          fontFamily: sub.font === "Arial" ? "Arial, Helvetica, sans-serif" :
                      sub.font === "Geist" ? "Geist, sans-serif" :
                      sub.font === "Inter Tight" ? "'Inter Tight', sans-serif" :
                      sub.font === "Mono" ? "var(--font-mono)" : "Arial",
          fontSize: sub.size * 0.30,  // scale down from 64 to fit preview
          fontWeight: 700,
          letterSpacing: "0.01em",
          textAlign: "center",
          color: assToRgba(sub.color_text),
          textShadow: sub.color_outline && sub.color_outline.slice(0,7) !== "#000000" || (sub.color_outline && parseInt((sub.color_outline.slice(7)||"FF"), 16) > 0)
            ? `
              -1px -1px 0 ${assToRgba(sub.color_outline)},
              1px -1px 0 ${assToRgba(sub.color_outline)},
              -1px 1px 0 ${assToRgba(sub.color_outline)},
              1px 1px 0 ${assToRgba(sub.color_outline)},
              0 0 4px ${assToRgba(sub.color_outline)}`
            : "none",
          whiteSpace: "nowrap",
          lineHeight: 1.2,
        }}>
          {"Voyager 1 and Voyager 2 are still transmitting today.".split(" ").map((w, i) => {
            const isActive = sub.mode === "capcut" && i === 5;
            return (
              <span key={i} style={{
                display: "inline-block",
                padding: isActive ? "1px 6px" : "0",
                margin: isActive ? "0 1px" : "0 2px",
                background: isActive ? assToRgba(sub.color_highlight) : "transparent",
                color: isActive ? "#0a0a0a" : "inherit",
                borderRadius: 3,
                textShadow: isActive ? "none" : undefined,
              }}>{w}</span>
            );
          })}
        </div>
      </div>
      
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
        <Field label={uiLang === "en" ? "Font" : "Phông chữ"}>
          <Select value={sub.font} onChange={(v) => setSub({...sub, font: v})}
            options={[
              { value: "Arial", label: "Arial" },
              { value: "Geist", label: "Geist Sans" },
              { value: "Inter Tight", label: "Inter Tight" },
              { value: "Mono", label: "Geist Mono" },
            ]}/>
        </Field>
        <Field label={uiLang === "en" ? "Position" : "Vị trí"}>
          <Segmented value={sub.position} onChange={(v) => setSub({...sub, position: v})} options={POSITIONS}/>
        </Field>
      </div>

      <Field label={uiLang === "en" ? "Style" : "Kiểu dáng"}>
        <Segmented value={sub.mode} onChange={(v) => setSub({ ...sub, mode: v })} options={SUBTITLE_MODES}/>
      </Field>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
        <Field label={uiLang === "en" ? "Size" : "Kích cỡ"}>
          <NumberStepper value={sub.size} onChange={(v) => setSub({...sub, size: v})} min={24} max={120} step={2} suffix="px"/>
        </Field>
        <Field label={uiLang === "en" ? "Words / line" : "Số từ / dòng"}>
          <NumberStepper value={sub.maxWords} onChange={(v) => setSub({...sub, maxWords: v})} min={1} max={12}/>
        </Field>
      </div>

      <Field label={uiLang === "en" ? "Margin" : "Lề dưới"}>
        <NumberStepper value={sub.marginV} onChange={(v) => setSub({...sub, marginV: v})} min={0} max={600} step={10} suffix="px"/>
      </Field>

      <div>
        <div style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--fg-3)", fontWeight: 500, marginBottom: 8 }}>
          {uiLang === "en" ? "Colors" : "Màu sắc"}
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
          {[
            { label: COLOR_LABELS.color_text, key: "color_text", alpha: "00" },
            { label: COLOR_LABELS.color_outline, key: "color_outline", alpha: "00" },
            { label: COLOR_LABELS.color_back, key: "color_back", alpha: "90" },
            { label: COLOR_LABELS.color_highlight, key: "color_highlight", alpha: "00" },
          ].map(c => (
            <div key={c.key} style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 12, color: "var(--fg-1)" }}>
              <input type="color" value={toHex(sub[c.key])} 
                onChange={e => setSub(prev => ({ ...prev, [c.key]: toAssColor(e.target.value, c.alpha) }))}
                style={{ width: 26, height: 26, padding: 0, border: "none", borderRadius: 4, cursor: "pointer", background: "none" }}
              />
              {c.label}
            </div>
          ))}
        </div>
      </div>

      <button onClick={handleUpdate} disabled={loading} style={{
        marginTop: 4, width: "100%", padding: "8px", background: "var(--accent)", color: "var(--accent-fg)",
        border: "none", borderRadius: "var(--radius)", fontSize: 12.5, fontWeight: 500, cursor: loading ? "wait" : "pointer",
        display: "flex", alignItems: "center", justifyContent: "center", gap: 8
      }}>
        {loading ? (
          <svg width="14" height="14" viewBox="0 0 16 16" style={{ animation: "spin 1s linear infinite" }}>
            <circle cx="8" cy="8" r="6" fill="none" stroke="currentColor" strokeWidth="2" strokeDasharray="30" strokeDashoffset="20" strokeLinecap="round" />
            <style>{`@keyframes spin { to { transform: rotate(360deg); } }`}</style>
          </svg>
        ) : (uiLang === "en" ? "Apply Style" : "Áp dụng định dạng")}
      </button>
    </section>
  );
}

Object.assign(window, { OutputScreen, SCENES });
