(function () {
  'use strict';

  const tk = {
    bgPage: '#0f0f0f', bgCard: '#1a1a1a', bgCardAlt: '#141414', bgInput: '#111',
    bgHover: '#222', bgSunken: '#0a0a0a', bgOverlay: 'rgba(0,0,0,0.75)',
    border: '#2a2a2a', borderSubtle: '#1e1e1e',
    textPrimary: '#f5f5f5', textSecondary: '#aaaaaa', textMuted: '#666',
    textDisabled: '#444', accent: '#00ff00', accentText: '#000',
    error: '#ff4444',
  };

  // ── Stubs ────────────────────────────────────────────────────────────────────

  function generateId() { return 'cap-' + Date.now() + '-' + Math.random().toString(36).slice(2, 7); }

  function parseSRT(text) {
    const blocks = text.trim().split(/\n\n+/);
    const result = [];
    blocks.forEach(block => {
      const lines = block.split('\n');
      if (lines.length < 2) return;
      const timeLine = lines.find(l => l.includes('-->'));
      if (!timeLine) return;
      const timeMatch = timeLine.match(/(\d+:\d+:\d+[,.:]\d+)\s*-->\s*(\d+:\d+:\d+[,.:]\d+)/);
      if (!timeMatch) return;
      const parseTime = s => {
        const parts = s.replace(',', '.').split(':');
        return parseFloat(parts[0]) * 3600 + parseFloat(parts[1]) * 60 + parseFloat(parts[2]);
      };
      const textLines = lines.slice(lines.indexOf(timeLine) + 1).join(' ').trim();
      if (!textLines) return;
      result.push({ startTime: parseTime(timeMatch[1]), endTime: parseTime(timeMatch[2]), text: textLines });
    });
    return result;
  }

  function parseVTT(text) {
    return parseSRT(text.replace(/^WEBVTT\n/, ''));
  }

  function parseSCC() { return []; }

  function computeDefaultOverlayFontSizePx(height) { return Math.round((height || 1080) * 0.045); }

  // ── Helpers ──────────────────────────────────────────────────────────────────

  const WORD_MIN_DURATION = 0.001;

  const formatTimecode = (value) => {
    const safe = Number.isFinite(value) ? Math.max(0, value) : 0;
    const minutes = Math.floor(safe / 60);
    const seconds = safe - minutes * 60;
    return `${String(minutes).padStart(2, '0')}:${seconds.toFixed(2).padStart(5, '0')}`;
  };

  const css = `
    .vls-ed-cs { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: ${tk.bgCard}; color: ${tk.textPrimary}; display: flex; flex-direction: column; min-height: 0; }
    .vls-ed-cs-tabs { display: flex; border-bottom: 1px solid ${tk.border}; background: ${tk.bgCardAlt}; flex-shrink: 0; }
    .vls-ed-cs-tab { flex: 1; padding: 9px 4px; background: transparent; border: none; border-bottom: 2px solid transparent; color: ${tk.textMuted}; font-size: 11px; font-weight: 600; text-transform: uppercase; cursor: pointer; }
    .vls-ed-cs-tab.active { background: ${tk.bgCard}; border-bottom-color: ${tk.accent}; color: ${tk.accent}; }
    .vls-ed-cs-body { padding: 0; overflow-y: auto; flex: 1; min-height: 0; }
    .vls-ed-cs-section { padding: 12px 14px; border-bottom: 1px solid ${tk.border}; }
    .vls-ed-cs-section-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: ${tk.textMuted}; margin-bottom: 10px; }
    .vls-ed-cs-caption-item { padding: 10px 12px; background: ${tk.bgCardAlt}; border-radius: 6px; border: 1px solid ${tk.border}; margin-bottom: 6px; cursor: pointer; transition: border-color 0.15s; }
    .vls-ed-cs-caption-item:hover { border-color: ${tk.bgHover}; }
    .vls-ed-cs-caption-item.active { border-color: rgba(0,255,0,0.4); background: rgba(0,255,0,0.04); }
    .vls-ed-cs-caption-time { font-size: 10px; color: ${tk.textMuted}; font-family: monospace; margin-bottom: 4px; display: flex; justify-content: space-between; align-items: center; }
    .vls-ed-cs-caption-text { font-size: 13px; color: ${tk.textSecondary}; line-height: 1.4; }
    .vls-ed-cs-caption-text textarea { width: 100%; box-sizing: border-box; background: ${tk.bgInput}; border: 1px solid ${tk.border}; border-radius: 4px; color: ${tk.textPrimary}; font-size: 13px; padding: 6px 8px; resize: vertical; outline: none; font-family: inherit; }
    .vls-ed-cs-btn { padding: 7px 12px; border-radius: 5px; border: 1px solid ${tk.border}; background: ${tk.bgHover}; color: ${tk.textSecondary}; font-size: 12px; font-weight: 600; cursor: pointer; }
    .vls-ed-cs-btn:hover { background: #2a2a2a; color: ${tk.textPrimary}; }
    .vls-ed-cs-btn.primary { background: ${tk.accent}; color: #000; border-color: ${tk.accent}; }
    .vls-ed-cs-btn.danger { border-color: rgba(255,68,68,0.4); color: ${tk.error}; background: transparent; }
    .vls-ed-cs-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
    .vls-ed-cs-label { font-size: 12px; color: ${tk.textMuted}; min-width: 90px; }
    .vls-ed-cs-input { flex: 1; padding: 6px 8px; background: ${tk.bgInput}; border: 1px solid ${tk.border}; border-radius: 4px; color: ${tk.textPrimary}; font-size: 12px; outline: none; }
    .vls-ed-cs-input:focus { border-color: rgba(0,255,0,0.4); }
    .vls-ed-cs-range { flex: 1; accentColor: #00ff00; cursor: pointer; }
    .vls-ed-cs-select { padding: 6px 8px; background: ${tk.bgInput}; border: 1px solid ${tk.border}; border-radius: 4px; color: ${tk.textPrimary}; font-size: 12px; outline: none; cursor: pointer; }
  `;

  function CaptionsSidebarReal() {
    const [activeTab, setActiveTab] = React.useState('captions');
    const [captions, setCaptions] = React.useState([
      { id: 'cap-1', startTime: 0.5, endTime: 3.0, text: 'Welcome to the demo.' },
      { id: 'cap-2', startTime: 3.5, endTime: 6.5, text: 'This is the captions panel.' },
      { id: 'cap-3', startTime: 7.0, endTime: 10.0, text: 'You can add, edit, and style captions here.' },
    ]);
    const [currentTime, setCurrentTime] = React.useState(0);
    const [editingId, setEditingId] = React.useState(null);
    const [editText, setEditText] = React.useState('');
    const [isGenerating, setIsGenerating] = React.useState(false);
    const [language, setLanguage] = React.useState('en');
    const [captionStyle, setCaptionStyle] = React.useState({
      fontFamily: 'Arial',
      fontSize: 48,
      fontWeight: 'bold',
      color: '#ffffff',
      backgroundColor: 'rgba(0,0,0,0.7)',
      alignment: 'center',
      position: 'bottom',
      outline: 1,
      outlineColor: '#000000',
    });
    const importFileInputRef = React.useRef(null);

    const activeSegmentIndex = React.useMemo(() => {
      for (let i = 0; i < captions.length; i++) {
        if (currentTime >= captions[i].startTime && currentTime < captions[i].endTime) return i;
      }
      return -1;
    }, [captions, currentTime]);

    const addCaption = () => {
      const lastEnd = captions.length > 0 ? captions[captions.length - 1].endTime : 0;
      const newCap = { id: generateId(), startTime: lastEnd + 0.5, endTime: lastEnd + 3.5, text: 'New caption' };
      setCaptions(prev => [...prev, newCap].sort((a, b) => a.startTime - b.startTime));
      setEditingId(newCap.id);
      setEditText(newCap.text);
    };

    const removeCaption = (id) => {
      setCaptions(prev => prev.filter(c => c.id !== id));
      if (editingId === id) { setEditingId(null); setEditText(''); }
    };

    const updateCaption = (id, patch) => {
      setCaptions(prev => prev.map(c => c.id === id ? { ...c, ...patch } : c));
    };

    const startEdit = (cap) => {
      setEditingId(cap.id);
      setEditText(cap.text);
    };

    const finishEdit = () => {
      if (editingId) updateCaption(editingId, { text: editText });
      setEditingId(null);
      setEditText('');
    };

    const handleAutoTranscribe = () => {
      setIsGenerating(true);
      setTimeout(() => {
        const mockCaps = [
          { id: generateId(), startTime: 0, endTime: 2.5, text: 'Hello, this is auto-generated.' },
          { id: generateId(), startTime: 3, endTime: 5.5, text: 'Transcription works in the desktop app.' },
          { id: generateId(), startTime: 6, endTime: 9, text: 'This is a demo preview only.' },
        ];
        setCaptions(mockCaps);
        setIsGenerating(false);
      }, 1500);
    };

    const handleImportFile = (e) => {
      const file = e.target.files?.[0];
      if (!file) return;
      const reader = new FileReader();
      reader.onload = (ev) => {
        const text = ev.target.result;
        let parsed = [];
        if (file.name.endsWith('.srt')) parsed = parseSRT(text);
        else if (file.name.endsWith('.vtt')) parsed = parseVTT(text);
        else if (file.name.endsWith('.scc')) parsed = parseSCC(text);
        if (parsed.length > 0) {
          setCaptions(parsed.map(c => ({ ...c, id: generateId() })));
        } else {
          alert('Could not parse caption file. Supported: .srt, .vtt');
        }
      };
      reader.readAsText(file);
      e.target.value = '';
    };

    const exportSRT = () => {
      const lines = captions.map((c, i) => {
        const fmtTime = (s) => { const h = Math.floor(s/3600); const m = Math.floor((s%3600)/60); const sec = Math.floor(s%60); const ms = Math.round((s%1)*1000); return `${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')}:${String(sec).padStart(2,'0')},${String(ms).padStart(3,'0')}`; };
        return `${i+1}\n${fmtTime(c.startTime)} --> ${fmtTime(c.endTime)}\n${c.text}\n`;
      });
      const blob = new Blob([lines.join('\n')], { type: 'text/plain' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a'); a.href = url; a.download = 'captions.srt'; a.click();
      URL.revokeObjectURL(url);
    };

    return (
      <div className="vls-ed-cs">
        <style>{css}</style>
        <div style={{ padding: '10px 14px', borderBottom: `1px solid ${tk.border}`, fontSize: 13, fontWeight: 700, color: tk.accent, flexShrink: 0 }}>
          Captions
        </div>

        {/* Current time scrubber (demo) */}
        <div style={{ padding: '8px 14px', borderBottom: `1px solid ${tk.border}`, background: tk.bgCardAlt, flexShrink: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <span style={{ fontSize: 11, color: tk.textMuted }}>Time:</span>
            <input type="range" min={0} max={15} step={0.1} value={currentTime} onChange={e => setCurrentTime(Number(e.target.value))} style={{ flex: 1, accentColor: '#00ff00' }} />
            <span style={{ fontSize: 11, color: tk.accent, fontFamily: 'monospace', minWidth: 50 }}>{formatTimecode(currentTime)}</span>
          </div>
        </div>

        <div className="vls-ed-cs-tabs">
          {['captions', 'style', 'import'].map(tab => (
            <button key={tab} className={`vls-ed-cs-tab${activeTab === tab ? ' active' : ''}`} onClick={() => setActiveTab(tab)}>{tab}</button>
          ))}
        </div>

        <div className="vls-ed-cs-body">
          {/* Captions Tab */}
          {activeTab === 'captions' && (
            <div>
              <div className="vls-ed-cs-section">
                <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                  <button className="vls-ed-cs-btn primary" onClick={addCaption}>+ Add Caption</button>
                  <button className="vls-ed-cs-btn" onClick={handleAutoTranscribe} disabled={isGenerating}>
                    {isGenerating ? 'Generating...' : '✦ Auto Transcribe'}
                  </button>
                  <button className="vls-ed-cs-btn" onClick={exportSRT} disabled={captions.length === 0}>Export SRT</button>
                </div>
              </div>

              <div className="vls-ed-cs-section">
                <div className="vls-ed-cs-section-title">Captions ({captions.length})</div>
                {captions.length === 0 && (
                  <div style={{ color: tk.textDisabled, fontSize: 12, textAlign: 'center', padding: '20px 0' }}>No captions yet</div>
                )}
                {captions.map((cap, i) => {
                  const isActive = activeSegmentIndex === i;
                  const isEditing = editingId === cap.id;
                  return (
                    <div key={cap.id} className={`vls-ed-cs-caption-item${isActive ? ' active' : ''}`} onClick={() => !isEditing && setCurrentTime(cap.startTime)}>
                      <div className="vls-ed-cs-caption-time">
                        <span>{formatTimecode(cap.startTime)} → {formatTimecode(cap.endTime)}</span>
                        <div style={{ display: 'flex', gap: 4 }}>
                          <button onClick={e => { e.stopPropagation(); startEdit(cap); }} className="vls-ed-cs-btn" style={{ padding: '2px 8px', fontSize: 10 }}>Edit</button>
                          <button onClick={e => { e.stopPropagation(); removeCaption(cap.id); }} className="vls-ed-cs-btn danger" style={{ padding: '2px 8px', fontSize: 10 }}>✕</button>
                        </div>
                      </div>
                      {isEditing ? (
                        <div>
                          <div style={{ display: 'flex', gap: 4, marginBottom: 6 }}>
                            <input type="number" value={cap.startTime.toFixed(2)} min={0} step={0.1} onChange={e => updateCaption(cap.id, { startTime: parseFloat(e.target.value) || 0 })} style={{ width: 70, padding: '3px 5px', background: tk.bgInput, border: `1px solid ${tk.border}`, borderRadius: 3, color: tk.textPrimary, fontSize: 11 }} />
                            <span style={{ color: tk.textMuted, alignSelf: 'center' }}>→</span>
                            <input type="number" value={cap.endTime.toFixed(2)} min={0} step={0.1} onChange={e => updateCaption(cap.id, { endTime: parseFloat(e.target.value) || 0 })} style={{ width: 70, padding: '3px 5px', background: tk.bgInput, border: `1px solid ${tk.border}`, borderRadius: 3, color: tk.textPrimary, fontSize: 11 }} />
                          </div>
                          <div className="vls-ed-cs-caption-text">
                            <textarea
                              autoFocus
                              rows={2}
                              value={editText}
                              onChange={e => setEditText(e.target.value)}
                              onBlur={finishEdit}
                              onKeyDown={e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); finishEdit(); } }}
                            />
                          </div>
                        </div>
                      ) : (
                        <div className="vls-ed-cs-caption-text">{cap.text}</div>
                      )}
                    </div>
                  );
                })}
              </div>
            </div>
          )}

          {/* Style Tab */}
          {activeTab === 'style' && (
            <div>
              <div className="vls-ed-cs-section">
                <div className="vls-ed-cs-section-title">Caption Style</div>

                {/* Preview */}
                <div style={{ marginBottom: 14, background: '#1a1a2e', borderRadius: 8, height: 80, display: 'flex', alignItems: captionStyle.position === 'top' ? 'flex-start' : 'flex-end', justifyContent: 'center', padding: 8, border: `1px solid ${tk.border}` }}>
                  <span style={{ fontFamily: captionStyle.fontFamily, fontSize: Math.round(captionStyle.fontSize * 0.35), fontWeight: captionStyle.fontWeight, color: captionStyle.color, background: captionStyle.backgroundColor, padding: '2px 8px', borderRadius: 3, textShadow: captionStyle.outline > 0 ? `0 0 ${captionStyle.outline}px ${captionStyle.outlineColor}` : 'none', textAlign: captionStyle.alignment }}>
                    {captions[0]?.text || 'Sample Caption'}
                  </span>
                </div>

                <div className="vls-ed-cs-row">
                  <span className="vls-ed-cs-label">Font</span>
                  <select className="vls-ed-cs-select" style={{ flex: 1 }} value={captionStyle.fontFamily} onChange={e => setCaptionStyle(prev => ({ ...prev, fontFamily: e.target.value }))}>
                    {['Arial', 'Verdana', 'Georgia', 'Impact', 'Courier New', 'Times New Roman'].map(f => <option key={f} value={f}>{f}</option>)}
                  </select>
                </div>

                <div className="vls-ed-cs-row">
                  <span className="vls-ed-cs-label">Font Size</span>
                  <input type="range" min={20} max={120} step={2} value={captionStyle.fontSize} onChange={e => setCaptionStyle(prev => ({ ...prev, fontSize: Number(e.target.value) }))} className="vls-ed-cs-range" />
                  <span style={{ fontSize: 11, color: tk.textSecondary, minWidth: 35 }}>{captionStyle.fontSize}px</span>
                </div>

                <div className="vls-ed-cs-row">
                  <span className="vls-ed-cs-label">Weight</span>
                  <select className="vls-ed-cs-select" value={captionStyle.fontWeight} onChange={e => setCaptionStyle(prev => ({ ...prev, fontWeight: e.target.value }))}>
                    {['normal', 'bold', '600', '700', '800'].map(w => <option key={w} value={w}>{w}</option>)}
                  </select>
                </div>

                <div className="vls-ed-cs-row">
                  <span className="vls-ed-cs-label">Text Color</span>
                  <input type="color" value={captionStyle.color} onChange={e => setCaptionStyle(prev => ({ ...prev, color: e.target.value }))} style={{ width: 40, height: 28, padding: 2, background: tk.bgInput, border: `1px solid ${tk.border}`, borderRadius: 4, cursor: 'pointer' }} />
                  <span style={{ fontSize: 11, color: tk.textMuted }}>{captionStyle.color}</span>
                </div>

                <div className="vls-ed-cs-row">
                  <span className="vls-ed-cs-label">Background</span>
                  <input type="color" value={captionStyle.outlineColor} onChange={e => setCaptionStyle(prev => ({ ...prev, outlineColor: e.target.value }))} style={{ width: 40, height: 28, padding: 2, background: tk.bgInput, border: `1px solid ${tk.border}`, borderRadius: 4, cursor: 'pointer' }} />
                  <select className="vls-ed-cs-select" value={captionStyle.backgroundColor} onChange={e => setCaptionStyle(prev => ({ ...prev, backgroundColor: e.target.value }))} style={{ flex: 1 }}>
                    {['rgba(0,0,0,0.7)', 'rgba(0,0,0,0)', 'rgba(0,0,0,0.9)', 'rgba(255,255,255,0.15)'].map(v => <option key={v} value={v}>{v}</option>)}
                  </select>
                </div>

                <div className="vls-ed-cs-row">
                  <span className="vls-ed-cs-label">Alignment</span>
                  <select className="vls-ed-cs-select" value={captionStyle.alignment} onChange={e => setCaptionStyle(prev => ({ ...prev, alignment: e.target.value }))}>
                    {['left', 'center', 'right'].map(a => <option key={a} value={a}>{a}</option>)}
                  </select>
                </div>

                <div className="vls-ed-cs-row">
                  <span className="vls-ed-cs-label">Position</span>
                  <select className="vls-ed-cs-select" value={captionStyle.position} onChange={e => setCaptionStyle(prev => ({ ...prev, position: e.target.value }))}>
                    {['bottom', 'top', 'middle'].map(p => <option key={p} value={p}>{p}</option>)}
                  </select>
                </div>

                <div className="vls-ed-cs-row">
                  <span className="vls-ed-cs-label">Outline</span>
                  <input type="range" min={0} max={5} step={0.5} value={captionStyle.outline} onChange={e => setCaptionStyle(prev => ({ ...prev, outline: Number(e.target.value) }))} className="vls-ed-cs-range" />
                  <span style={{ fontSize: 11, color: tk.textSecondary, minWidth: 25 }}>{captionStyle.outline}px</span>
                </div>
              </div>
            </div>
          )}

          {/* Import Tab */}
          {activeTab === 'import' && (
            <div>
              <div className="vls-ed-cs-section">
                <div className="vls-ed-cs-section-title">Import Captions</div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                  <button className="vls-ed-cs-btn" onClick={() => importFileInputRef.current?.click()} style={{ padding: '10px', textAlign: 'center' }}>
                    📂 Import .srt / .vtt file
                  </button>
                  <input ref={importFileInputRef} type="file" accept=".srt,.vtt,.scc" style={{ display: 'none' }} onChange={handleImportFile} />
                  <div style={{ fontSize: 11, color: tk.textMuted, lineHeight: 1.5 }}>
                    Supports SubRip (.srt) and WebVTT (.vtt) files.<br />
                    SCC support requires the desktop app.
                  </div>
                </div>
              </div>

              <div className="vls-ed-cs-section">
                <div className="vls-ed-cs-section-title">Auto Transcription</div>
                <div style={{ marginBottom: 10 }}>
                  <div className="vls-ed-cs-row">
                    <span className="vls-ed-cs-label">Language</span>
                    <select className="vls-ed-cs-select" value={language} onChange={e => setLanguage(e.target.value)}>
                      {[['en','English'],['es','Spanish'],['fr','French'],['de','German'],['it','Italian'],['pt','Portuguese'],['ja','Japanese'],['zh','Chinese']].map(([v,l]) => <option key={v} value={v}>{l}</option>)}
                    </select>
                  </div>
                </div>
                <button className="vls-ed-cs-btn primary" onClick={handleAutoTranscribe} disabled={isGenerating} style={{ width: '100%', padding: 10 }}>
                  {isGenerating ? '⏳ Transcribing... (demo)' : '✦ Auto Transcribe (demo)'}
                </button>
                <div style={{ fontSize: 11, color: tk.textMuted, marginTop: 6, lineHeight: 1.5 }}>
                  Full AI transcription (Whisper) requires the desktop app.<br />
                  Demo generates mock captions after 1.5s.
                </div>
              </div>
            </div>
          )}
        </div>
      </div>
    );
  }

  window.CaptionsSidebarReal = CaptionsSidebarReal;
})();
