// INLEARN CRM — Firestore-backed shared workspace with live sync.
//
// Mirrors the app's localStorage datasets to Firestore (/crm/{key}) so every
// allowlisted user shares ONE CRM across all devices and domains, and changes
// propagate live via onSnapshot.
//
// Flow:
//   1. hydrate(user) — pull every dataset doc from Firestore into localStorage
//      BEFORE the app mounts; one-time migration lifts existing local data up.
//      Then start live listeners.
//   2. App writes to localStorage are mirrored to Firestore (debounced).
//   3. Remote changes arrive via onSnapshot → localStorage updated + an
//      'inlearn-remote' event is dispatched so the app updates its React state
//      instantly (no refresh).
//
// Echo-loop prevention: `lastSynced[key]` holds the last JSON we pushed or
// received for each key. We skip pushing values equal to it, and ignore
// snapshots equal to it (our own write bouncing back).
//
// Active on the live site only (AuthGate calls hydrate after sign-in + allowlist).

(function () {
  const SYNC_KEYS = [
    'INLEARN_CONTACTS_V1', 'INLEARN_DEALS_V1', 'INLEARN_RAWLEADS_V1',
    'INLEARN_CRM_SOURCES_V2', 'INLEARN_CRM_STAGES_V2', 'INLEARN_CRM_PLAYBOOKS_V2',
    'INLEARN_PACKAGES_V1', 'INLEARN_SUBJECTS_V1', 'INLEARN_TEAM_V1',
  ];

  const rawSet = window.localStorage.setItem.bind(window.localStorage);
  const rawGet = window.localStorage.getItem.bind(window.localStorage);

  let active = false;        // true after hydrate → writes start mirroring
  let listening = false;
  let currentUser = null;
  const timers = {};
  const lastSynced = {};     // key -> last JSON string pushed/received

  const db = () => window.firebase.firestore();

  // Treat null / [] / {} / {all-empty-arrays} as "no data" so a blank origin
  // can never overwrite a populated one during hydrate/migration.
  function isEmptyVal(s) {
    if (s == null) return true;
    try {
      const v = JSON.parse(s);
      if (v == null) return true;
      if (Array.isArray(v)) return v.length === 0;
      if (typeof v === 'object') {
        const vals = Object.values(v);
        if (vals.length === 0) return true;
        if (vals.every(x => Array.isArray(x))) return vals.every(x => x.length === 0);
        return false;
      }
      return false;
    } catch (e) { return true; }
  }

  async function pushKey(key, jsonStr) {
    lastSynced[key] = jsonStr;   // set before await so a fast echo compares equal
    try {
      await db().collection('crm').doc(key).set({
        json: jsonStr,
        updatedAt: new Date().toISOString(),
        updatedBy: (currentUser && currentUser.email) || 'unknown',
      });
    } catch (e) {
      console.error('[store] push failed for', key, e && e.message);
    }
  }

  // Patch setItem so the app's persistence transparently mirrors to Firestore.
  window.localStorage.setItem = function (key, value) {
    rawSet(key, value);
    if (active && SYNC_KEYS.indexOf(key) !== -1 && value !== lastSynced[key]) {
      clearTimeout(timers[key]);
      timers[key] = setTimeout(() => pushKey(key, value), 600);
    }
  };

  // Live listeners: push remote changes into localStorage + notify the app.
  function startListening() {
    if (listening || !window.firebase) return;
    listening = true;
    SYNC_KEYS.forEach((key) => {
      db().collection('crm').doc(key).onSnapshot((doc) => {
        if (!doc.exists) return;
        const json = doc.data().json;
        if (typeof json !== 'string' || json === lastSynced[key]) return; // our own echo
        lastSynced[key] = json;
        rawSet(key, json);
        window.dispatchEvent(new CustomEvent('inlearn-remote', { detail: { key, json } }));
      }, (err) => console.error('[store] listen failed for', key, err && err.message));
    });
  }

  async function hydrate(user) {
    currentUser = user || null;
    if (!window.firebase) { active = true; return; }

    const results = await Promise.all(SYNC_KEYS.map(async (key) => {
      try {
        const doc = await db().collection('crm').doc(key).get();
        return { key, exists: doc.exists, json: doc.exists ? doc.data().json : null };
      } catch (e) {
        console.error('[store] read failed for', key, e && e.message);
        return { key, error: true };
      }
    }));

    for (const r of results) {
      if (r.error) { lastSynced[r.key] = rawGet(r.key); continue; }
      const remote = r.exists ? r.json : null;
      const local = rawGet(r.key);
      if (!isEmptyVal(remote)) {
        rawSet(r.key, remote);                 // Firestore has real data → use it
      } else if (!isEmptyVal(local)) {
        await pushKey(r.key, local);           // migrate real local data up; keep local
      }
      // Record the settled value so mount-time persistence writes don't re-push.
      lastSynced[r.key] = rawGet(r.key);
    }
    active = true;
    startListening();
  }

  window.INLEARN_STORE = { hydrate, SYNC_KEYS };
})();
