/* global React, Reveal */
// ============================================================
// EDITOR SECTIONS
//   - Postproduction: INTERACTIVE Premiere-style timeline
//     · Hover to see timecode  · Click to scrub
//     · Click track label to mute · "Customize" mode to drag clips
//   - ColorGrade: before/after slider
//   - Pipeline: 7-layer cards with hover infographic popover
// ============================================================
const { useState, useEffect, useRef, useMemo } = React;

// ── Initial timeline data — names mix all the AI tools so it
//    reads like a real 2026 hybrid AI workflow, not a Veo demo.
const SEQ_LENGTH_SEC = 102; // 1:42 mapped to 0–100% scrub
const INITIAL_TRACKS = [
{ label: "V3", color: "#7E89FF", clips: [
  { x: 0.5, w: 8, name: "title_card.mov" },
  { x: 50, w: 6, name: "lower_third" },
  { x: 88, w: 11, name: "end_card" }]
},
{ label: "V2", color: "#E8A24A", clips: [
  { x: 0, w: 14, name: "intro_grade" },
  { x: 14, w: 28, name: "act_1_grade" },
  { x: 42, w: 34, name: "act_2_grade" },
  { x: 76, w: 24, name: "finale_grade" }]
},
{ label: "V1", color: "#6ED47A", clips: [
  { x: 0, w: 7, name: "VEO_001" },
  { x: 7, w: 5, name: "KLING_002" },
  { x: 12, w: 8, name: "SEEDANCE_003" },
  { x: 20, w: 6, name: "VEO_004" },
  { x: 26, w: 11, name: "NB_005" },
  { x: 37, w: 8, name: "KLING_006" },
  { x: 45, w: 5, name: "GPT_IMG_007" },
  { x: 50, w: 9, name: "VEO_008" },
  { x: 59, w: 7, name: "SEEDANCE_009" },
  { x: 66, w: 6, name: "NB_010" },
  { x: 72, w: 10, name: "VEO_011" },
  { x: 82, w: 8, name: "KLING_012" },
  { x: 90, w: 10, name: "VEO_013" }]
},
{ kind: "wave", label: "A1", hue: 232 },
{ label: "A2", color: "#D9613A", clips: [
  { x: 6, w: 4, name: "sfx_swoosh" },
  { x: 20, w: 3, name: "sfx_impact" },
  { x: 38, w: 4, name: "sfx_riser" },
  { x: 64, w: 3, name: "sfx_glitch" },
  { x: 82, w: 6, name: "sfx_boom" }]
},
{ kind: "wave", label: "A3", hue: 28, variant: "dense" }];


