/* Multiligo Social Studio — Karikatür (comic-strip reel) mode.
 * Thin UI over /api/comic, which shares its implementation with the MCP
 * comic tools (lib/comic/tools.js). Mounted from app.jsx when view === 'comic'.
 */
(function () {
  const { useState, useEffect, useRef } = React;
  const STUDIO_PASS = 'deneme123'; // must match PasswordGate (app.jsx) / STUDIO_PASSWORD env
  const RECENT_KEY = 'ml.comics';

  async function comicApi(action, args = {}) {
    const res = await fetch('/api/comic', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'x-studio-pass': STUDIO_PASS },
      body: JSON.stringify({ action, ...args }),
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) throw new Error(data.error || `/api/comic ${res.status}`);
    return data;
  }
  const sleep = ms => new Promise(r => setTimeout(r, ms));
  function loadRecent() { try { return JSON.parse(localStorage.getItem(RECENT_KEY) || '[]'); } catch { return []; } }
  function pushRecent(item) {
    const list = [item, ...loadRecent().filter(x => x.comicId !== item.comicId)].slice(0, 20);
    try { localStorage.setItem(RECENT_KEY, JSON.stringify(list)); } catch {}
    return list;
  }

  const STAGES = ['storyboard', 'characters', 'panels', 'voiceover', 'composed', 'reel'];
  const STAGE_LABEL = {
    tr: { storyboard: 'Senaryo', characters: 'Karakterler', panels: 'Paneller', voiceover: 'Seslendirme', composed: 'Baloncuklar', reel: 'Reel', veo: 'Veo canlandırma' },
    en: { storyboard: 'Storyboard', characters: 'Characters', panels: 'Panels', voiceover: 'Voiceover', composed: 'Bubbles', reel: 'Reel', veo: 'Veo animation' },
  };

  function StageBar({ stage, status, tr }) {
    const L = STAGE_LABEL[tr ? 'tr' : 'en'];
    const idx = STAGES.indexOf(stage);
    return (
      <div className="comic-stages">
        {STAGES.map((s, i) => {
          const done = status === 'done' || (idx >= 0 && i < idx) || (status === 'running' && i < idx);
          const active = status === 'running' && (s === stage || (idx === -1 && i === 0));
          return (
            <div key={s} className={'comic-stage' + (done ? ' is-done' : '') + (active ? ' is-active' : '')}>
              <span className="comic-stage-dot">{done ? '✓' : active ? <span className="ai-spinner" /> : i + 1}</span>
              <span>{L[s]}</span>
            </div>
          );
        })}
      </div>
    );
  }

  function CharacterPanel({ brandId, tr, characters, setCharacters, options, busy, setBusy, setError }) {
    const [open, setOpen] = useState(false);
    const [form, setForm] = useState({ name: '', role: '', gender: 'male', visual: '', voiceName: '', voiceStyle: '' });
    const create = async () => {
      if (!form.name || !form.visual) return;
      setBusy(true); setError('');
      try {
        const c = await comicApi('create_character', { brandId, ...form, voiceName: form.voiceName || undefined });
        setCharacters([c, ...characters]);
        setForm({ name: '', role: '', gender: 'male', visual: '', voiceName: '', voiceStyle: '' });
        setOpen(false);
      } catch (e) { setError(e.message); }
      setBusy(false);
    };
    return (
      <div className="section">
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <h3 className="section-title" style={{ marginBottom: 0 }}>{tr ? 'Kadro (tekrar eden karakterler)' : 'Cast (recurring characters)'}</h3>
          <button className="btn ghost small" onClick={() => setOpen(!open)}>{open ? (tr ? 'Kapat' : 'Close') : (tr ? '+ Yeni' : '+ New')}</button>
        </div>
        {open && (
          <div className="section-row" style={{ marginTop: 10 }}>
            <input className="input" placeholder={tr ? 'Ad (örn. Serkan)' : 'Name'} value={form.name} onChange={e => setForm({ ...form, name: e.target.value })} />
            <div style={{ display: 'flex', gap: 8 }}>
              <input className="input" placeholder={tr ? 'Rol (örn. ramp görevlisi)' : 'Role'} value={form.role} onChange={e => setForm({ ...form, role: e.target.value })} />
              <select className="select" value={form.gender} onChange={e => setForm({ ...form, gender: e.target.value, voiceName: '' })} title={tr ? 'Ses cinsiyeti buna göre seçilir' : 'The voice is picked to match'}>
                <option value="male">{tr ? 'Erkek' : 'Male'}</option>
                <option value="female">{tr ? 'Kadın' : 'Female'}</option>
              </select>
            </div>
            <textarea className="textarea" placeholder={tr ? 'Görünüm (İngilizce önerilir): yaş, saç, yüz, kıyafet + renkler, imza eşya' : 'Appearance (English): age, hair, face, outfit + colours, signature prop'} value={form.visual} onChange={e => setForm({ ...form, visual: e.target.value })} />
            <div style={{ display: 'flex', gap: 8 }}>
              <select className="select" value={form.voiceName} onChange={e => setForm({ ...form, voiceName: e.target.value })}>
                <option value="">{tr ? 'Ses (otomatik)' : 'Voice (auto)'}</option>
                {(options?.voices || []).filter(v => !v.gender || !form.gender || v.gender === form.gender)
                  .map(v => <option key={v.name} value={v.name}>{v.name} · {v.tone}</option>)}
              </select>
              <input className="input" placeholder={tr ? 'Ses tarzı (EN): gruff, tired' : 'Voice style (EN)'} value={form.voiceStyle} onChange={e => setForm({ ...form, voiceStyle: e.target.value })} />
            </div>
            <button className="btn ink full" disabled={busy || !form.name || !form.visual} onClick={create}>{busy ? <span className="ai-spinner" /> : (tr ? 'Karakter sayfası üret (~30 sn)' : 'Generate model sheet (~30s)')}</button>
          </div>
        )}
        {!characters.length && <div className="history-empty">{tr ? 'Henüz karakter yok — ilk üretimde kadro otomatik oluşur.' : 'No characters yet — the first run creates a cast automatically.'}</div>}
        <div className="comic-char-list">
          {characters.map(c => (
            <a key={c.characterId} className="comic-char" href={c.sheetUrl} target="_blank" rel="noreferrer" title={c.visual}>
              <img src={c.sheetUrl} alt={c.name} />
              <div><b>{c.name}</b><span>{c.role}{c.gender ? ` · ${c.gender === 'male' ? (tr ? 'erkek' : 'male') : (tr ? 'kadın' : 'female')}` : ''}{c.voice?.voiceName ? ` · ${c.voice.voiceName}` : ''}</span></div>
            </a>
          ))}
        </div>
      </div>
    );
  }

  function ComicStudio({ brandId, lang, onClose }) {
    const tr = lang === 'tr';
    const [options, setOptions] = useState(null);
    const [characters, setCharacters] = useState([]);
    const [form, setForm] = useState({ brief: '', panels: 6, tone: 'witty', styleId: 'realistic-cartoon', voice: 'dialogue', animate: 'none', music: true, castIds: [], bubbleMode: window.comicBubbleMode ? window.comicBubbleMode() : 'overlay' });
    const [busy, setBusy] = useState(false);
    const [error, setError] = useState('');
    const [job, setJob] = useState(null);          // {jobId, status, stage, comicId, error}
    const [comic, setComic] = useState(null);      // full storyboard from get_comic
    const [result, setResult] = useState(null);    // package result
    const [recent, setRecent] = useState(loadRecent());
    const [note, setNote] = useState({});
    const [translating, setTranslating] = useState('');
    const pollRef = useRef(null);

    useEffect(() => {
      comicApi('list_comic_options').then(o => { setOptions(o); setCharacters((o.characters || []).filter(c => c.brandId === brandId)); }).catch(e => setError(e.message));
    }, []);
    useEffect(() => {
      if (!options) return;
      setCharacters((options.characters || []).filter(c => c.brandId === brandId));
      setForm(f => ({ ...f, castIds: [] }));
    }, [brandId]);
    useEffect(() => () => clearTimeout(pollRef.current), []);

    const openComic = async (comicId) => {
      setError('');
      try {
        const sb = await comicApi('get_comic', { comicId });
        setComic(sb);
        setResult(sb.reel?.url ? { mediaUrl: sb.reel.url, caption: sb.caption, comicId } : null);
      } catch (e) { setError(e.message); }
    };

    const poll = async (jobId) => {
      try {
        const j = await comicApi('get_job', { jobId });
        setJob(j);
        if (j.status === 'done') {
          setBusy(false);
          setResult(j.result);
          await openComic(j.result.comicId);
          setRecent(pushRecent({ comicId: j.result.comicId, title: j.result.title, mediaUrl: j.result.mediaUrl, lang: j.result.lang, at: Date.now() }));
          return;
        }
        if (j.status === 'error') { setBusy(false); setError(j.error || 'error'); if (j.comicId) openComic(j.comicId); return; }
        pollRef.current = setTimeout(() => poll(jobId), 6000);
      } catch (e) { setBusy(false); setError(e.message); }
    };

    const start = async () => {
      if (!form.brief.trim()) return;
      setBusy(true); setError(''); setResult(null); setComic(null); setJob({ status: 'running', stage: 'storyboard' });
      try {
        const { jobId } = await comicApi('create_comic_reel_package', { ...form, brandId, lang, panels: Number(form.panels) });
        setJob({ jobId, status: 'running', stage: 'storyboard' });
        pollRef.current = setTimeout(() => poll(jobId), 5000);
      } catch (e) { setBusy(false); setError(e.message); }
    };
    const resume = async () => {
      if (!job?.comicId) return;
      setBusy(true); setError('');
      try {
        const { jobId } = await comicApi('resume_comic_package', { comicId: job.comicId, animate: form.animate, music: form.music });
        setJob({ jobId, status: 'running', stage: job.stage, comicId: job.comicId });
        pollRef.current = setTimeout(() => poll(jobId), 5000);
      } catch (e) { setBusy(false); setError(e.message); }
    };

    const redrawPanel = async (index) => {
      if (!comic) return;
      setBusy(true); setError('');
      try {
        await comicApi('regenerate_panel', { comicId: comic.comicId, index, note: note[index] || '' });
        await comicApi('compose_comic_panels', { comicId: comic.comicId });
        const r = await comicApi('render_comic_reel', { comicId: comic.comicId, animate: form.animate, music: form.music });
        setResult(r);
        await openComic(comic.comicId);
      } catch (e) { setError(e.message); }
      setBusy(false);
    };

    const rerender = async () => {
      if (!comic) return;
      setBusy(true); setError('');
      try {
        const r = await comicApi('render_comic_reel', { comicId: comic.comicId, animate: form.animate, music: form.music });
        setResult(r); await openComic(comic.comicId);
      } catch (e) { setError(e.message); }
      setBusy(false);
    };

    const translate = async (targetLang) => {
      if (!comic) return;
      setBusy(true); setError(''); setTranslating(tr ? 'Çeviriliyor…' : 'Translating…');
      try {
        const t = await comicApi('translate_storyboard', { comicId: comic.comicId, targetLang });
        if ((comic.audio?.mode || comic.voiceMode) !== 'none') { setTranslating(tr ? 'Seslendiriliyor…' : 'Voicing…'); await comicApi('generate_voiceover', { comicId: t.comicId }); }
        setTranslating(tr ? 'Baloncuklar basılıyor…' : 'Composing…'); await comicApi('compose_comic_panels', { comicId: t.comicId });
        setTranslating(tr ? 'Reel oluşturuluyor…' : 'Rendering reel…');
        const r = await comicApi('render_comic_reel', { comicId: t.comicId, animate: form.animate, music: form.music });
        setResult(r); await openComic(t.comicId);
        setRecent(pushRecent({ comicId: t.comicId, title: t.title, mediaUrl: r.mediaUrl, lang: targetLang, at: Date.now() }));
      } catch (e) { setError(e.message); }
      setTranslating(''); setBusy(false);
    };

    const copy = (text) => { try { navigator.clipboard.writeText(text || ''); } catch {} };
    const toggleCast = (id) => setForm(f => ({ ...f, castIds: f.castIds.includes(id) ? f.castIds.filter(x => x !== id) : [...f.castIds, id].slice(0, 4) }));
    const L = options?.limits?.[lang] || {};

    return (
      <div className="comic-wrap">
        <div className="comic-col comic-form">
          <div className="section" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <h2 className="comic-title">🎨 {tr ? 'Karikatür Reel' : 'Comic Reel'}</h2>
            <button className="btn ghost small" onClick={onClose}>← {tr ? 'Tasarım' : 'Design'}</button>
          </div>
          <div className="section section-row">
            <div className="field">
              <label className="field-label">{tr ? 'Konu / durum (herkesin bildiği komik bir an)' : 'Topic / situation (a relatable funny moment)'}</label>
              <textarea className="textarea" rows={4} value={form.brief} onChange={e => setForm({ ...form, brief: e.target.value })}
                placeholder={tr ? 'Örn. "Antalya\'ya gidiyorsun" dediler; deniz sandık, apron çıktı.' : 'e.g. They said "you\'re going to Antalya"; we pictured the beach, got the apron.'} />
            </div>
            <div className="comic-grid2">
              <div className="field"><label className="field-label">{tr ? 'Kare sayısı' : 'Panels'}</label>
                <select className="select" value={form.panels} onChange={e => setForm({ ...form, panels: e.target.value })}>{[4, 5, 6, 7].map(n => <option key={n} value={n}>{n}</option>)}</select></div>
              <div className="field"><label className="field-label">{tr ? 'Ton' : 'Tone'}</label>
                <select className="select" value={form.tone} onChange={e => setForm({ ...form, tone: e.target.value })}>
                  {['witty', 'deadpan', 'sarcastic', 'absurd', 'warm'].map(t => <option key={t} value={t}>{t}</option>)}</select></div>
              <div className="field"><label className="field-label">{tr ? 'Çizim stili' : 'Art style'}</label>
                <select className="select" value={form.styleId} onChange={e => setForm({ ...form, styleId: e.target.value })}>
                  {(options?.styles || [{ id: 'realistic-cartoon', name: 'Realistic cartoon' }]).map(s => <option key={s.id} value={s.id}>{s.name}</option>)}</select></div>
              <div className="field"><label className="field-label">{tr ? 'Ses' : 'Voice'}</label>
                <select className="select" value={form.voice} onChange={e => setForm({ ...form, voice: e.target.value })}>
                  <option value="dialogue">{tr ? 'Diyalog (karakter sesleri)' : 'Dialogue (character voices)'}</option>
                  <option value="narrator">{tr ? 'Anlatıcı' : 'Narrator'}</option>
                  <option value="none">{tr ? 'Sessiz (sadece müzik)' : 'None (music only)'}</option></select></div>
              <div className="field"><label className="field-label">{tr ? 'Hareket' : 'Motion'}</label>
                <select className="select" value={form.animate} onChange={e => setForm({ ...form, animate: e.target.value })}>
                  <option value="none">{tr ? 'Sabit (varsayılan)' : 'Static (default)'}</option><option value="kenburns">Ken Burns</option></select></div>
              <div className="field"><label className="field-label">{tr ? 'Müzik' : 'Music'}</label>
                <select className="select" value={form.music ? '1' : '0'} onChange={e => setForm({ ...form, music: e.target.value === '1' })}>
                  <option value="1">{tr ? 'Otomatik (Jamendo)' : 'Auto (Jamendo)'}</option><option value="0">{tr ? 'Yok' : 'Off'}</option></select></div>
              <div className="field"><label className="field-label">{tr ? 'Baloncuklar' : 'Bubbles'}</label>
                <select className="select" value={form.bubbleMode} onChange={e => { setForm({ ...form, bubbleMode: e.target.value }); window.setComicBubbleMode && window.setComicBubbleMode(e.target.value); }}>
                  <option value="overlay">{tr ? 'HTML (metin kesin, TR/EN aynı çizim)' : 'HTML (exact text, panels reused)'}</option>
                  <option value="baked">{tr ? 'Gemini çizsin (resmin içine)' : 'Gemini draws them (in the picture)'}</option></select></div>
            </div>
            {!!characters.length && (
              <div className="field">
                <label className="field-label">{tr ? 'Bu reel\'de oynasın (en fazla 4)' : 'Cast for this reel (max 4)'}</label>
                <div className="chips">{characters.map(c => (
                  <button key={c.characterId} className={'chip' + (form.castIds.includes(c.characterId) ? ' is-active' : '')} onClick={() => toggleCast(c.characterId)}>{c.name}</button>))}</div>
              </div>
            )}
            <button className="btn primary full" disabled={busy || !form.brief.trim()} onClick={start}>
              {busy && job?.status === 'running' ? <><span className="ai-spinner" /> {STAGE_LABEL[lang][job.stage] || '…'}</> : (tr ? 'Karikatür reel üret (2-4 dk)' : 'Generate comic reel (2-4 min)')}
            </button>
            {L.bubbleChars && <div className="comic-hint">{tr ? `Baloncuk ≤ ${L.bubbleChars} karakter / ${L.bubbleWords} kelime · panel başına 2 baloncuk · tahmini maliyet ≈ $1-1.5` : `Bubble ≤ ${L.bubbleChars} chars / ${L.bubbleWords} words · 2 bubbles per panel · est. cost ≈ $1-1.5`}</div>}
          </div>
          <CharacterPanel brandId={brandId} tr={tr} characters={characters} setCharacters={setCharacters} options={options} busy={busy} setBusy={setBusy} setError={setError} />
          {!!recent.length && (
            <div className="section">
              <h3 className="section-title">{tr ? 'Son üretimler' : 'Recent'}</h3>
              {recent.map(r => (
                <div key={r.comicId} className="history-item" onClick={() => openComic(r.comicId)}>
                  <div className="history-item-title">{r.title || r.comicId}</div>
                  <div className="history-item-meta">{(r.lang || '').toUpperCase()} · {new Date(r.at).toLocaleString()}</div>
                </div>
              ))}
            </div>
          )}
        </div>

        <div className="comic-col comic-result">
          {error && <div className="comic-error">⚠ {error} {job?.comicId && job?.status === 'error' && <button className="btn small" onClick={resume}>{tr ? 'Kaldığı yerden devam et' : 'Resume'}</button>}</div>}
          {job && <StageBar stage={job.stage} status={job.status} tr={tr} />}
          {translating && <div className="comic-hint"><span className="ai-spinner" /> {translating}</div>}
          {!comic && !job && (
            <div className="comic-empty">
              <div style={{ fontSize: 44 }}>🎬</div>
              <p>{tr ? 'Bir durum yaz, Gemini 5-6 kareli bir karikatür senaryosu yazsın, karakterleri çizsin, seslendirsin ve reel\'i oluştursun. Aynı karakterler sonraki reel\'lerde de kullanılır.' : 'Describe a situation; Gemini writes a 5-6 panel comic, draws the cast, voices it and renders the reel. The cast is reused in later reels.'}</p>
            </div>
          )}
          {comic && (
            <>
              <div className="comic-head">
                <div>
                  <div className="comic-head-title">{comic.title}</div>
                  <div className="history-item-meta">{comic.comicId} · {comic.lang.toUpperCase()} · {comic.panels.length} {tr ? 'panel' : 'panels'} · {comic.audio?.mode || comic.voiceMode}</div>
                </div>
                <div style={{ display: 'flex', gap: 6 }}>
                  {comic.lang !== 'en' && <button className="btn ghost small" disabled={busy} onClick={() => translate('en')}>EN {tr ? 'sürüm' : 'version'}</button>}
                  {comic.lang !== 'tr' && <button className="btn ghost small" disabled={busy} onClick={() => translate('tr')}>TR {tr ? 'sürüm' : 'version'}</button>}
                  <button className="btn ink small" disabled={busy} onClick={rerender}>{tr ? 'Reel\'i yeniden oluştur' : 'Re-render reel'}</button>
                </div>
              </div>
              <div className="comic-body">
                <div className="comic-video">
                  {result?.mediaUrl || comic.reel?.url
                    ? <video key={result?.mediaUrl || comic.reel?.url} src={result?.mediaUrl || comic.reel?.url}
                        poster={comic.reel?.coverUrl || comic.panels?.[0]?.composedUrl || comic.panels?.[0]?.image || undefined}
                        controls playsInline preload="metadata" />
                    : <div className="comic-empty small">{tr ? 'Reel henüz oluşmadı' : 'Reel not rendered yet'}</div>}
                  {(result?.mediaUrl || comic.reel?.url) && (
                    <div style={{ display: 'flex', gap: 6, marginTop: 8 }}>
                      <a className="btn small" href={result?.mediaUrl || comic.reel?.url} target="_blank" rel="noreferrer" download>MP4</a>
                      <button className="btn small" onClick={() => copy(result?.mediaUrl || comic.reel?.url)}>{tr ? 'URL kopyala' : 'Copy URL'}</button>
                    </div>
                  )}
                  <div className="field" style={{ marginTop: 12 }}>
                    <label className="field-label">Caption <button className="btn ghost small" style={{ marginLeft: 8 }} onClick={() => copy(comic.caption)}>{tr ? 'Kopyala' : 'Copy'}</button></label>
                    <textarea className="textarea" rows={8} readOnly value={comic.caption || ''} />
                  </div>
                </div>
                <div className="comic-panels">
                  {comic.panels.map(p => (
                    <div key={p.index} className="comic-panel">
                      {(p.composedUrl || p.image)
                        ? <img src={p.composedUrl || p.image} alt={`panel ${p.index + 1}`} />
                        : <div className="comic-panel-ph"><span className="ai-spinner" /></div>}
                      <div className="comic-panel-meta">
                        <b>{p.index + 1}</b> {p.kind}{p.qaPass === false ? ' · QA ✗' : ''}{p.fits === false ? ' · ⚠ overflow' : ''}
                      </div>
                      <div className="comic-panel-lines">
                        {(p.bubbles || []).map((b, j) => <div key={j}><b>{(comic.cast.find(c => c.ref === b.speaker) || {}).name}:</b> {b.text}</div>)}
                        {p.narration && <div><i>{p.narration}</i></div>}
                      </div>
                      <div style={{ display: 'flex', gap: 6 }}>
                        <input className="input" placeholder={tr ? 'Not (opsiyonel): daha yakın plan…' : 'Note (optional)'} value={note[p.index] || ''} onChange={e => setNote({ ...note, [p.index]: e.target.value })} />
                        <button className="btn small" disabled={busy} onClick={() => redrawPanel(p.index)}>{tr ? 'Yeniden çiz' : 'Redraw'}</button>
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            </>
          )}
        </div>
      </div>
    );
  }

  // Shared with app.jsx (Reels → Comic layout → "AI ile üret" flow).
  function comicSlidesFrom(sb) {
    const headFor = (panel, b) => {
      const hb = (panel.headBoxes || []).find(h => h.ref === b.speaker);
      if (!hb) return null;
      const [y0, x0, y1, x1] = hb.box;
      return { x: (x0 + x1) / 2 / 1000, y: (y0 + (y1 - y0) * 0.78) / 1000, top: y0 / 1000, bottom: y1 / 1000, left: x0 / 1000, right: x1 / 1000 };
    };
    return (sb.panels || []).map(p => ({
      layout: 'comic', bg: 'paper', kind: p.kind, image: p.image, composedUrl: p.composedUrl,
      title: p.kind === 'title' ? (sb.title || '') : '', narration: p.narration || '', sfx: sb.bubbleMode === 'baked' ? '' : (p.sfx || ''),
      bubbles: sb.bubbleMode === 'baked' ? [] : (p.bubbles || []).map(b => {
        const head = headFor(p, b);
        return { ...b, name: (sb.cast.find(c => c.ref === b.speaker) || {}).name || '', head, tailTo: head ? { x: head.x, y: head.y } : null };
      }),
      comicId: sb.comicId, panelIndex: p.index,
    }));
  }
  // Bubble mode preference shared by the Comic Studio form and the canvas
  // "AI ile üret" flow (persisted per browser).
  window.comicBubbleMode = () => { try { return localStorage.getItem('ml_comic_bubbleMode') === 'baked' ? 'baked' : 'overlay'; } catch { return 'overlay'; } };
  window.setComicBubbleMode = (m) => { try { localStorage.setItem('ml_comic_bubbleMode', m === 'baked' ? 'baked' : 'overlay'); } catch {} };
  window.ComicStudio = ComicStudio;
  window.comicApi = comicApi;
  window.comicSlidesFrom = comicSlidesFrom;
  window.COMIC_STAGE_LABEL = STAGE_LABEL;
})();
