// Cloud sync layer — mirrors window.Hub's in-memory state to Supabase, and
// routes the hero photo to Supabase Storage. Designed to be invisible to the
// rest of the app: hifi-store.jsx just calls window.Cloud.saveState() after
// every snapshot, and hifi-hero.jsx routes uploads through window.Cloud.
//
// Lifecycle:
//   1. hifi-store.jsx hydrates from localStorage on load (fast first paint).
//   2. After login, AuthGate calls Cloud.setUser(user) then Cloud.loadState().
//   3. loadState() pulls the cloud row, replaces the in-memory arrays, and
//      dispatches "homehub:cloud-loaded" so React re-renders.
//   4. Every subsequent Hub mutation triggers a debounced upsert.

(function () {
  const TABLE  = 'homehub_state';
  const BUCKET = 'hero';

  let currentUser = null;
  let saving = false;
  let pendingSave = false;
  let saveTimer = null;

  // ---- snapshot helpers ---------------------------------------------------

  const snapshot = () => ({
    assets:   window.ASSETS   || [],
    routines: window.ROUTINES || [],
    contacts: window.CONTACTS || [],
    todos:    window.TODOS    || [],
    profile:  (window.Account && window.Account.current && window.Account.current()) || null,
  });

  const isEmptyState = (s) =>
    !s || (
      (!s.assets   || !s.assets.length) &&
      (!s.routines || !s.routines.length) &&
      (!s.contacts || !s.contacts.length) &&
      (!s.todos    || !s.todos.length) &&
      !s.profile
    );

  function replaceAll(data) {
    if (!data) return;
    const repl = (arr, next) => { arr.length = 0; (next || []).forEach(x => arr.push(x)); };
    repl(window.ASSETS,   data.assets);
    repl(window.ROUTINES, data.routines);
    repl(window.CONTACTS, data.contacts);
    repl(window.TODOS,    data.todos);
    if (data.profile && window.Account && window.Account.replaceFromCloud) {
      window.Account.replaceFromCloud(data.profile);
    }
    if (window.normalizeRecords)        window.normalizeRecords();
    if (window.Hub && window.Hub.refreshStatuses) window.Hub.refreshStatuses();
    if (window.Hub && window.Hub.reconcileGaps)   window.Hub.reconcileGaps();
  }

  // ---- state read / write -------------------------------------------------

  async function loadState() {
    if (!currentUser || !window.SB) return null;

    const { data, error } = await window.SB
      .from(TABLE)
      .select('state, hero_photo')
      .eq('user_id', currentUser.id)
      .maybeSingle();

    if (error) {
      console.error('[Home Hub] Cloud load failed:', error);
      window.dispatchEvent(new CustomEvent('homehub:cloud-loaded', { detail: { error } }));
      return null;
    }

    const cloudState = data && data.state;
    const cloudHero  = data && data.hero_photo;

    // ---- state migration / hydration
    if (cloudState && !isEmptyState(cloudState)) {
      replaceAll(cloudState);
      // Backfill: cloud row existed but predated profile sync. Push local profile up.
      if (!cloudState.profile && window.Account && window.Account.current()) {
        await saveStateNow();
      }
    } else {
      // Cloud is empty. If localStorage has anything, push it up so this
      // device's existing data becomes the new source of truth.
      const localHasData = !isEmptyState(snapshot());
      if (localHasData) {
        console.log('[Home Hub] First-time cloud migration: pushing localStorage state up.');
        await saveStateNow();
      } else {
        // Both empty — create an empty row so future saves UPDATE rather than INSERT.
        await saveStateNow();
      }
    }

    // ---- hero photo
    if (cloudHero) {
      await refreshHeroDisplayUrl(cloudHero);
    } else {
      // Cloud has no hero. If we have a local data-URL hero, upload it.
      const local = window.HeroPhoto && window.HeroPhoto.get();
      if (local && local.startsWith('data:')) {
        try {
          console.log('[Home Hub] First-time cloud migration: uploading existing hero photo.');
          const blob = await (await fetch(local)).blob();
          await uploadHero(blob);
        } catch (e) {
          console.error('[Home Hub] Hero migration failed:', e);
        }
      }
    }

    window.dispatchEvent(new CustomEvent('homehub:cloud-loaded'));
    return data;
  }

  async function saveStateNow() {
    if (!currentUser || !window.SB) return;
    saving = true;
    try {
      const { error } = await window.SB
        .from(TABLE)
        .upsert(
          { user_id: currentUser.id, state: snapshot() },
          { onConflict: 'user_id' }
        );
      if (error) console.error('[Home Hub] Cloud save failed:', error);
    } finally {
      saving = false;
      if (pendingSave) { pendingSave = false; scheduleSave(); }
    }
  }

  function scheduleSave() {
    if (!currentUser) return;            // not logged in yet — localStorage is enough
    if (saving) { pendingSave = true; return; }
    if (saveTimer) clearTimeout(saveTimer);
    saveTimer = setTimeout(() => { saveTimer = null; saveStateNow(); }, 600);
  }

  // ---- hero photo ---------------------------------------------------------

  // Builds a fresh signed URL and hands it to HeroPhoto for display.
  async function refreshHeroDisplayUrl(path) {
    if (!path || !window.SB) return;
    const { data, error } = await window.SB
      .storage.from(BUCKET)
      .createSignedUrl(path, 60 * 60); // 1 hour
    if (error) { console.error('[Home Hub] Hero signed-URL failed:', error); return; }
    if (data && data.signedUrl && window.HeroPhoto && window.HeroPhoto._setDisplay) {
      window.HeroPhoto._setDisplay(data.signedUrl);
    }
  }

  async function uploadHero(blob) {
    if (!currentUser || !window.SB) throw new Error('Not signed in');
    const path = `${currentUser.id}/hero.jpg`;

    const { error: upErr } = await window.SB
      .storage.from(BUCKET)
      .upload(path, blob, { upsert: true, contentType: blob.type || 'image/jpeg' });
    if (upErr) throw upErr;

    const { error: rowErr } = await window.SB
      .from(TABLE)
      .upsert(
        { user_id: currentUser.id, hero_photo: path, state: snapshot() },
        { onConflict: 'user_id' }
      );
    if (rowErr) throw rowErr;

    await refreshHeroDisplayUrl(path);
    return path;
  }

  async function removeHero() {
    if (!currentUser || !window.SB) return;
    const path = `${currentUser.id}/hero.jpg`;
    try { await window.SB.storage.from(BUCKET).remove([path]); } catch (e) {}
    await window.SB
      .from(TABLE)
      .upsert(
        { user_id: currentUser.id, hero_photo: null, state: snapshot() },
        { onConflict: 'user_id' }
      );
  }

  // ---- user lifecycle -----------------------------------------------------

  function setUser(user) {
    currentUser = user || null;
  }

  // Wipe local state when signing out so the next user (or next sign-in)
  // doesn't see leftover data. The cloud row remains intact.
  function clearLocal() {
    try { localStorage.removeItem('homehub.state.v3'); } catch (e) {}
    try { localStorage.removeItem('homehub.hero.v1');  } catch (e) {}
    try { localStorage.removeItem('homehub.profile.v1'); } catch (e) {}
    if (window.HeroPhoto && window.HeroPhoto._setDisplay) window.HeroPhoto._setDisplay('');
    const repl = (arr) => { if (arr) arr.length = 0; };
    repl(window.ASSETS); repl(window.ROUTINES); repl(window.CONTACTS); repl(window.TODOS);
  }

  window.Cloud = {
    setUser,
    loadState,
    saveState: scheduleSave,
    saveStateNow,
    uploadHero,
    removeHero,
    clearLocal,
    isSignedIn: () => !!currentUser,
    currentUser: () => currentUser,
  };
})();
