/**
 * idb.js
 * Inventory Counter PWA — IndexedDB schema & helpers
 * Stores: assignmentSnapshot | itemLookup | countQueue | decisionQueue | sessionCache | metadata
 */

const IDB = (() => {
  const DB_NAME    = 'invcount-db';
  const DB_VERSION = 1;

  function open() {
    return new Promise((resolve, reject) => {
      if (window.__invcount_IDB) return resolve(window.__invcount_IDB);
      const req = indexedDB.open(DB_NAME, DB_VERSION);
      req.onupgradeneeded = ev => {
        const db = ev.target.result;
        if (!db.objectStoreNames.contains('assignmentSnapshot'))
          db.createObjectStore('assignmentSnapshot', { keyPath: 'id' });
        if (!db.objectStoreNames.contains('itemLookup'))
          db.createObjectStore('itemLookup', { keyPath: 'id' });
        if (!db.objectStoreNames.contains('countQueue')) {
          const s = db.createObjectStore('countQueue', { keyPath: 'localId', autoIncrement: true });
          s.createIndex('assignment_id', 'assignment_id', { unique: false });
        }
        if (!db.objectStoreNames.contains('decisionQueue')) {
          const s = db.createObjectStore('decisionQueue', { keyPath: 'localId', autoIncrement: true });
          s.createIndex('check_review_id', 'check_review_id', { unique: false });
        }
        if (!db.objectStoreNames.contains('sessionCache'))
          db.createObjectStore('sessionCache', { keyPath: 'id' });
        if (!db.objectStoreNames.contains('metadata'))
          db.createObjectStore('metadata', { keyPath: 'key' });
      };
      req.onsuccess = ev => {
        window.__invcount_IDB = ev.target.result;
        resolve(window.__invcount_IDB);
      };
      req.onerror = ev => reject(ev.target.error);
    });
  }

  function store(name) {
    return open().then(db => db.transaction(name, 'readwrite').objectStore(name));
  }
  function storeRO(name) {
    return open().then(db => db.transaction(name, 'readonly').objectStore(name));
  }

  /* ── Generic CRUD ───────────────────────────────────────────── */
  function put(storeName, record) { return _put(storeName, record); }
  function putAll(storeName, records) {
    return open().then(db => {
      const tx = db.transaction(storeName, 'readwrite');
      const s  = tx.objectStore(storeName);
      records.forEach(r => s.put(r));
      return tx.complete;
    });
  }
  function get(storeName, key) { return _get(storeName, key); }
  function getAll(storeName) { return _getAll(storeName); }
  function getByIndex(storeName, indexName, value) { return _getByIndex(storeName, indexName, value); }
  function del(storeName, key) { return _del(storeName, key); }
  function clear(storeName) { return _clear(storeName); }
  function count(storeName) { return _count(storeName); }

  /* ── Queues ─────────────────────────────────────────────────── */
  function enqueueCount(payload) {
    const entry = { ...payload, createdAt: Date.now() };
    return put('countQueue', entry);
  }
  function enqueueDecision(payload) {
    const entry = { ...payload, createdAt: Date.now() };
    return put('decisionQueue', entry);
  }
  function getCountQueue() { return getAll('countQueue'); }
  function getDecisionQueue() { return getAll('decisionQueue'); }
  function clearCountEntry(localId) { return del('countQueue', localId); }
  function clearDecisionEntry(localId) { return del('decisionQueue', localId); }

  /* ── Metadata ───────────────────────────────────────────────── */
  function setMeta(key, value) { return put('metadata', { key, value }); }
  function getMeta(key) { return _get('metadata', key); }

  /* ── Internal helpers ───────────────────────────────────────── */
  function _put(storeName, record) {
    return open().then(db => {
      return new Promise((resolve, reject) => {
        const tx  = db.transaction(storeName, 'readwrite');
        const req = tx.objectStore(storeName).put(record);
        req.onsuccess = () => resolve(record);
        req.onerror   = e => reject(e.target.error);
      });
    });
  }
  function _get(storeName, key) {
    return open().then(db => {
      return new Promise((resolve, reject) => {
        const tx  = db.transaction(storeName, 'readonly');
        const req = tx.objectStore(storeName).get(key);
        req.onsuccess = () => resolve(req.result || null);
        req.onerror   = e => reject(e.target.error);
      });
    });
  }
  function _getAll(storeName) {
    return open().then(db => {
      return new Promise((resolve, reject) => {
        const tx  = db.transaction(storeName, 'readonly');
        const req = tx.objectStore(storeName).getAll();
        req.onsuccess = () => resolve(req.result || []);
        req.onerror   = e => reject(e.target.error);
      });
    });
  }
  function _getByIndex(storeName, indexName, value) {
    return open().then(db => {
      return new Promise((resolve, reject) => {
        const tx  = db.transaction(storeName, 'readonly');
        const idx = tx.objectStore(storeName).index(indexName);
        const req = idx.getAll(value);
        req.onsuccess = () => resolve(req.result || []);
        req.onerror   = e => reject(e.target.error);
      });
    });
  }
  function _del(storeName, key) {
    return open().then(db => {
      return new Promise((resolve, reject) => {
        const tx  = db.transaction(storeName, 'readwrite');
        const req = tx.objectStore(storeName).delete(key);
        req.onsuccess = () => resolve();
        req.onerror   = e => reject(e.target.error);
      });
    });
  }
  function _clear(storeName) {
    return open().then(db => {
      return new Promise((resolve, reject) => {
        const tx  = db.transaction(storeName, 'readwrite');
        const req = tx.objectStore(storeName).clear();
        req.onsuccess = () => resolve();
        req.onerror   = e => reject(e.target.error);
      });
    });
  }
  function _count(storeName) {
    return open().then(db => {
      return new Promise((resolve, reject) => {
        const tx  = db.transaction(storeName, 'readonly');
        const req = tx.objectStore(storeName).count();
        req.onsuccess = () => resolve(req.result);
        req.onerror   = e => reject(e.target.error);
      });
    });
  }

  return {
    open, put, putAll, get, getAll, getByIndex, del, clear, count,
    enqueueCount, enqueueDecision, getCountQueue, getDecisionQueue,
    clearCountEntry, clearDecisionEntry,
    setMeta, getMeta,
  };
})();
