/* ===========================================================================
   iRaven App Store Studio — AI everywhere.
   A context-aware assistant scoped to ONE screen or ONE scene. It reads the
   project (brand, what other screens/scenes say, the current item) so its
   suggestions fit the work so far, asks for a short brief, then proposes copy
   + visual treatment via the text model (always available) and can generate or
   pick the matching image / video / music (real media when a MiniMax key is
   set, otherwise prompts + guidance you can hand off).
   =========================================================================== */

function aiBrandLine() {
  const b = window.CURRENT_BRAND || {};
  return `App: ${b.name || 'App'}${b.tagline ? ' — “' + b.tagline + '”' : ''}.`;
}

function aiScreenshotPrompt(ctx, brief) {
  const others = (ctx.slides || []).map((s, i) => `${i + 1}. ${(s.headline || '').replace(/\n/g, ' ')}`).join('\n');
  return `${aiBrandLine()}
You are art-directing ONE App Store screenshot (screen ${ctx.slideNo}) for this app.
Other screens already say:
${others || '(none yet)'}

Designer brief for THIS screen: ${brief || '(make it strong and on-brand; pick a fresh angle not covered above)'}

Reply with ONLY valid JSON, no markdown:
{"headline":"2-4 punchy words, may contain \\n once","subtitle":"max 9 words",
"template":"one of: headline-top, headline-bottom, angled, callouts, split, poster, full-bleed, big-stat, duo",
"bg":"one of: stadium, floodlight, pitch, cobalt, ember, aurora, royal, dawn, steel, noir, minimal",
"accent":"one of: cobalt, amber, brand1, brand2",
"imagePrompt":"a vivid prompt to GENERATE the screenshot's hero image/background (no text in image), or empty string if a real app screenshot belongs here instead",
"note":"one sentence of art direction"}`;
}

function aiScenePrompt(ctx, brief) {
  const others = (ctx.scenes || []).map((s, i) => `${i + 1}. ${(s.headline || '·').replace(/\n/g, ' ')}`).join('\n');
  return `${aiBrandLine()}
You are directing ONE scene (scene ${ctx.sceneNo}) of an App Store app-preview video for this app.
The preview's scenes so far:
${others}

Director brief for THIS scene: ${brief || '(make it punchy and on-brand)'}

Reply with ONLY valid JSON, no markdown:
{"headline":"0-4 words, may contain \\n once, or empty","subtitle":"max 8 words or empty",
"captionPos":"top, bottom, or none",
"layout":"device or fullbleed",
"enter":"one of: fade, rise, slideUp, slideDown, slideLeft, slideRight, zoomIn, zoomOut, pop, tilt, none",
"exit":"one of: fade, rise, slideUp, slideDown, slideLeft, slideRight, zoomIn, zoomOut, pop, tilt, none",
"imagePrompt":"prompt to GENERATE a still for this scene, or empty if a real screenshot/clip belongs here",
"videoPrompt":"prompt to GENERATE a short motion clip for this scene, or empty",
"musicPrompt":"if the whole preview still needs a soundtrack, a style prompt for it, else empty",
"note":"one sentence of direction"}`;
}

function aiPreviewPrompt(ctx, brief) {
  const lib = ctx.assets || [];
  const names = (k) => lib.filter(a => a.kind === k).map(a => a.name).filter(Boolean);
  const imgs = names('image'), vids = names('video'), mus = names('audio');
  return `${aiBrandLine()}
You are directing a COMPLETE App Store app-preview video — a timeline of 2–6 scenes — for this app.

Media available in the project library (use EXACT names for "media"; video scenes play their own length):
IMAGES: ${imgs.join(' | ') || '(none)'}
VIDEOS: ${vids.join(' | ') || '(none)'}
MUSIC: ${mus.join(' | ') || '(none)'}

Director brief: ${brief || '(make a punchy, on-brand promo using the best available media)'}

Reply with ONLY valid JSON, no markdown:
{"device":"iphone",
"bg":"one of: stadium, floodlight, pitch, cobalt, ember, aurora, royal, dawn, steel, noir, minimal",
"accent":"one of: cobalt, amber, brand1, brand2",
"music":"exact MUSIC name from the library, or empty",
"scenes":[ 2 to 6 items, each:
 {"media":"exact IMAGE or VIDEO name from the library, or empty",
  "layout":"device or fullbleed",
  "dur": number of seconds for image scenes (videos ignore this),
  "headline":"0-4 words, may contain \\n once, or empty",
  "subtitle":"<= 8 words or empty",
  "captionPos":"top, bottom, or none",
  "enter":"one of: fade, rise, slideUp, slideDown, slideLeft, slideRight, zoomIn, zoomOut, pop, tilt, none",
  "exit":"one of the same options"} ],
"note":"one sentence describing the cut"}
If the brief names a target length (e.g. 35s), choose scene durations so the total lands close to it.`;
}