function toTimecode(percent) {
  const totalSec = percent / 100 * SEQ_LENGTH_SEC;
  const m = Math.floor(totalSec / 60);
  const s = Math.floor(totalSec - m * 60);
  const f = Math.floor((totalSec - Math.floor(totalSec)) * 24);
  return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}:${String(f).padStart(2, "0")}`;
}

// ─── Postproduction / Interactive Timeline ─────────────────
function Postproduction() {
  const [tracks, setTracks] = useState(INITIAL_TRACKS);
  const [muted, setMuted] = useState(() => new Set());
  const [hoverX, setHoverX] = useState(null);
  const [playhead, setPlayhead] = useState(null); // null = auto-loop animation
  const [customize, setCustomize] = useState(false);
  const tracksRef = useRef(null);
  const dragRef = useRef(null);

  const xFromClient = (clientX) => {
    if (!tracksRef.current) return 0;
    const r = tracksRef.current.getBoundingClientRect();
    return Math.max(0, Math.min(100, (clientX - r.left) / r.width * 100));
  };

  // global mousemove/up for clip dragging
  useEffect(() => {
    const move = (e) => {
      if (!dragRef.current) return;
      const cx = e.clientX ?? e.touches?.[0]?.clientX;
      if (cx == null) return;
      const newX = xFromClient(cx) - dragRef.current.offsetX;
      const { ti, ci } = dragRef.current;
      setTracks((prev) => {
        const next = prev.slice();
        const tr = { ...next[ti], clips: next[ti].clips.slice() };
        const w = tr.clips[ci].w;
        tr.clips[ci] = { ...tr.clips[ci], x: Math.max(0, Math.min(100 - w, newX)) };
        next[ti] = tr;
        return next;
      });
    };
    const up = () => {dragRef.current = null;document.body.style.cursor = "";};
    window.addEventListener("mousemove", move);
    window.addEventListener("mouseup", up);
    window.addEventListener("touchmove", move);
    window.addEventListener("touchend", up);
    return () => {
      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseup", up);
      window.removeEventListener("touchmove", move);
      window.removeEventListener("touchend", up);
    };
  }, []);

  const startDrag = (e, ti, ci) => {
    if (!customize) return;
    e.stopPropagation();
    const cx = e.clientX ?? e.touches?.[0]?.clientX;
    const clipX = tracks[ti].clips[ci].x;
    dragRef.current = { ti, ci, offsetX: xFromClient(cx) - clipX };
    document.body.style.cursor = "grabbing";
  };

  const toggleMute = (label) => {
    setMuted((prev) => {
      const next = new Set(prev);
      next.has(label) ? next.delete(label) : next.add(label);
      return next;
    });
  };

  const reset = () => {
    setTracks(INITIAL_TRACKS);
    setMuted(new Set());
    setPlayhead(null);
    setCustomize(false);
  };

  const tcDisplay = playhead != null ? toTimecode(playhead) :
  hoverX != null ? toTimecode(hoverX) :
  "00:01:42:08";

  return (
    <section className="post" id="post">
      <div className="section-head">
        <div className="caps">Behind the cut</div>
        <h2 className="section-title">AI generates. <em>Editing makes it watchable.</em></h2>
        <p className="section-sub">
          Pacing, sound design, color, transitions, captions - the post-production work is what
          separates a deliverable channel video from a stitched-together prompt dump.
          {" "}<em>Hover to scrub. Click a track label to mute. Hit Customize to drag clips around.</em>
        </p>
      </div>

      <window.Reveal className="timeline">
        <div className="timeline__head">
          <span className="caps">Project ▸ horror_trailer_v07.prproj</span>
          <span className="caps timeline__seq">Sequence 01 · 1920×1080 · 24fps</span>
          <div className="timeline__ctrls">
            <button
              className={`tl-ctrl ${customize ? "tl-ctrl--on" : ""}`}
              onClick={() => setCustomize((c) => !c)}
              title="Drag clips to reposition">
              
              {customize ? "✓ Editing" : "✎ Customize"}
            </button>
            <button className="tl-ctrl" onClick={reset} title="Restore initial state">↻ Reset</button>
            <span className="caps timeline__tc">
              <i className="dot dot--rec" /> {tcDisplay}
            </span>
          </div>
        </div>

        <div className="timeline__ruler">
          {Array.from({ length: 18 }).map((_, i) =>
          <span key={i}>{(i * 5).toString().padStart(2, "0")}s</span>
          )}
        </div>

        <div
          className={`timeline__tracks ${customize ? "timeline__tracks--edit" : ""}`}
          ref={tracksRef}
          onMouseMove={(e) => setHoverX(xFromClient(e.clientX))}
          onMouseLeave={() => setHoverX(null)}
          onClick={(e) => setPlayhead(xFromClient(e.clientX))}>
          
          {tracks.map((t, ti) =>
          t.kind === "wave" ?
          <Waveform
            key={ti}
            label={t.label}
            hue={t.hue}
            variant={t.variant}
            muted={muted.has(t.label)}
            onMute={(e) => {e.stopPropagation();toggleMute(t.label);}} /> :


          <Track
            key={ti}
            label={t.label}
            color={t.color}
            clips={t.clips}
            muted={muted.has(t.label)}
            onMute={(e) => {e.stopPropagation();toggleMute(t.label);}}
            onClipDown={(ci, e) => startDrag(e, ti, ci)}
            editable={customize} />


          )}

          {hoverX !== null && playhead === null &&
          <div className="timeline__hover" style={{ left: hoverX + "%" }}>
              <span className="timeline__hover-tc">{toTimecode(hoverX)}</span>
            </div>
          }

          <div
            className="timeline__playhead"
            style={playhead !== null ?
            { left: playhead + "%", animation: "none" } :
            undefined} />
          
        </div>

        <div className="timeline__legend">
          <span><i style={{ background: "#7E89FF" }} /> Graphics</span>
          <span><i style={{ background: "#E8A24A" }} /> Color</span>
          <span><i style={{ background: "#6ED47A" }} /> AI shots</span>
          <span><i style={{ background: "#D9613A" }} /> SFX</span>
          <span><i style={{ background: "#9EC9D9" }} /> VO + music</span>
          <span className="timeline__help">↳ Click to scrub · Click label to mute · Customize → drag clips</span>
        </div>
      </window.Reveal>
    </section>);

}

function Track({ label, color, clips, muted, onMute, onClipDown, editable }) {
  return (
    <div className={`tl-row ${muted ? "tl-row--muted" : ""}`}>
      <button
        className={`tl-row__label ${muted ? "tl-row__label--muted" : ""}`}
        onClick={onMute}
        title={muted ? "Unmute" : "Mute"}>
        
        {label}
        {muted && <span className="tl-mute-x">M</span>}
      </button>
      <div className="tl-row__lane">
        {clips.map((c, i) =>
        <div
          key={i}
          className={`tl-clip ${editable ? "tl-clip--drag" : ""}`}
          style={{
            left: c.x + "%",
            width: c.w + "%",
            background: `linear-gradient(180deg, ${color}33 0%, ${color}1c 100%)`,
            borderColor: color,
            animationDelay: i * 60 + "ms"
          }}
          onMouseDown={(e) => onClipDown(i, e)}
          onTouchStart={(e) => onClipDown(i, e)}
          onClick={(e) => e.stopPropagation()}>
          
            <span className="tl-clip__name">{c.name}</span>
            <span className="tl-clip__handle tl-clip__handle--l" />
            <span className="tl-clip__handle tl-clip__handle--r" />
          </div>
        )}
      </div>
    </div>);

}

function Waveform({ label, hue = 28, variant = "normal", muted, onMute }) {
  const bars = useMemo(() => {
    const n = variant === "dense" ? 220 : 160;
    return Array.from({ length: n }, (_, i) => {
      const a = Math.abs(Math.sin(i * 0.31) * 0.6 + Math.cos(i * 0.13) * 0.4);
      const b = Math.abs(Math.sin(i * 0.07 + 1) * 0.5);
      return 0.18 + 0.82 * (a * 0.7 + b * 0.3);
    });
  }, [variant]);
  return (
    <div className={`tl-row tl-row--wave ${muted ? "tl-row--muted" : ""}`}>
      <button
        className={`tl-row__label ${muted ? "tl-row__label--muted" : ""}`}
        onClick={onMute}
        title={muted ? "Unmute" : "Mute"}>
        
        {label}
        {muted && <span className="tl-mute-x">M</span>}
      </button>
      <div className="tl-row__lane">
        <div className="wave" style={{ "--wave-hue": hue }}>
          {bars.map((h, i) =>
          <span key={i} style={{ height: h * 100 + "%", animationDelay: i * 6 + "ms" }} />
          )}
        </div>
      </div>
    </div>);

}

// ─── Color Grade Before/After ──────────────────────────────
function ColorGrade() {
  const [pos, setPos] = useState(50);
  const wrap = useRef(null);
  const dragging = useRef(false);

  const move = (clientX) => {
    if (!wrap.current) return;
    const r = wrap.current.getBoundingClientRect();
    const p = (clientX - r.left) / r.width * 100;
    setPos(Math.max(2, Math.min(98, p)));
  };
  const onDown = (e) => {dragging.current = true;move(e.clientX ?? e.touches?.[0]?.clientX);};

  useEffect(() => {
    const onMove = (e) => {if (!dragging.current) return;move(e.clientX ?? e.touches?.[0]?.clientX);};
    const onUp = () => {dragging.current = false;};
    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseup", onUp);
    window.addEventListener("touchmove", onMove);
    window.addEventListener("touchend", onUp);
    return () => {
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mouseup", onUp);
      window.removeEventListener("touchmove", onMove);
      window.removeEventListener("touchend", onUp);
    };
  }, []);

  return (
    <section className="grade-section">
      <div className="section-head">
        <div className="caps">Color &amp; finishing</div>
        <h2 className="section-title">From AI output to <em>finished frame</em>.</h2>
        <p className="section-sub">
          The final pass is where raw generations become a coherent film: contrast, skin tone protection, halation,
          grain, letterbox, and a shot-to-shot match that feels intentional.
        </p>
      </div>

      <window.Reveal>
        <div className="grade-lab">
          <div className="grade-lab__monitor">
            <div className="grade-lab__bar">
              <span className="dot dot--rec" />
              <span>sequence_hero_final.prproj</span>
              <span>24fps / Rec.709 / H.264</span>
            </div>
            <div className="grade" ref={wrap} onMouseDown={onDown} onTouchStart={onDown}>
              <div className="grade__layer grade__raw">
                <GradeArt variant="raw" />
                <span className="grade__tag">Raw generation</span>
              </div>
              <div className="grade__layer grade__final" style={{ clipPath: `inset(0 0 0 ${pos}%)` }}>
                <GradeArt variant="final" />
                <span className="grade__tag grade__tag--final">Final master</span>
              </div>
              <div className="grade__handle" style={{ left: pos + "%" }}>
                <div className="grade__knob">
                  <svg width="18" height="18" viewBox="0 0 18 18"><path d="M6 3 L3 9 L6 15 M12 3 L15 9 L12 15" stroke="currentColor" strokeWidth="1.6" fill="none" strokeLinecap="round" /></svg>
                </div>
              </div>
            </div>
            <div className="grade-lab__footer">
              <span>Drag the divider</span>
              <span>{Math.round(pos)}% reveal</span>
            </div>
          </div>

          <aside className="grade-board">
            <div className="grade-board__block">
              <div className="caps">Finish stack</div>
              {[
                ["01", "Balance", "Exposure, blacks, contrast"],
                ["02", "Look", "Teal shadows, warm highlights"],
                ["03", "Texture", "Grain, halation, vignette"],
                ["04", "QC", "Shot match, export check"],
              ].map(([n, t, d]) =>
              <div className="grade-step" key={n}>
                  <span>{n}</span>
                  <div><b>{t}</b><small>{d}</small></div>
                </div>
              )}
            </div>

            <div className="grade-board__block">
              <div className="caps">Scopes</div>
              <div className="scope">
                {Array.from({ length: 26 }).map((_, i) => <i key={i} style={{ height: `${24 + Math.abs(Math.sin(i * 0.47)) * 62}%`, "--i": i }} />)}
              </div>
              <div className="scope__labels"><span>shadows</span><span>skin</span><span>highlights</span></div>
            </div>
          </aside>
        </div>
      </window.Reveal>
    </section>);

}

function GradeArt({ variant }) {
  const raw = variant === "raw";
  const src = raw ? "public/grade/raw-before-grade.png" : "public/grade/final-after-grade.png";
  return (
    <div className={`gart ${raw ? "gart--raw" : "gart--final"}`}>
      <img className="gart__image" src={src} alt={raw ? "Raw ungraded frame" : "Color graded final frame"} />
      <div className="gart__grain" />
      <div className="gart__vignette" />
      <div className="gart__bars"><span /><span /></div>
    </div>);

}

// ─── Pipeline with Netflix-style hover expand ───────────────
const PIPE_LAYERS = [
{ t: "Script lock + shotlist", d: "Beat-by-beat plan before any generation", detail: "I lock the story structure first: hook, emotional turns, visual beats, and delivery notes. This prevents wasted generations and gives every scene a clear job before production starts.", tag: "Pre", image: "public/pipeline/01-shotlist.svg", beats: ["Brief cleaned into story beats", "Scene list and pacing notes", "Generation plan before tools open"] },
{ t: "Character sheets", d: "Nano Banana + GPT Image - faces stay consistent", detail: "For character-led stories, I build reference sheets before video generation. The goal is simple: the same person, wardrobe, lighting rules, and camera language across every important shot.", tag: "Pre", image: "public/pipeline/02-character.svg", beats: ["Face and costume anchors", "Prompt DNA for consistency", "Reference set for every scene"] },
{ t: "AI shot generation", d: "Veo 3.1 · Kling · Seedance - best-of selection per beat", detail: "Each beat gets multiple generated options, then I choose the strongest shots instead of forcing the first output. I match tool choice to the scene: cinematic motion, action, atmosphere, or fast variations.", tag: "Gen", image: "public/pipeline/03-generation.svg", beats: ["Multiple takes per story beat", "Best tool picked per shot", "Rejected clips filtered early"] },
{ t: "Voiceover + mix", d: "Client VO or ElevenLabs - leveled, EQ'd, de-essed", detail: "Audio carries the perceived quality of the whole video. I clean the voice, balance levels, add ambience and impacts, then shape the mix so it feels finished rather than assembled.", tag: "Audio", image: "public/pipeline/04-voiceover.svg", beats: ["VO cleaned and leveled", "Music and atmosphere shaped", "SFX placed on story moments"] },
{ t: "Premiere assembly", d: "Pacing, j-cuts, transitions, captions, lower thirds", detail: "This is where the raw generated pieces become a watchable video. I build rhythm with J-cuts, trim dead air, layer captions, and use transitions only where they support the story.", tag: "Edit", image: "public/pipeline/05-assembly.svg", beats: ["A-roll and B-roll arranged", "Captions and lower thirds placed", "Timing tuned for retention"] },
{ t: "Color + film emulation", d: "Lumetri grade, halation, grain, frame-rate match", detail: "The finish pass makes the project feel intentional. I match contrast, warmth, grain, halation, and motion feel so the scenes look like one film instead of separate AI clips.", tag: "Finish", image: "public/pipeline/06-color.svg", beats: ["Lumetri grade and contrast pass", "Grain, glow, halation added", "Shot-to-shot consistency checked"] },
{ t: "Delivery", d: "1080p H.264 · channel-ready · project file backup", detail: "Before handoff, I do a final review pass and export a clean upload-ready file. The delivery is packaged so the client can publish without fixing technical details.", tag: "Out", image: "public/pipeline/07-delivery.svg", beats: ["Final QC pass", "1080p H.264 export", "Project backup and handoff"] }];


function Pipeline() {
  return (
    <section className="pipe" id="pipeline">
      <div className="section-head">
        <div className="caps">Pipeline</div>
        <h2 className="section-title">Seven layers. <em>One finished video.</em></h2>
        <p className="section-sub">Hover any layer to see the infographic for that production step.</p>
      </div>
      <div className="pipe__grid">
        {PIPE_LAYERS.map((l, i) =>
        <window.Reveal key={l.t} delay={i * 70} className="pipe__cell">
            <PipeCard layer={l} index={i} />
          </window.Reveal>
        )}
      </div>
    </section>);

}

function PipeCard({ layer, index }) {
  const [imgLoaded, setImgLoaded] = useState(false);
  const [imgErrored, setImgErrored] = useState(false);
  const [fullscreen, setFullscreen] = useState(false);
  const [detailed, setDetailed] = useState(false);
  const [approved, setApproved] = useState(false);
  const num = `L.${String(index + 1).padStart(2, "0")}`;
  useEffect(() => {
    if (!fullscreen) return;
    const onKey = (e) => {if (e.key === "Escape") setFullscreen(false);};
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => {window.removeEventListener("keydown", onKey);document.body.style.overflow = "";};
  }, [fullscreen]);

  return (
    <article className="nfx">
      {/* COMPACT — visible by default, sits in grid flow */}
      <div className="nfx__compact">
        <div className="nfx__num">{num}</div>
        <div className="nfx__tag">{layer.tag}</div>
        <h3 className="nfx__t">{layer.t}</h3>
        <p className="nfx__d">{layer.d}</p>
        <div className="nfx__hint">
          <span className="nfx__hint-dot" />
          Hover to preview
        </div>
      </div>

      {/* EXPANDED — Netflix-style overlay on hover */}
      <div className="nfx__expanded">
        <div className="nfx__media">
          {layer.image && !imgErrored ?
          <img
            src={layer.image}
            alt={layer.t}
            onLoad={() => setImgLoaded(true)}
            onError={() => setImgErrored(true)}
            className={imgLoaded ? "is-loaded" : ""} /> :

          null}
          {(!layer.image || imgErrored) &&
          <div className="nfx__media-ph">
              <svg width="100%" height="100%" preserveAspectRatio="none" style={{ position: "absolute", inset: 0 }}>
                <defs>
                  <pattern id={`nfx-${index}`} width="14" height="14" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
                    <rect width="14" height="14" fill="transparent" />
                    <line x1="0" y1="0" x2="0" y2="14" stroke="rgba(255,255,255,0.07)" strokeWidth="1" />
                  </pattern>
                </defs>
                <rect width="100%" height="100%" fill={`url(#nfx-${index})`} />
              </svg>
              <div className="nfx__media-ph-text">
                <span className="caps">Infographic unavailable</span>
                <code>{layer.image}</code>
              </div>
            </div>
          }
          <div className="nfx__media-fade" />
          <span className="nfx__media-badge">{num} · {layer.tag}</span>
        </div>

        <div className="nfx__body">
          <h3 className="nfx__t-big">{layer.t}</h3>
          <div className="nfx__actions">
            <button className="nfx__btn nfx__btn--primary" title="Open infographic fullscreen" type="button" onClick={() => setFullscreen(true)}>
              <svg width="14" height="14" viewBox="0 0 14 14"><path d="M3 1.5 L12 7 L3 12.5 Z" fill="currentColor" /></svg>
            </button>
            <button className={approved ? "nfx__btn is-on" : "nfx__btn"} title={approved ? "Marked as reviewed" : "Looks good"} type="button" onClick={() => setApproved((v) => !v)}>
              <svg width="14" height="14" viewBox="0 0 14 14"><path d="M2 7 L5.5 10.5 L12 4" stroke="currentColor" strokeWidth="1.6" fill="none" strokeLinecap="round" strokeLinejoin="round" /></svg>
            </button>
            <button className={detailed ? "nfx__btn nfx__btn--end is-on" : "nfx__btn nfx__btn--end"} title={detailed ? "Hide details" : "Show full card details"} type="button" aria-expanded={detailed} onClick={() => setDetailed((v) => !v)}>
              <svg width="12" height="12" viewBox="0 0 12 12"><path d="M2.5 4.5 L6 8 L9.5 4.5" stroke="currentColor" strokeWidth="1.6" fill="none" strokeLinecap="round" strokeLinejoin="round" /></svg>
            </button>
          </div>
          <p className="nfx__d-big">{layer.d}</p>
          {detailed &&
          <div className="nfx__details">
              <p>{layer.detail}</p>
              <ul>
                {layer.beats.map((b) => <li key={b}>{b}</li>)}
              </ul>
            </div>
          }
          <div className="nfx__meta-row">
            <span className="nfx__chip nfx__chip--accent">{layer.tag}</span>
            <span className="nfx__chip">Layer {index + 1} of 7</span>
            <span className="nfx__chip">{detailed ? "Details open" : "Use arrow for details"}</span>
          </div>
        </div>
      </div>
      {fullscreen && (window.ReactDOM?.createPortal ? window.ReactDOM.createPortal(
      <div className="nfx-full" role="dialog" aria-modal="true" aria-label={`${layer.t} infographic`} onClick={() => setFullscreen(false)}>
          <button className="nfx-full__close" type="button" onClick={() => setFullscreen(false)}>Close ×</button>
          <div className="nfx-full__inner" onClick={(e) => e.stopPropagation()}>
            <img src={layer.image} alt={layer.t} />
            <div className="nfx-full__caption">
              <span className="caps">{num} · {layer.tag}</span>
              <h3>{layer.t}</h3>
              <p>{layer.detail}</p>
            </div>
          </div>
        </div>,
        document.body
      ) : null)}
    </article>);

}

Object.assign(window, { Postproduction, ColorGrade, Pipeline });
