/* ===========================================================================
   iRaven App Store Studio — Save / Open a project as a portable file.

   "Save" writes a single self-contained .socc360.json holding the whole app:
   brand, screenshots, every App Preview (scenes · timeline · animations ·
   soundtrack), the Storage library, AND all referenced media blobs (base64).
   "Open project file" (home) imports it as a NEW project with FRESH media keys
   so two apps never share or clobber each other's blobs.
   =========================================================================== */

/* collect every IndexedDB media key a project state references */
function collectMediaKeys(state) {
  const keys = new Set();
  const addRef = (m) => { if (m && typeof m === 'object' && m.key) keys.add(m.key); };
  for (const a of state.assets || []) if (a && a.key) keys.add(a.key);
  for (const v of state.videos || []) {
    for (const sc of v.scenes || []) addRef(sc.media);
    for (const m of v.images || []) addRef(m);     // legacy
    addRef(v.audio);
    if (v.savedExport && v.savedExport.key) keys.add(v.savedExport.key);
  }
  for (const sl of state.slides || []) { addRef(sl.image); addRef(sl.image2); }
  return [...keys];
}

const _blobToB64 = (blob) => new Promise((res, rej) => {
  const f = new FileReader();
  f.onload = () => res(String(f.result).split(',')[1] || '');
  f.onerror = rej; f.readAsDataURL(blob);
});
function _b64ToBlob(b64, mime) {
  const bin = atob(b64); const arr = new Uint8Array(bin.length);
  for (let i = 0; i < bin.length; i++) arr[i] = bin.charCodeAt(i);
  return new Blob([arr], { type: mime || 'application/octet-stream' });
}

/* ---------- SAVE ---------- */
async function exportProjectFile(state, onStatus) {
  onStatus && onStatus('Packing media…');
  const keys = collectMediaKeys(state);
  const media = {};
  let total = 0;
  for (const k of keys) {
    try {
      const blob = await window.vidMediaGet(k);
      if (!blob) continue;
      total += blob.size;
      media[k] = { mime: blob.type || 'application/octet-stream', b64: await _blobToB64(blob) };
    } catch (e) { console.warn('pack failed for', k, e); }
  }
  const doc = {
    format: 'socc360.project', version: 1, exportedAt: Date.now(),
    name: (state.brand && state.brand.name) || 'App',
    state: { brand: state.brand, slides: state.slides, videos: state.videos, assets: state.assets,
      current: state.current || 0, vcurrent: state.vcurrent || 0, tab: state.tab || 'photos' },
    media,
  };
  onStatus && onStatus('Writing file…');
  const blob = new Blob([JSON.stringify(doc)], { type: 'application/json' });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = (doc.name || 'app').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') + '.socc360.json';
  a.click();
  setTimeout(() => URL.revokeObjectURL(a.href), 4000);
  const mb = (blob.size / 1e6).toFixed(1);
  onStatus && onStatus(`Saved ✓ ${doc.name}.socc360.json (${mb} MB)`);
  setTimeout(() => onStatus && onStatus(null), 4000);
}

/* ---------- OPEN ---------- */
async function importProjectFile(file) {
  const text = await file.text();
  let doc;
  try { doc = JSON.parse(text); } catch (e) { throw new Error('Not a valid project file (bad JSON).'); }
  if (!doc || doc.format !== 'socc360.project' || !doc.state) throw new Error('Not a Socc360 project file.');

  /* fresh keys so the imported app can never share blobs with another app */
  const keymap = {};
  for (const oldK of Object.keys(doc.media || {})) keymap[oldK] = window.assetUid(oldK[0] || 'a');

  /* restore blobs under the NEW keys */
  for (const [oldK, rec] of Object.entries(doc.media || {})) {
    try { await window.vidMediaPut(keymap[oldK], _b64ToBlob(rec.b64, rec.mime)); } catch (e) { console.warn('restore failed', oldK, e); }
  }

  /* rewrite every key reference in the state via safe two-phase replace */
  let s = JSON.stringify(doc.state);
  const entries = Object.entries(keymap);
  entries.forEach(([oldK], i) => { s = s.split(oldK).join('\u0000K' + i + '\u0000'); });
  entries.forEach(([, newK], i) => { s = s.split('\u0000K' + i + '\u0000').join(newK); });
  const state = JSON.parse(s);

  /* migrate any legacy previews + ensure assets array exists */
  state.videos = (state.videos || []).map(window.videoToScenes);
  state.assets = state.assets || [];
  return state;   // caller creates the project + opens it
}

Object.assign(window, { exportProjectFile, importProjectFile, collectMediaKeys });