function aiParseLoose(text) {
  const a = text.indexOf('{');
  if (a === -1) throw new Error('no JSON in reply');
  let depth = 0, inStr = false, esc = false;
  for (let i = a; i < text.length; i++) {
    const ch = text[i];
    if (inStr) { if (esc) esc = false; else if (ch === '\\') esc = true; else if (ch === '"') inStr = false; continue; }
    if (ch === '"') inStr = true;
    else if (ch === '{') depth++;
    else if (ch === '}') { depth--; if (depth === 0) return JSON.parse(text.slice(a, i + 1)); }
  }
  throw new Error('no complete JSON object in reply');
}

function AIAssist({ scope, brand, assets, setAssets, genMedia, pickMedia, onClose, onStatus }) {
  const isScene = scope.kind === 'scene';
  const isPreview = scope.kind === 'preview';
  const [brief, setBrief] = useState('');
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState(null);
  const [sug, setSug] = useState(null);

  const ctx = isPreview
    ? { previewNo: String(scope.current + 1).padStart(2, '0'), scenes: scope.preview.scenes, assets }
    : isScene
    ? { sceneNo: String(scope.sel + 1).padStart(2, '0'), scenes: scope.preview.scenes }
    : { slideNo: String(scope.current + 1).padStart(2, '0'), slides: scope.slides };

  const ask = async () => {
    if (busy) return;
    setErr(null); setBusy(true); setSug(null);
    try {
      const prompt = isPreview ? aiPreviewPrompt(ctx, brief)
        : isScene ? aiScenePrompt(ctx, brief) : aiScreenshotPrompt(ctx, brief);
      const out = await window.aiComplete([{ role: 'user', content: prompt }]);
      setSug(aiParseLoose(out));
    } catch (e) { setErr(String(e.message || e)); }
    setBusy(false);
  };

  const buildTimeline = () => {
    if (!sug) return;
    scope.applyTimeline(sug);
    onStatus && onStatus('Timeline built ✓');
    setTimeout(() => onStatus && onStatus(null), 1800);
    onClose();
  };

  const applyText = () => {
    if (!sug) return;
    if (isScene) {
      const ch = {};
      if (sug.headline !== undefined) ch.headline = String(sug.headline).replace(/\\n/g, '\n');
      if (sug.subtitle !== undefined) ch.subtitle = sug.subtitle || '';
      if (sug.captionPos) ch.captionPos = sug.captionPos;
      if (sug.layout) ch.layout = sug.layout;
      if (sug.enter && window.SCENE_ANIMS.find(a => a.id === sug.enter)) ch.enter = { ...(scope.preview.scenes[scope.sel].enter || {}), type: sug.enter };
      if (sug.exit && window.SCENE_ANIMS.find(a => a.id === sug.exit)) ch.exit = { ...(scope.preview.scenes[scope.sel].exit || {}), type: sug.exit };
      scope.apply(ch);
    } else {
      const ch = {};
      if (sug.headline !== undefined) ch.headline = String(sug.headline).replace(/\\n/g, '\n');
      if (sug.subtitle !== undefined) ch.subtitle = sug.subtitle || '';
      if (sug.template && window.TEMPLATES.find(t => t.id === sug.template)) ch.template = sug.template;
      if (sug.bg && window.BACKGROUNDS.find(t => t.id === sug.bg)) ch.bg = sug.bg;
      if (sug.accent) ch.accent = sug.accent;
      scope.apply(ch);
    }
    onStatus && onStatus('AI suggestions applied ✓');
    setTimeout(() => onStatus && onStatus(null), 1800);
  };

  const useMedia = (asset, isVideo) => {
    if (isScene) scope.applyMedia(window.assetToRef(asset), asset.dur);
    else scope.apply({ image: window.assetToRef(asset) });
  };

  const generateImage = () => genMedia({ kind: 'image', prompt: sug && sug.imagePrompt,
    onAsset: (asset) => useMedia(asset, false) });
  const generateVideo = () => genMedia({ kind: 'video', prompt: sug && sug.videoPrompt,
    onAsset: (asset) => useMedia(asset, true) });
  const generateMusic = () => genMedia({ kind: 'music', prompt: sug && sug.musicPrompt,
    onAsset: (asset) => scope.applyAudio && scope.applyAudio(window.assetToRef(asset)) });
  const chooseMedia = () => pickMedia({ accept: isScene ? 'image+video' : 'image', title: 'Use from storage',
    aiKind: 'image', onPick: (asset) => useMedia(asset, asset.kind === 'video') });

  const chip = (txt) => (
    <span style={{ display: 'inline-block', padding: '4px 10px', borderRadius: 999, fontSize: 12,
      background: 'rgba(47,109,246,0.16)', border: '1px solid rgba(47,109,246,0.32)', color: '#bcd2ff' }}>{txt}</span>
  );

  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 1280, background: 'rgba(3,5,14,0.84)',
      display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: BODY }}>
      <div onClick={e => e.stopPropagation()} style={{ width: 'min(540px,94vw)', maxHeight: '88vh', overflowY: 'auto',
        borderRadius: 18, background: '#0c1222', border: '1px solid rgba(255,255,255,0.12)', padding: 22 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 6 }}>
          <span style={{ fontFamily: DISPLAY, fontWeight: 600, fontSize: 17, color: '#fff' }}>
            ✦ AI · {isPreview ? 'Timeline' : isScene ? 'Scene ' + ctx.sceneNo : 'Screen ' + ctx.slideNo}</span>
          <button style={btnStyle({ padding: '6px 12px' })} onClick={onClose}>✕</button>
        </div>
        <p style={{ margin: '0 0 14px', fontSize: 12.5, color: 'rgba(255,255,255,0.5)' }}>
          {isPreview
            ? aiBrandLine() + ' Builds a whole multi-scene timeline from your library media and one prompt.'
            : aiBrandLine() + ' AI knows your other ' + (isScene ? 'scenes' : 'screens') + ' and will fit this one to them.'}
        </p>

        <Field label={isPreview ? 'Describe the whole video' : isScene ? 'What should this scene do?' : 'What should this screen show?'} rows={3}
          value={brief} onChange={setBrief}
          placeholder={isPreview ? 'e.g. a 35s energetic promo — open on the live score, then stats, then AI signals, end on the brand'
            : isScene ? 'e.g. punchy opener on the live score, fast zoom in, energetic'
            : 'e.g. highlight the live timeline feature, bold and confident'} />
        <button onClick={ask} disabled={busy} style={btnStyle({ width: '100%', padding: '11px',
          background: 'linear-gradient(180deg,#3b78ff,#1f54d6)', border: '1px solid #3b78ff', opacity: busy ? 0.55 : 1 })}>
          {busy ? 'Thinking…' : '✦ Suggest'}</button>

        {err ? (
          <div style={{ marginTop: 12, padding: '10px 14px', borderRadius: 12, fontSize: 13,
            background: 'rgba(255,59,70,0.12)', border: '1px solid rgba(255,59,70,0.35)', color: '#ff9ba1' }}>{err}</div>
        ) : null}

        {sug ? (
          <div style={{ marginTop: 16, borderRadius: 14, border: '1px solid rgba(255,255,255,0.10)',
            background: 'rgba(255,255,255,0.03)', padding: 16 }}>
            {sug.note ? <div style={{ fontSize: 12.5, color: 'rgba(255,255,255,0.6)', fontStyle: 'italic', marginBottom: 12 }}>“{sug.note}”</div> : null}

            {isPreview ? (<>
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 12 }}>
                {chip((sug.scenes || []).length + ' scenes')}
                {sug.bg ? chip('bg · ' + sug.bg) : null}
                {sug.accent ? chip('accent · ' + sug.accent) : null}
                {sug.music ? chip('♪ ' + sug.music) : null}
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginBottom: 14 }}>
                {(sug.scenes || []).map((s, i) => (
                  <div key={i} style={{ display: 'flex', gap: 10, alignItems: 'center', padding: '8px 10px', borderRadius: 10,
                    background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(255,255,255,0.08)' }}>
                    <span style={{ fontFamily: "'JetBrains Mono',monospace", fontSize: 11, color: 'rgba(255,255,255,0.4)' }}>{String(i + 1).padStart(2, '0')}</span>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 13, color: '#fff', fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                        {s.headline ? String(s.headline).replace(/\\n/g, ' ') : (s.media || '—')}</div>
                      <div style={{ fontFamily: "'JetBrains Mono',monospace", fontSize: 10.5, color: 'rgba(255,255,255,0.42)',
                        whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                        {[s.media || 'no media', s.layout, (s.dur ? (+s.dur).toFixed(1) + 's' : ''), s.enter && ('in:' + s.enter)].filter(Boolean).join(' · ')}</div>
                    </div>
                  </div>
                ))}
              </div>
              <button onClick={buildTimeline} style={btnStyle({ width: '100%', padding: '11px',
                background: 'linear-gradient(180deg,#22a45c,#157a41)', border: '1px solid #22a45c' })}>
                Build {(sug.scenes || []).length}-scene timeline</button>
              <p style={{ margin: '10px 0 0', fontSize: 11, color: 'rgba(255,255,255,0.4)', lineHeight: 1.5 }}>
                Media is matched from your Storage by name. Upload or generate the clips/screens first for the best match.</p>
            </>) : (<>
            {(sug.headline || sug.subtitle) ? (
              <div style={{ marginBottom: 12 }}>
                {sug.headline ? <div style={{ fontFamily: DISPLAY, fontWeight: 700, fontSize: 20, color: '#fff', whiteSpace: 'pre-wrap', lineHeight: 1.05 }}>
                  {String(sug.headline).replace(/\\n/g, '\n')}</div> : null}
                {sug.subtitle ? <div style={{ fontSize: 13.5, color: 'rgba(255,255,255,0.7)', marginTop: 6 }}>{sug.subtitle}</div> : null}
              </div>
            ) : null}
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 14 }}>
              {isScene ? (<>
                {sug.layout ? chip('layout · ' + sug.layout) : null}
                {sug.captionPos ? chip('caption · ' + sug.captionPos) : null}
                {sug.enter ? chip('in · ' + sug.enter) : null}
                {sug.exit ? chip('out · ' + sug.exit) : null}
              </>) : (<>
                {sug.template ? chip('template · ' + sug.template) : null}
                {sug.bg ? chip('bg · ' + sug.bg) : null}
                {sug.accent ? chip('accent · ' + sug.accent) : null}
              </>)}
            </div>
            <button onClick={applyText} style={btnStyle({ width: '100%', padding: '10px', marginBottom: 12,
              background: 'linear-gradient(180deg,#22a45c,#157a41)', border: '1px solid #22a45c' })}>
              Apply copy & style</button>

            <div style={{ fontSize: 11.5, color: 'rgba(255,255,255,0.45)', marginBottom: 8, fontWeight: 600 }}>Media</div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
              <button style={btnStyle({ flex: '1 1 45%', padding: '9px', fontSize: 12.5 })} onClick={chooseMedia}>From storage</button>
              {(sug.imagePrompt) ? <button style={btnStyle({ flex: '1 1 45%', padding: '9px', fontSize: 12.5,
                background: 'rgba(47,109,246,0.16)', border: '1px solid rgba(47,109,246,0.36)', color: '#bcd2ff' })}
                onClick={generateImage}>✦ Generate image</button> : null}
              {isScene && sug.videoPrompt ? <button style={btnStyle({ flex: '1 1 45%', padding: '9px', fontSize: 12.5,
                background: 'rgba(47,109,246,0.16)', border: '1px solid rgba(47,109,246,0.36)', color: '#bcd2ff' })}
                onClick={generateVideo}>✦ Generate clip</button> : null}
              {isScene && sug.musicPrompt ? <button style={btnStyle({ flex: '1 1 45%', padding: '9px', fontSize: 12.5,
                background: 'rgba(47,109,246,0.16)', border: '1px solid rgba(47,109,246,0.36)', color: '#bcd2ff' })}
                onClick={generateMusic}>✦ Generate music</button> : null}
            </div>
            {(sug.imagePrompt || sug.videoPrompt || sug.musicPrompt) ? (
              <p style={{ margin: '10px 0 0', fontSize: 11, color: 'rgba(255,255,255,0.4)', lineHeight: 1.5 }}>
                Generation prompt{sug.imagePrompt ? ' · image: “' + sug.imagePrompt.slice(0, 70) + '…”' : ''}.
                Real media needs a MiniMax key (AI settings); without one you can still copy these prompts.</p>
            ) : null}
            </>)}
          </div>
        ) : null}
      </div>
    </div>
  );
}

Object.assign(window, { AIAssist });
