/* ===========================================================================
   iRaven App Store Studio — App Store Preview export pipeline (client side).

   Why this module exists:
     The browser-side WebCodecs encoder produces an .mp4, but App Store
     Connect rejects exports whose avg_frame_rate dips below 30 fps — which
     happens any time the encoder loop falls behind realtime. The fix is
     to ALWAYS run the encoded blob through a server-side ffmpeg pass
     that re-encodes to constant 30 fps, H.264 high@4.0, yuv420p, AAC
     stereo 48 kHz, and (for App Store presets) hard-caps duration to
     30 seconds.

     This file owns:
       1. APP_STORE_PRESETS — list of presets that match the Apple spec.
       2. appStoreNormalize(blob, presetKey) — POSTs to /api/export, returns
          { blob, validation } where validation is the structured ffprobe
          report from the server.
       3. probeForAppStore(blob, presetKey) — POSTs to /api/probe for the
          metadata-only path (no re-encode).
       4. summarizeValidation(validation) — turns the report into a short
          status string for the UI status line.

   The preset list MUST stay in sync with lib/appstore/presets.ts on the
   server. Mismatch is a release-blocking bug.
   =========================================================================== */

(function () {
  const APP_STORE_PRESETS = [
    { key: 'iphone-6-5-portrait', label: 'App Store Preview — iPhone 6.5″', surface: 'app-store', maxDur: 30 },
    { key: 'iphone-6-1-portrait', label: 'App Store Preview — iPhone 6.1″', surface: 'app-store', maxDur: 30 },
    { key: 'iphone-6-7-portrait', label: 'App Store Preview — iPhone 6.7″', surface: 'app-store', maxDur: 30 },
    { key: 'ipad-13-portrait',    label: 'App Store Preview — iPad 13″',    surface: 'app-store', maxDur: 30 },
    { key: 'marketing',           label: 'Marketing Video (no cap)',         surface: 'marketing', maxDur: 0  },
  ];
  const DEFAULT_PRESET = 'iphone-6-5-portrait';

  /* POST a Blob through /api/export with the chosen preset. Server runs
     ffmpeg with the App Store-safe pipeline and returns the normalized
     mp4 in the body. The validation report (parsed JSON) is in the
     X-Validation response header so the UI can render pass/fail without
     a second round-trip. */
  async function appStoreNormalize(blob, presetKey) {
    if (!blob) throw new Error('appStoreNormalize: blob required');
    const preset = presetKey || DEFAULT_PRESET;
    const form = new FormData();
    form.append('file', blob, 'source.mp4');
    form.append('preset', preset);
    const res = await fetch('/api/export', { method: 'POST', body: form });
    if (!res.ok) {
      const text = await res.text().catch(() => '');
      throw new Error(`normalize failed (${res.status}): ${text.slice(0, 200)}`);
    }
    const validationHeader = res.headers.get('x-validation');
    let validation = null;
    try { validation = validationHeader ? JSON.parse(validationHeader) : null; }
    catch (e) { validation = null; }
    const outBlob = await res.blob();
    return { blob: outBlob, validation, preset };
  }

  /* Probe without re-encoding. Useful for "validate an existing export"
     buttons; the server returns the ffprobe metadata + validation if
     `preset` is supplied. */
  async function probeForAppStore(blob, presetKey) {
    if (!blob) throw new Error('probeForAppStore: blob required');
    const form = new FormData();
    form.append('file', blob, 'source.mp4');
    if (presetKey) form.append('preset', presetKey);
    const res = await fetch('/api/probe', { method: 'POST', body: form });
    if (!res.ok) {
      const text = await res.text().catch(() => '');
      throw new Error(`probe failed (${res.status}): ${text.slice(0, 200)}`);
    }
    return res.json();
  }

  /* Short human-readable status string. Used by the status bar after a
     normalize completes. Returns one of:
       'App Store validation passed · 30fps · 28.0s · 4.1 MB'
       '✗ Frame rate too low (24.0/1 avg) · Variable frame rate'
   */
  function summarizeValidation(validation) {
    if (!validation) return 'No validation report';
    const probe = validation.probe || {};
    if (validation.passed) {
      const size = probe.fileBytes ? `${(probe.fileBytes / 1048576).toFixed(1)} MB` : '';
      return [
        'App Store validation passed',
        `${probe.rFrameRateValue || 30}fps`,
        `${(probe.durationSeconds || 0).toFixed(1)}s`,
        `${probe.width}×${probe.height}`,
        size,
      ].filter(Boolean).join(' · ');
    }
    const errs = (validation.issues || []).filter(i => i.severity === 'error').map(i => i.message);
    return '✗ ' + (errs.slice(0, 2).join(' · ') || 'validation failed');
  }

  /* Build a multi-line block describing every issue (for a modal or
     details panel). Returns an array of {severity,message,field}. */
  function listValidationIssues(validation) {
    return (validation && validation.issues) || [];
  }

  Object.assign(window, {
    APP_STORE_PRESETS,
    APP_STORE_DEFAULT_PRESET: DEFAULT_PRESET,
    appStoreNormalize,
    probeForAppStore,
    summarizeAppStoreValidation: summarizeValidation,
    listAppStoreValidationIssues: listValidationIssues,
  });
})();
