// Project storage layer — single source of truth for the localStorage shape
// used by both the projects landing page and the shot-list editor.
//
// Keys:
//   pixelPortal.projects.v1            → [{ id, title, favourite, archived,
//                                            createdAt, updatedAt, shotCount,
//                                            deletedAt? }]
//   pixelPortal.project.<id>           → per-project state (see shot-list-app.jsx
//                                            for the shape — scenes, project,
//                                            dataConfig, view, …)
//   pixelPortal.shotList.v1            → legacy v1.0–v1.1 single-list state,
//                                            migrated on first run.
//
// All helpers are exposed on `window` so the JSX modules can call them.

const LEGACY_KEY         = 'pixelPortal.shotList.v1';
const PROJECTS_INDEX_KEY = 'pixelPortal.projects.v1';
const PROJECT_KEY_PREFIX = 'pixelPortal.project.';
const TRASH_TTL_MS       = 30 * 24 * 60 * 60 * 1000;   // 30 days

const projectKey = id => PROJECT_KEY_PREFIX + id;

// Wraps localStorage.setItem so write failures (most importantly a full quota
// from large inline images) are SURFACED instead of silently dropping the edit.
// On failure it fires a `pp-save-error` event — the editor shows a persistent
// warning — and returns false so callers can react. Returns true on success.
function safeSetItem(key, value) {
  try {
    localStorage.setItem(key, value);
    return true;
  } catch (e) {
    const quota = !!(e && (e.name === 'QuotaExceededError' || e.code === 22 || e.code === 1014));
    try { window.dispatchEvent(new CustomEvent('pp-save-error', { detail: { key, quota } })); } catch (_) {}
    console.error('save failed for', key, e);
    return false;
  }
}

function loadProjectsIndex() {
  try {
    const raw = localStorage.getItem(PROJECTS_INDEX_KEY);
    if (raw) {
      const arr = JSON.parse(raw);
      if (Array.isArray(arr)) return arr;
    }
  } catch (e) { console.error('projects index parse failed', e); }
  return null;
}
function saveProjectsIndex(list) {
  safeSetItem(PROJECTS_INDEX_KEY, JSON.stringify(list));
}

function migrateLegacyIfNeeded() {
  if (loadProjectsIndex() !== null) return;     // already migrated
  const legacyRaw = localStorage.getItem(LEGACY_KEY);
  if (!legacyRaw) { saveProjectsIndex([]); return; }
  try {
    const data = JSON.parse(legacyRaw);
    const id = crypto.randomUUID();
    const now = Date.now();
    const meta = {
      id,
      title: data.title || 'Documentary Shot List',
      favourite: false,
      archived: false,
      createdAt: now,
      updatedAt: now,
      shotCount: Array.isArray(data.shots) ? data.shots.length : 0,
    };
    localStorage.setItem(projectKey(id), JSON.stringify(data));
    saveProjectsIndex([meta]);
    // Leave legacy key as a safety net.
  } catch (e) {
    console.error('legacy migration failed', e);
    saveProjectsIndex([]);
  }
}

function createProject(title) {
  const id = crypto.randomUUID();
  const now = Date.now();
  const list = loadProjectsIndex() || [];
  list.push({
    id,
    title: title || 'Untitled Shot List',
    favourite: false, archived: false,
    createdAt: now, updatedAt: now,
    shotCount: 0,
  });
  saveProjectsIndex(list);
  // Cloud sync: kick off an async push if a user is signed in. Fire-and-forget;
  // the editor's UX never blocks on the network. Safe no-op when cloud-sync
  // hasn't loaded (e.g. Supabase JS missing) or the user is signed out.
  if (typeof window.ppPushOne === 'function') window.ppPushOne(id);
  return id;
}

function updateProjectMeta(id, patch) {
  const list = loadProjectsIndex() || [];
  const i = list.findIndex(p => p.id === id);
  if (i < 0) return;
  list[i] = { ...list[i], ...patch, updatedAt: Date.now() };
  saveProjectsIndex(list);
  if (typeof window.ppPushOne === 'function') window.ppPushOne(id);
}

function trashProject(id) {
  const list = loadProjectsIndex() || [];
  const p = list.find(x => x.id === id);
  if (!p) return;
  p.deletedAt = Date.now();
  p.favourite = false;
  p.archived  = false;
  saveProjectsIndex(list);
  if (typeof window.ppPushOne === 'function') window.ppPushOne(id);
}
function restoreProject(id) {
  const list = loadProjectsIndex() || [];
  const p = list.find(x => x.id === id);
  if (!p) return;
  delete p.deletedAt;
  p.updatedAt = Date.now();
  saveProjectsIndex(list);
  if (typeof window.ppPushOne === 'function') window.ppPushOne(id);
}
function deleteProjectStorage(id) {
  const next = (loadProjectsIndex() || []).filter(p => p.id !== id);
  saveProjectsIndex(next);
  localStorage.removeItem(projectKey(id));
  // Hard delete on the server too — restoration is impossible past this
  // point. Also nuke the project's image folder in Supabase Storage so
  // we don't leak files.
  if (typeof window.ppDeleteOne === 'function') window.ppDeleteOne(id);
  if (typeof window.ppDeleteProjectImages === 'function') window.ppDeleteProjectImages(id);
}
function purgeExpiredDeleted() {
  const list = loadProjectsIndex() || [];
  const now = Date.now();
  const survivors = [];
  const dropped = [];
  for (const p of list) {
    if (p.deletedAt && now - p.deletedAt >= TRASH_TTL_MS) {
      localStorage.removeItem(projectKey(p.id));
      dropped.push(p.id);
    } else {
      survivors.push(p);
    }
  }
  if (survivors.length !== list.length) saveProjectsIndex(survivors);
  // Mirror the purge to the cloud so storage stays in sync, AND clean
  // up each project's image folder in Supabase Storage.
  if (typeof window.ppDeleteOne === 'function') {
    for (const id of dropped) window.ppDeleteOne(id);
  }
  if (typeof window.ppDeleteProjectImages === 'function') {
    for (const id of dropped) window.ppDeleteProjectImages(id);
  }
}

Object.assign(window, {
  PROJECTS_INDEX_KEY, PROJECT_KEY_PREFIX, LEGACY_KEY, TRASH_TTL_MS,
  projectKey, safeSetItem,
  loadProjectsIndex, saveProjectsIndex,
  migrateLegacyIfNeeded, createProject, updateProjectMeta,
  trashProject, restoreProject, deleteProjectStorage, purgeExpiredDeleted,
});
