// AI Highlight Agent — clip judge console
const AIHighlightAgent = ({ tweaks }) => {
  const [selectedClip, setSelectedClip] = useState("clip-2026-05-11-1842");
  const [overrides, setOverrides] = useState({});
  const [pulseStage, setPulseStage] = useState(4); // multimodal judge currently working

  // Upload state
  const [uploaded, setUploaded] = useState(null);     // { url, frames, duration, width, height, fileName, fileSize }
  const [analysis, setAnalysis] = useState(null);     // result from LLM
  const [pipelineStep, setPipelineStep] = useState(-1); // -1 idle, 0..5 running
  const [analysisError, setAnalysisError] = useState(null);
  const fileInputRef = useRef(null);

  // Cycle pulse through pipeline stages (only when no upload is processing)
  useEffect(() => {
    if (pipelineStep !== -1) return; // upload-driven pulse takes over
    const i = setInterval(() => {
      setPulseStage(s => (s + 1) % window.WZN.AI_PIPELINE_STAGES.length);
    }, 1800);
    return () => clearInterval(i);
  }, [pipelineStep]);

  useEffect(() => {
    if (pipelineStep >= 0) setPulseStage(pipelineStep);
  }, [pipelineStep]);

  const state = window.WZN.AI_AGENT_STATE;
  const stages = window.WZN.AI_PIPELINE_STAGES;
  const queue = window.WZN.AI_QUEUE;
  const dailyVol = window.WZN.AI_DAILY_VOLUME;

  // Build the active clip from upload (if present) or fall back to mock
  const baseClip = window.WZN.AI_FOCUS_CLIP;
  const clip = uploaded && analysis ? {
    ...baseClip,
    id: `upload-${uploaded.fileName}`,
    submitter: "EGEN OPPLASTING",
    submitterTag: "OPP",
    player: uploaded.fileName.replace(/\.[^.]+$/, "").slice(0,20),
    uploadedAt: new Date().toISOString(),
    duration: uploaded.duration,
    fileSize: `${(uploaded.fileSize / 1024 / 1024).toFixed(1)} MB`,
    resolution: `${uploaded.width}×${uploaded.height}`,
    status: "DONE",
    keyFrames: uploaded.frames.map((f, i, arr) => ({
      t: f.t,
      label: analysis.events && analysis.events[i] ? analysis.events[i].label : `FRAME ${i+1}`,
      type: analysis.events && analysis.events[i] ? analysis.events[i].type : "context",
      dataUrl: f.dataUrl,
    })),
    scores: analysis.scores,
    events: analysis.events || baseClip.events,
    metadata: {
      title: analysis.title,
      titleConfidence: 0.88,
      description: analysis.description,
      descConfidence: 0.85,
      category: analysis.category,
      categoryConfidence: 0.92,
      tags: analysis.tags,
      weapon: analysis.weapon || "Ukjent",
      location: analysis.location || "Ukjent",
      killCount: analysis.killCount ?? 0,
      avgDistance: analysis.avgDistance ?? 0,
      timeFrame: `${uploaded.duration.toFixed(1)}s`,
    },
    recommendation: {
      overallScore: (
        (analysis.scores.difficulty.value + analysis.scores.execution.value +
         analysis.scores.hype.value + analysis.scores.originality.value) / 4
      ),
      publishDecision: analysis.recommendation,
      decisionConfidence: 0.88,
      flags: analysis.flags || [],
      similarClips: ["upload-prev-1", "upload-prev-2"],
    },
  } : baseClip;

  const axisScore = (axis) => overrides[axis] ?? clip.scores[axis].value;
  const overallScore = (
    (axisScore("difficulty") + axisScore("execution") + axisScore("hype") + axisScore("originality")) / 4
  ).toFixed(1);

  // --- Upload + analysis flow ---
  const handleFile = async (file) => {
    if (!file || !file.type.startsWith("video/")) {
      setAnalysisError("Filen må være en video (mp4, mov, webm).");
      return;
    }
    setAnalysisError(null);
    setOverrides({});
    setAnalysis(null);

    const url = URL.createObjectURL(file);
    setPipelineStep(0); // INTAKE
    await sleep(400);

    try {
      setPipelineStep(1); // FRAMES
      const meta = await extractFrames(file, 9);
      setUploaded({
        url,
        frames: meta.frames,
        duration: meta.duration,
        width: meta.width,
        height: meta.height,
        fileName: file.name,
        fileSize: file.size,
      });

      setPipelineStep(2); // OCR
      await sleep(800);
      setPipelineStep(3); // AUDIO
      await sleep(600);
      setPipelineStep(4); // JUDGE
      const result = await callClipJudge({
        fileName: file.name,
        duration: meta.duration,
        width: meta.width,
        height: meta.height,
      });
      setPipelineStep(5); // SYNTH
      await sleep(500);
      setAnalysis(result);
      setPipelineStep(-1);
    } catch (e) {
      setAnalysisError("Analyse feilet: " + (e.message || e));
      setPipelineStep(-1);
    }
  };

  const resetUpload = () => {
    if (uploaded?.url) URL.revokeObjectURL(uploaded.url);
    setUploaded(null);
    setAnalysis(null);
    setOverrides({});
    setAnalysisError(null);
    setPipelineStep(-1);
  };

  return (
    <div className="ai-agent">
      {/* Upload zone */}
      <UploadStrip
        onFile={handleFile}
        onPickClick={() => fileInputRef.current?.click()}
        fileInputRef={fileInputRef}
        uploaded={uploaded}
        analysis={analysis}
        pipelineStep={pipelineStep}
        error={analysisError}
        onReset={resetUpload}
        accent={tweaks.accent}
        stages={stages}
      />

      {/* Top status banner */}
      <div className="aa-banner" style={{borderColor: tweaks.accent}}>
        <div className="aab-left">
          <div className="aab-status">
            <span className="aab-pulse" style={{background: tweaks.accent}} />
            <div className="aab-status-text">
              <div className="aab-label" style={{color: tweaks.accent}}>● AGENT ACTIVE</div>
              <div className="aab-model">MODEL · {state.modelVersion}</div>
            </div>
          </div>
        </div>
        <div className="aab-stats">
          <div className="aab-stat">
            <span>I KØ</span>
            <b style={{color: tweaks.accent}}>{state.queueDepth}</b>
          </div>
          <div className="aab-stat">
            <span>PROSESSERT I DAG</span>
            <b>{state.processedToday}</b>
          </div>
          <div className="aab-stat">
            <span>ACCEPT RATE</span>
            <b>{Math.round(state.acceptanceRate * 100)}%</b>
          </div>
          <div className="aab-stat">
            <span>SNITT KONFIDENS</span>
            <b>{Math.round(state.avgConfidence * 100)}%</b>
          </div>
          <div className="aab-stat">
            <span>SNITT LATENCY</span>
            <b>{state.avgLatency}s</b>
          </div>
          <div className="aab-stat">
            <span>KOSTNAD I DAG</span>
            <b>${state.costToday.toFixed(2)}</b>
          </div>
        </div>
      </div>

      {/* Pipeline visualization */}
      <div className="panel aa-pipeline">
        <div className="aap-head">
          <div className="aap-head-l">
            <div className="section-code" style={{borderColor: tweaks.accent}}>P01</div>
            <div>
              <h3 className="ls-title">PIPELINE · CLIP JUDGE</h3>
              <div className="ls-sub">{state.modelsActive.length} modeller aktive · snitt {(stages.reduce((s,x) => s + x.avgMs, 0)/1000).toFixed(1)}s ende-til-ende</div>
            </div>
          </div>
          <div className="aap-head-r">
            <button className="ghost-btn small">EKSPORTER LOGGER ↗</button>
            <button className="ghost-btn small">PAUSE AGENT</button>
          </div>
        </div>

        <div className="aap-flow">
          {stages.map((s, i) => {
            const active = i === pulseStage;
            return (
              <React.Fragment key={s.id}>
                <div className={`aap-stage ${active ? "active" : ""}`} style={active ? {borderColor: tweaks.accent} : null}>
                  <div className="aaps-num" style={active ? {color: tweaks.accent} : null}>{s.icon}</div>
                  <div className="aaps-name" style={active ? {color: tweaks.accent} : null}>{s.name}</div>
                  <div className="aaps-desc">{s.desc}</div>
                  <div className="aaps-ms">~{s.avgMs}ms</div>
                  {active && <div className="aaps-pulse" style={{background: tweaks.accent}} />}
                </div>
                {i < stages.length - 1 && (
                  <div className="aap-arrow">
                    <div className={`aap-arrow-line ${active || i+1 === pulseStage ? "lit" : ""}`} style={(active || i+1 === pulseStage) ? {background: tweaks.accent} : null} />
                    <div className="aap-arrow-tip">→</div>
                  </div>
                )}
              </React.Fragment>
            );
          })}
        </div>
      </div>

      {/* Main content: focus clip + queue */}
      <div className="aa-main">
        {/* Focus clip — left column */}
        <div className="aa-focus">
          <div className="panel">
            <div className="aaf-head">
              <div>
                <div className="aaf-eyebrow">FOKUS · LIVE ANALYSE</div>
                <div className="aaf-title">{clip.metadata.title}</div>
                <div className="aaf-sub">
                  <div className="team-tag" style={{borderColor: tweaks.accent, color: tweaks.accent}}>{clip.submitterTag}</div>
                  <span>{clip.submitter}</span>
                  <span className="dot-sep">·</span>
                  <span>{clip.player}</span>
                  <span className="dot-sep">·</span>
                  <span>{clip.duration}s · {clip.resolution}</span>
                </div>
              </div>
              <div className="aaf-status" style={{borderColor: tweaks.accent, color: tweaks.accent}}>
                <span className="aabs-pulse" style={{background: tweaks.accent}} />
                {clip.status}
              </div>
            </div>

            {/* Video preview with overlay */}
            <div className="aaf-video">
              {uploaded ? (
                <div className="aaf-real-video">
                  <video
                    src={uploaded.url}
                    controls
                    muted
                    style={{width:"100%", display:"block", aspectRatio:"16/9", background:"#000", objectFit:"contain"}}
                  />
                  <div className="aaf-overlay-grid" style={{pointerEvents:"none"}}>
                    <div className="aov-corner tl">VISION · YOLO-X · live</div>
                    <div className="aov-corner tr">OPPLASTET · {clip.fileSize}</div>
                    <div className="aov-corner bl">OCR · KILLFEED</div>
                    <div className="aov-corner br">JUDGE · v3.2 · streamed</div>
                  </div>
                </div>
              ) : (
                <div className="stream-mock big">
                  <div className="stream-mock-scan" />
                  <div className="stream-mock-corners"><span/><span/><span/><span/></div>
                  {/* AI overlay grid */}
                  <div className="aaf-overlay-grid">
                    <div className="aov-corner tl">VISION · YOLO-X · 60fps</div>
                    <div className="aov-corner tr">AUDIO · MEL · 16kHz</div>
                    <div className="aov-corner bl">OCR · KILLFEED LIVE</div>
                    <div className="aov-corner br">JUDGE · v3.2 · streaming</div>
                    {/* Detection boxes */}
                    <div className="aov-box" style={{left:"42%", top:"38%", width:"12%", height:"22%", borderColor: tweaks.accent}}>
                      <span style={{background: tweaks.accent}}>ENEMY · 0.94</span>
                    </div>
                    <div className="aov-box" style={{left:"68%", top:"52%", width:"8%", height:"14%", borderColor: tweaks.accent}}>
                      <span style={{background: tweaks.accent}}>ENEMY · 0.87</span>
                    </div>
                    <div className="aov-reticle" style={{borderColor: tweaks.accent}} />
                  </div>
                  <div className="aaf-play" style={{borderColor: tweaks.accent, color: tweaks.accent}}>▶</div>
                  <div className="aaf-time">04:08 / {clip.duration}s</div>
                </div>
              )}
            </div>

            {/* Key frame strip */}
            <div className="aaf-frames">
              <div className="aaff-label">EXTRAHERTE KEY-FRAMES · {clip.keyFrames.length} av 60</div>
              <div className="aaff-strip">
                {clip.keyFrames.map((f, i) => (
                  <div key={i} className={`aaff-frame frame-${f.type}`} style={f.type === "kill" ? {borderColor: tweaks.accent} : null}>
                    <div className="aaff-thumb">
                      {f.dataUrl ? (
                        <img src={f.dataUrl} alt={`Frame ${i}`} style={{width:"100%", height:"100%", display:"block", objectFit:"cover"}} />
                      ) : (
                        <>
                          <div className="stream-mock-scan" />
                          {f.type === "kill" && <span className="aaff-kill-pip" style={{background: tweaks.accent}} />}
                        </>
                      )}
                      {f.dataUrl && f.type === "kill" && <span className="aaff-kill-pip" style={{background: tweaks.accent, zIndex:2}} />}
                    </div>
                    <div className="aaff-meta">
                      <span className="aaff-t">{f.t.toFixed(1)}s</span>
                      <span className="aaff-l" style={f.type === "kill" ? {color: tweaks.accent} : null}>{f.label}</span>
                    </div>
                  </div>
                ))}
              </div>
            </div>

            {/* Event timeline */}
            <div className="aaf-events">
              <div className="aafe-head">
                <div className="aafe-eyebrow">EVENT-TIMELINE · DETEKTERT</div>
                <div className="aafe-legend">
                  <span><span className="evd kill" style={{background: tweaks.accent}}/>KILL</span>
                  <span><span className="evd audio"/>AUDIO</span>
                  <span><span className="evd movement"/>MOVEMENT</span>
                  <span><span className="evd item"/>ITEM</span>
                </div>
              </div>
              <div className="aafe-track">
                <div className="aafe-axis">
                  {[0,5,10,15].map(t => (
                    <span key={t} style={{left: `${(t/clip.duration)*100}%`}}>{t}s</span>
                  ))}
                </div>
                {clip.events.map((e, i) => (
                  <div
                    key={i}
                    className={`aafe-event ev-${e.type}`}
                    style={{left: `${(e.t/clip.duration)*100}%`, ...(e.type === "kill" ? {background: tweaks.accent, borderColor: tweaks.accent} : {})}}
                    title={e.label}
                  >
                    <div className="aafe-event-tip">
                      <div className="aet-t">{e.t.toFixed(1)}s · {Math.round(e.confidence*100)}%</div>
                      <div className="aet-l">{e.label}</div>
                    </div>
                  </div>
                ))}
              </div>
              <div className="aafe-list">
                {clip.events.map((e, i) => (
                  <div key={i} className={`aafe-row ev-${e.type}`}>
                    <span className="aafer-t">{e.t.toFixed(1)}s</span>
                    <span className={`aafer-type ev-${e.type}`} style={e.type === "kill" ? {background: tweaks.accent, color:'#000'} : null}>{e.type.toUpperCase()}</span>
                    <span className="aafer-text">{e.label}</span>
                    <span className="aafer-conf">{Math.round(e.confidence*100)}%</span>
                  </div>
                ))}
              </div>
            </div>
          </div>

          {/* Score breakdown */}
          <div className="panel">
            <SectionHeader
              code="SC"
              title="VURDERING · 4 AKSER"
              subtitle="Multimodal LLM scoring · justerbar"
              accent={tweaks.accent}
              right={
                <div className="aafs-overall">
                  <span>TOTAL</span>
                  <b style={{color: tweaks.accent}}>{overallScore}</b>
                  <span>/10</span>
                </div>
              }
            />
            <div className="score-grid">
              {[
                { key:"difficulty",  label:"VANSKELIGHETSGRAD", desc:"1v4, lav HP, dårlig posisjonering" },
                { key:"execution",   label:"EKSEKVERING",       desc:"Aim, recoil, TTK, decisions" },
                { key:"hype",        label:"HYPE-FAKTOR",       desc:"Momentum, audio-energi, dramaturgi" },
                { key:"originality", label:"ORIGINALITET",      desc:"Taktikk, kreativitet, sjeldenhet" },
              ].map(axis => {
                const data = clip.scores[axis.key];
                const val = overrides[axis.key] ?? data.value;
                const isOverridden = overrides[axis.key] !== undefined;
                return (
                  <div key={axis.key} className="score-axis">
                    <div className="sa-head">
                      <div>
                        <div className="sa-label">{axis.label}</div>
                        <div className="sa-desc">{axis.desc}</div>
                      </div>
                      <div className="sa-value" style={{color: tweaks.accent}}>{val.toFixed(1)}</div>
                    </div>
                    <div className="sa-bar">
                      <div className="sa-bar-bg" />
                      <div className="sa-bar-fill" style={{width: `${val*10}%`, background: tweaks.accent}} />
                      <div className="sa-bar-marks">
                        {[2,4,6,8].map(m => <span key={m} style={{left: `${m*10}%`}}/>)}
                      </div>
                    </div>
                    <div className="sa-foot">
                      <div className="sa-conf">
                        <span>KONFIDENS</span>
                        <div className="sa-conf-bar"><div className="sa-conf-fill" style={{width: `${data.confidence*100}%`, background: tweaks.accent}}/></div>
                        <b>{Math.round(data.confidence*100)}%</b>
                      </div>
                      <div className="sa-actions">
                        <button className="sa-step" onClick={() => setOverrides(o => ({...o, [axis.key]: Math.max(0, val - 0.5)}))}>−</button>
                        <button className="sa-step" onClick={() => setOverrides(o => ({...o, [axis.key]: Math.min(10, val + 0.5)}))}>+</button>
                        {isOverridden && (
                          <button className="sa-reset" onClick={() => setOverrides(o => { const n = {...o}; delete n[axis.key]; return n; })}>RESET</button>
                        )}
                      </div>
                    </div>
                    <div className="sa-reasoning">
                      <span className="sa-r-label">AI BEGRUNNELSE:</span>
                      "{data.reasoning}"
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
        </div>

        {/* Right column: metadata + queue */}
        <div className="aa-side">
          {/* Auto-metadata */}
          <div className="panel compact">
            <div className="ls-head">
              <div className="ls-head-l">
                <div className="section-code" style={{borderColor: tweaks.accent}}>M01</div>
                <div>
                  <div className="ls-title">AUTO-METADATA</div>
                  <div className="ls-sub">Generert av synthesis-laget</div>
                </div>
              </div>
            </div>
            <div className="aa-meta">
              <div className="aam-row">
                <span className="aam-k">TITTEL</span>
                <div className="aam-v">
                  <div className="aam-text">{clip.metadata.title}</div>
                  <div className="aam-conf"><span className="cc-pip" style={{background: tweaks.accent}}/>{Math.round(clip.metadata.titleConfidence*100)}%</div>
                </div>
              </div>
              <div className="aam-row">
                <span className="aam-k">BESKRIVELSE</span>
                <div className="aam-v">
                  <div className="aam-text small">"{clip.metadata.description}"</div>
                  <div className="aam-conf"><span className="cc-pip" style={{background: tweaks.accent}}/>{Math.round(clip.metadata.descConfidence*100)}%</div>
                </div>
              </div>
              <div className="aam-row">
                <span className="aam-k">KATEGORI</span>
                <div className="aam-v">
                  <span className="aam-pill big" style={{borderColor: tweaks.accent, color: tweaks.accent}}>{clip.metadata.category}</span>
                  <div className="aam-conf"><span className="cc-pip" style={{background: tweaks.accent}}/>{Math.round(clip.metadata.categoryConfidence*100)}%</div>
                </div>
              </div>
              <div className="aam-row">
                <span className="aam-k">TAGGER</span>
                <div className="aam-tags">
                  {clip.metadata.tags.map(t => (
                    <span key={t} className="aam-tag">{t}</span>
                  ))}
                </div>
              </div>
              <div className="aam-grid">
                <div><span>VÅPEN</span><b>{clip.metadata.weapon}</b></div>
                <div><span>STED</span><b>{clip.metadata.location}</b></div>
                <div><span>KILLS</span><b style={{color: tweaks.accent}}>{clip.metadata.killCount}</b></div>
                <div><span>SNITT AVST</span><b>{clip.metadata.avgDistance}m</b></div>
              </div>
            </div>
          </div>

          {/* Recommendation + actions */}
          <div className="panel compact aa-recommend" style={{borderColor: tweaks.accent}}>
            <div className="aar-eyebrow">ANBEFALING · AGENT</div>
            <div className="aar-decision" style={{color: tweaks.accent}}>
              <span className="aar-icon">★</span>
              {clip.recommendation.publishDecision}
            </div>
            <div className="aar-score">
              <span>OVERALL</span>
              <b style={{color: tweaks.accent}}>{overallScore}</b>
              <span>/ 10 · {Math.round(clip.recommendation.decisionConfidence*100)}% sikker</span>
            </div>
            <div className="aar-similar">
              <span>LIGNENDE KLIPP</span>
              <div className="aars-list">
                {clip.recommendation.similarClips.map(c => (
                  <span key={c} className="aars-pill">{c.slice(-4)}</span>
                ))}
              </div>
            </div>
            <div className="aar-actions">
              <button className="cta cta-primary" style={{background: tweaks.accent, borderColor: tweaks.accent}}>
                <span>✓ FEATURE PÅ FORSIDE</span>
              </button>
              <button className="ghost-btn">✓ GODKJENN</button>
              <button className="ghost-btn">⟳ REGENERER</button>
              <button className="ghost-btn warn">✗ AVVIS</button>
            </div>
          </div>

          {/* Queue */}
          <div className="panel compact">
            <div className="ls-head">
              <div className="ls-head-l">
                <div className="section-code" style={{borderColor: tweaks.accent}}>Q01</div>
                <div>
                  <div className="ls-title">KØ · NYLIGE</div>
                  <div className="ls-sub">{queue.length} klipp · siste 2 timer</div>
                </div>
              </div>
            </div>
            <div className="aaq-list">
              {queue.map(q => {
                const isSelected = q.clip === selectedClip;
                const isDone = q.status === "DONE";
                const isFailed = q.decision === "REJECT";
                return (
                  <button
                    key={q.id}
                    className={`aaq-row ${isSelected ? "selected" : ""} ${isFailed ? "failed" : ""}`}
                    style={isSelected ? {borderColor: tweaks.accent} : null}
                    onClick={() => setSelectedClip(q.clip)}
                  >
                    <div className="aaq-top">
                      <span className="aaq-time">{q.time}</span>
                      <span className="team-tag" style={{borderColor: tweaks.accent, color: tweaks.accent}}>{q.team}</span>
                      <span className="aaq-player">{q.player}</span>
                      {q.score !== null && (
                        <span className="aaq-score" style={{color: tweaks.accent}}>{q.score}</span>
                      )}
                    </div>
                    <div className="aaq-title">{q.title}</div>
                    <div className="aaq-bot">
                      <div className="aaq-prog">
                        <div className="aaq-prog-bar" style={{width: `${q.progress}%`, background: isFailed ? "var(--bad)" : tweaks.accent}} />
                      </div>
                      <span className={`aaq-status status-${q.status.toLowerCase()}`} style={q.status === "JUDGING" ? {color: tweaks.accent} : null}>
                        {isDone ? q.decision : q.status} {!isDone && `· ${q.progress}%`}
                      </span>
                    </div>
                    {q.flag && (
                      <div className="aaq-flag">⚠ {q.flag}</div>
                    )}
                  </button>
                );
              })}
            </div>
          </div>
        </div>
      </div>

      {/* Bottom: monitoring chart */}
      <div className="dual">
        <div className="panel">
          <SectionHeader
            code="V01"
            title="VOLUM · 14 DAGER"
            subtitle="Klipp prosessert per dag"
            accent={tweaks.accent}
          />
          <div className="aa-chart">
            {dailyVol.map((v, i) => {
              const max = Math.max(...dailyVol);
              const h = (v / max) * 100;
              const isToday = i === dailyVol.length - 1;
              return (
                <div key={i} className="aac-col">
                  <div className="aac-bar" style={{height: `${h}%`, background: isToday ? tweaks.accent : null}}>
                    <span className="aac-val">{v}</span>
                  </div>
                  <div className="aac-lab">D-{dailyVol.length - 1 - i}</div>
                </div>
              );
            })}
          </div>
          <div className="aa-chart-foot">
            <div><span>SNITT</span><b>{Math.round(dailyVol.reduce((s,v) => s+v, 0)/dailyVol.length)}/dag</b></div>
            <div><span>PEAK</span><b>{Math.max(...dailyVol)}</b></div>
            <div><span>VEKST 7D</span><b style={{color: tweaks.accent}}>+18%</b></div>
            <div><span>UPTIME</span><b>99.7%</b></div>
          </div>
        </div>

        <div className="panel">
          <SectionHeader
            code="K01"
            title="MODELL-KONFIG"
            subtitle="Aktive vekter og guardrails"
            accent={tweaks.accent}
            right={<button className="ghost-btn small">REDIGER ↗</button>}
          />
          <div className="aa-config">
            <div className="aac-section">
              <div className="aac-section-label">SCORING-VEKTER</div>
              <div className="aac-weights">
                {[
                  { k:"Vanskelighet", v: 0.35 },
                  { k:"Eksekvering",  v: 0.30 },
                  { k:"Hype",         v: 0.20 },
                  { k:"Originalitet", v: 0.15 },
                ].map(w => (
                  <div key={w.k} className="aacw-row">
                    <span>{w.k}</span>
                    <div className="aacw-bar"><div className="aacw-fill" style={{width: `${w.v*100}%`, background: tweaks.accent}}/></div>
                    <b>{(w.v*100).toFixed(0)}%</b>
                  </div>
                ))}
              </div>
            </div>
            <div className="aac-section">
              <div className="aac-section-label">GUARDRAILS</div>
              <div className="aac-guards">
                <div className="aacg"><span className="aacg-dot" style={{background: tweaks.accent}}/>Maks 1 klipp per spiller per matchday</div>
                <div className="aacg"><span className="aacg-dot" style={{background: tweaks.accent}}/>Auto-flag hvis cheat-indikator &gt; 0.4</div>
                <div className="aacg"><span className="aacg-dot" style={{background: tweaks.accent}}/>Krev admin-godkjenning hvis konfidens &lt; 70%</div>
                <div className="aacg"><span className="aacg-dot" style={{background: tweaks.accent}}/>Dedup mot similarity-cluster &gt; 0.85</div>
                <div className="aacg"><span className="aacg-dot" style={{background: tweaks.accent}}/>Maks 3 featured klipp per dag</div>
              </div>
            </div>
            <div className="aac-section">
              <div className="aac-section-label">FEEDBACK-LOOP</div>
              <p className="aac-fb">
                Community-voting brukes som ground-truth: hvis et klipp får &lt; 30% av forventet voting basert på AI-score, blir det merket som mis-classified og fôret tilbake i fine-tune-køen. Modellen re-trenes hver søndag.
              </p>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

Object.assign(window, { AIHighlightAgent });

// ---------- Helpers ----------
const sleep = (ms) => new Promise(r => setTimeout(r, ms));

// Extract N evenly-spaced frames from a video file using <video> + canvas
async function extractFrames(file, count = 9) {
  return new Promise((resolve, reject) => {
    const video = document.createElement("video");
    video.preload = "auto";
    video.muted = true;
    video.playsInline = true;
    video.src = URL.createObjectURL(file);

    const cleanup = () => URL.revokeObjectURL(video.src);

    video.addEventListener("error", (e) => { cleanup(); reject(new Error("Kunne ikke lese videofilen.")); });

    video.addEventListener("loadedmetadata", async () => {
      const duration = video.duration || 1;
      const W = 360;
      const H = Math.round((W * (video.videoHeight || 9)) / (video.videoWidth || 16));
      const canvas = document.createElement("canvas");
      canvas.width = W; canvas.height = H;
      const ctx = canvas.getContext("2d");

      const frames = [];
      try {
        for (let i = 0; i < count; i++) {
          const t = (i / (count - 1 || 1)) * Math.max(0, duration - 0.05);
          await new Promise((res, rej) => {
            const onSeek = () => { video.removeEventListener("seeked", onSeek); res(); };
            video.addEventListener("seeked", onSeek, { once: true });
            try { video.currentTime = t; } catch (e) { rej(e); }
          });
          ctx.drawImage(video, 0, 0, W, H);
          frames.push({ t, dataUrl: canvas.toDataURL("image/jpeg", 0.7) });
        }
        resolve({
          frames,
          duration,
          width: video.videoWidth,
          height: video.videoHeight,
        });
      } catch (e) {
        cleanup();
        reject(e);
      }
    });
  });
}

// Call LLM to generate a plausible highlight evaluation
async function callClipJudge({ fileName, duration, width, height }) {
  const prompt = `Du er en AI-agent som vurderer Call of Duty: Warzone highlight-klipp for WZN League (norsk esports-liga).

Generer en plausibel, spesifikk vurdering av dette klippet. Du har KUN tilgang til metadata, men oppfør deg som om du har analysert frames og lyd. Vær konkret med våpen, sted i Verdansk, antall kills, kontekst.

Metadata:
- Filnavn: ${fileName}
- Varighet: ${duration.toFixed(1)} sekunder
- Oppløsning: ${width}×${height}

Returner KUN gyldig JSON (ingen markdown, ingen forklaring rundt). Bruk norsk i alle tekstfelt. Format:

{
  "title": "ZRO_lars90 — KORT BESKRIVELSE I VERSALER (4-10 ord)",
  "description": "2-3 setninger som beskriver hva som skjer i klippet, på norsk.",
  "category": "CLUTCH" | "FRAG" | "COMEBACK" | "FUNNY" | "PLAY",
  "tags": ["array", "av", "5-8", "korte", "lowercase", "tags"],
  "weapon": "f.eks. SVA-545 eller MCW-12",
  "location": "f.eks. Storage Town",
  "killCount": tall (0-12),
  "avgDistance": tall i meter,
  "scores": {
    "difficulty":  { "value": tall 0-10, "confidence": tall 0-1, "reasoning": "en setning på norsk" },
    "execution":   { "value": tall 0-10, "confidence": tall 0-1, "reasoning": "en setning på norsk" },
    "hype":        { "value": tall 0-10, "confidence": tall 0-1, "reasoning": "en setning på norsk" },
    "originality": { "value": tall 0-10, "confidence": tall 0-1, "reasoning": "en setning på norsk" }
  },
  "events": [
    { "t": tall i sekunder, "type": "kill"|"audio"|"movement"|"item", "label": "beskrivelse på norsk", "confidence": tall 0-1 }
  ],
  "recommendation": "FEATURE" | "APPROVE" | "REJECT",
  "flags": []
}

Lag 6-10 events fordelt over varigheten på ${duration.toFixed(1)}s. Gjør scoring realistisk — ikke alt over 8.0. Hvis filnavnet hinter til innhold, bruk det.`;

  if (typeof window.claude?.complete !== "function") throw new Error("window.claude ikke tilgjengelig");
  const raw = await window.claude.complete(prompt);
  // Strip code fences if present, then parse
  const cleaned = raw.replace(/```json\s*/i, "").replace(/```\s*$/i, "").trim();
  const firstBrace = cleaned.indexOf("{");
  const lastBrace = cleaned.lastIndexOf("}");
  const json = cleaned.slice(firstBrace, lastBrace + 1);
  return JSON.parse(json);
}

// ---------- Upload strip component ----------
const UploadStrip = ({ onFile, onPickClick, fileInputRef, uploaded, analysis, pipelineStep, error, onReset, accent, stages }) => {
  const [dragOver, setDragOver] = useState(false);
  const onDrop = (e) => {
    e.preventDefault();
    setDragOver(false);
    const f = e.dataTransfer.files?.[0];
    if (f) onFile(f);
  };

  const processing = pipelineStep >= 0;
  const done = uploaded && analysis && !processing;
  const stageName = processing && stages[pipelineStep] ? stages[pipelineStep].name : null;

  return (
    <div className="upload-strip" style={done ? {borderColor: accent} : null}>
      <input
        ref={fileInputRef}
        type="file"
        accept="video/mp4,video/quicktime,video/webm,video/*"
        style={{display:"none"}}
        onChange={(e) => { const f = e.target.files?.[0]; if (f) onFile(f); }}
      />

      {!uploaded && !processing && (
        <div
          className={`upload-drop ${dragOver ? "over" : ""}`}
          onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
          onDragLeave={() => setDragOver(false)}
          onDrop={onDrop}
          onClick={onPickClick}
          style={dragOver ? {borderColor: accent} : null}
        >
          <div className="ud-left">
            <div className="ud-icon" style={{color: accent, borderColor: accent}}>↑</div>
            <div>
              <div className="ud-title">LAST OPP ET KLIPP FOR LIVE-ANALYSE</div>
              <div className="ud-sub">Dra inn .mp4 / .mov / .webm · eller klikk for å velge fil</div>
            </div>
          </div>
          <div className="ud-right">
            <div className="ud-tech">
              <div className="ud-tech-row"><span>FRAMES</span><b>EKTE</b></div>
              <div className="ud-tech-row"><span>METADATA</span><b>EKTE</b></div>
              <div className="ud-tech-row"><span>SCORING</span><b style={{color: accent}}>LLM</b></div>
            </div>
            <button className="cta cta-primary" style={{background: accent, borderColor: accent}}>
              <span>VELG FIL</span> <span>↗</span>
            </button>
          </div>
        </div>
      )}

      {processing && (
        <div className="upload-progress">
          <div className="up-head">
            <div className="up-spinner-wrap">
              <div className="up-spinner" style={{borderTopColor: accent}}/>
            </div>
            <div className="up-text">
              <div className="up-title">ANALYSERER · {stageName}</div>
              <div className="up-sub">{uploaded ? uploaded.fileName : "Leser fil..."}</div>
            </div>
            <button className="ghost-btn warn" onClick={onReset}>AVBRYT</button>
          </div>
          <div className="up-stages">
            {stages.map((s, i) => {
              const isActive = i === pipelineStep;
              const isDone = i < pipelineStep;
              return (
                <div key={s.id} className={`up-stage ${isActive ? "active" : ""} ${isDone ? "done" : ""}`}>
                  <span className="ups-num" style={(isActive || isDone) ? {color: accent} : null}>{s.icon}</span>
                  <span className="ups-name">{s.name}</span>
                  {isDone && <span className="ups-check" style={{color: accent}}>✓</span>}
                  {isActive && <span className="ups-pulse" style={{background: accent}}/>}
                </div>
              );
            })}
          </div>
        </div>
      )}

      {done && (
        <div className="upload-done">
          <div className="ud-done-l">
            <span className="ud-done-check" style={{color: accent, borderColor: accent}}>✓</span>
            <div>
              <div className="ud-done-title">ANALYSE FULLFØRT · {uploaded.fileName}</div>
              <div className="ud-done-sub">
                {(uploaded.fileSize/1024/1024).toFixed(1)} MB · {uploaded.width}×{uploaded.height} · {uploaded.duration.toFixed(1)}s
                <span className="dot-sep"> · </span>
                Total score <b style={{color: accent}}>{((analysis.scores.difficulty.value + analysis.scores.execution.value + analysis.scores.hype.value + analysis.scores.originality.value)/4).toFixed(1)}</b>/10
                <span className="dot-sep"> · </span>
                Anbefaling: <b style={{color: accent}}>{analysis.recommendation}</b>
              </div>
            </div>
          </div>
          <div className="ud-done-r">
            <button className="ghost-btn" onClick={() => onPickClick()}>↑ NYTT KLIPP</button>
            <button className="ghost-btn" onClick={onReset}>NULLSTILL</button>
          </div>
        </div>
      )}

      {error && (
        <div className="upload-error">
          <span>⚠</span>
          <span>{error}</span>
          <button className="ghost-btn small" onClick={onReset}>LUKK</button>
        </div>
      )}

      <div className="upload-disclaimer">
        <span style={{color: accent}}>● </span>
        DEMO: Ekte frame-uttrekking + metadata · multimodal scoring genereres av LLM basert på filinformasjon (vil ikke fungere offline).
      </div>
    </div>
  );
};

Object.assign(window, { UploadStrip });
