// /home/Autopartes/pos/static/js/sync-engine.js
// Nexus POS — Offline sync engine using IndexedDB

(function () {
  'use strict';

  var DB_NAME    = 'nexus_pos_offline';
  var DB_VERSION = 2;
  var QUEUE_STORE       = 'sync_queue';
  var INVENTORY_STORE   = 'inventory_cache';
  var TOP_PARTS_STORE   = 'cached_parts';

  var db = null;

  // ─── IndexedDB setup ──────────────────────────────────────────
  function openDB() {
    return new Promise(function (resolve, reject) {
      if (db) { resolve(db); return; }
      var req = indexedDB.open(DB_NAME, DB_VERSION);
      req.onupgradeneeded = function (e) {
        var d = e.target.result;
        if (!d.objectStoreNames.contains(QUEUE_STORE)) {
          d.createObjectStore(QUEUE_STORE, { keyPath: 'id', autoIncrement: true });
        }
        if (!d.objectStoreNames.contains(INVENTORY_STORE)) {
          var inv = d.createObjectStore(INVENTORY_STORE, { keyPath: 'item_id' });
          inv.createIndex('sku', 'sku', { unique: false });
          inv.createIndex('name', 'name', { unique: false });
        }
        if (!d.objectStoreNames.contains(TOP_PARTS_STORE)) {
          var tp = d.createObjectStore(TOP_PARTS_STORE, { keyPath: 'part_number' });
          tp.createIndex('name', 'name', { unique: false });
          tp.createIndex('category', 'category', { unique: false });
        }
      };
      req.onsuccess = function (e) {
        db = e.target.result;
        resolve(db);
      };
      req.onerror = function () { reject(req.error); };
    });
  }

  // ─── Queue operations for offline replay ──────────────────────
  function queueOperation(url, method, body) {
    return openDB().then(function (d) {
      return new Promise(function (resolve, reject) {
        var tx = d.transaction(QUEUE_STORE, 'readwrite');
        tx.objectStore(QUEUE_STORE).add({
          url: url,
          method: method,
          body: body || null,
          timestamp: Date.now()
        });
        tx.oncomplete = function () { resolve(); };
        tx.onerror    = function () { reject(tx.error); };
      });
    });
  }

  // ─── Process queued operations ────────────────────────────────
  function processQueue() {
    return openDB().then(function (d) {
      return new Promise(function (resolve, reject) {
        var tx = d.transaction(QUEUE_STORE, 'readonly');
        var req = tx.objectStore(QUEUE_STORE).getAll();
        req.onsuccess = function () { resolve(req.result); };
        req.onerror   = function () { reject(req.error); };
      });
    }).then(function (ops) {
      if (!ops.length) return Promise.resolve({ synced: 0 });

      // Replay in order
      var chain = Promise.resolve();
      var synced = 0;
      var failed = 0;

      ops.forEach(function (op) {
        chain = chain.then(function () {
          var opts = { method: op.method, headers: { 'Content-Type': 'application/json' } };
          if (op.body) opts.body = JSON.stringify(op.body);

          return fetch(op.url, opts).then(function (resp) {
            if (resp.ok) {
              synced++;
              return removeFromQueue(op.id);
            }
            failed++;
          }).catch(function () {
            failed++;
          });
        });
      });

      return chain.then(function () {
        return { synced: synced, failed: failed, total: ops.length };
      });
    });
  }

  function removeFromQueue(id) {
    return openDB().then(function (d) {
      return new Promise(function (resolve, reject) {
        var tx = d.transaction(QUEUE_STORE, 'readwrite');
        tx.objectStore(QUEUE_STORE).delete(id);
        tx.oncomplete = function () { resolve(); };
        tx.onerror    = function () { reject(tx.error); };
      });
    });
  }

  function getQueueCount() {
    return openDB().then(function (d) {
      return new Promise(function (resolve, reject) {
        var tx = d.transaction(QUEUE_STORE, 'readonly');
        var req = tx.objectStore(QUEUE_STORE).count();
        req.onsuccess = function () { resolve(req.result); };
        req.onerror   = function () { reject(req.error); };
      });
    });
  }

  // ─── Inventory cache ──────────────────────────────────────────
  function cacheInventory() {
    return fetch('/pos/api/sync/inventory').then(function (resp) {
      if (!resp.ok) throw new Error('Sync inventory failed: ' + resp.status);
      return resp.json();
    }).then(function (data) {
      var items = data.items || [];
      return openDB().then(function (d) {
        return new Promise(function (resolve, reject) {
          var tx = d.transaction(INVENTORY_STORE, 'readwrite');
          var store = tx.objectStore(INVENTORY_STORE);
          store.clear();
          items.forEach(function (item) { store.put(item); });
          tx.oncomplete = function () { resolve(items.length); };
          tx.onerror    = function () { reject(tx.error); };
        });
      });
    });
  }

  function getCachedInventory(query) {
    return openDB().then(function (d) {
      return new Promise(function (resolve, reject) {
        var tx = d.transaction(INVENTORY_STORE, 'readonly');
        var req = tx.objectStore(INVENTORY_STORE).getAll();
        req.onsuccess = function () {
          var all = req.result;
          if (!query) { resolve(all); return; }

          var q = query.toLowerCase();
          var filtered = all.filter(function (item) {
            return (item.sku && item.sku.toLowerCase().indexOf(q) !== -1) ||
                   (item.name && item.name.toLowerCase().indexOf(q) !== -1) ||
                   (item.barcode && item.barcode.toLowerCase().indexOf(q) !== -1);
          });
          resolve(filtered);
        };
        req.onerror = function () { reject(req.error); };
      });
    });
  }

  // ─── Top parts cache (offline catalog) ────────────────────────
  function cacheTopParts() {
    return fetch('/pos/api/sync/top-parts').then(function (resp) {
      if (!resp.ok) throw new Error('Sync top-parts failed: ' + resp.status);
      return resp.json();
    }).then(function (data) {
      var parts = data.parts || [];
      return openDB().then(function (d) {
        return new Promise(function (resolve, reject) {
          var tx = d.transaction(TOP_PARTS_STORE, 'readwrite');
          var store = tx.objectStore(TOP_PARTS_STORE);
          store.clear();
          parts.forEach(function (p) { store.put(p); });
          tx.oncomplete = function () {
            console.log('[SyncEngine] Cached ' + parts.length + ' top parts');
            resolve(parts.length);
          };
          tx.onerror = function () { reject(tx.error); };
        });
      });
    });
  }

  function searchCachedParts(query) {
    return openDB().then(function (d) {
      return new Promise(function (resolve, reject) {
        var tx = d.transaction(TOP_PARTS_STORE, 'readonly');
        var req = tx.objectStore(TOP_PARTS_STORE).getAll();
        req.onsuccess = function () {
          var all = req.result;
          if (!query) { resolve(all); return; }

          var q = query.toLowerCase();
          var filtered = all.filter(function (p) {
            return (p.part_number && p.part_number.toLowerCase().indexOf(q) !== -1) ||
                   (p.name && p.name.toLowerCase().indexOf(q) !== -1) ||
                   (p.category && p.category.toLowerCase().indexOf(q) !== -1) ||
                   (p.brand && p.brand.toLowerCase().indexOf(q) !== -1);
          });
          resolve(filtered);
        };
        req.onerror = function () { reject(req.error); };
      });
    });
  }

  // ─── Connectivity helpers ─────────────────────────────────────
  function isOnline() {
    return navigator.onLine;
  }

  // ─── Auto-sync on reconnect ───────────────────────────────────
  window.addEventListener('online', function () {
    console.log('[SyncEngine] Online — processing queue...');
    processQueue().then(function (result) {
      if (result.synced > 0) {
        console.log('[SyncEngine] Synced ' + result.synced + ' operations');
      }
    }).catch(function (err) {
      console.error('[SyncEngine] Queue processing error:', err);
    });
  });

  window.addEventListener('offline', function () {
    console.log('[SyncEngine] Offline — operations will be queued');
  });

  // Listen for SW sync messages
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.addEventListener('message', function (event) {
      if (event.data && event.data.type === 'SYNC_REQUESTED') {
        processQueue();
      }
    });
  }

  // ─── Init DB on load ──────────────────────────────────────────
  openDB().catch(function (err) {
    console.error('[SyncEngine] Failed to open IndexedDB:', err);
  });

  // ─── Public API ───────────────────────────────────────────────
  window.SyncEngine = {
    queueOperation:     queueOperation,
    processQueue:       processQueue,
    getQueueCount:      getQueueCount,
    isOnline:           isOnline,
    cacheInventory:     cacheInventory,
    getCachedInventory: getCachedInventory,
    cacheTopParts:      cacheTopParts,
    searchCachedParts:  searchCachedParts
  };

})();
