/**
 * offline-queue.js
 * Inventory Counter PWA — Client-side offline queue manager
 *
 * Exports on window.offlineQueue:
 *   enqueueCount(payload)       → for single count_items.php submit_count
 *   enqueueBulkCounts(payloads) → for bulk_submit_counts
 *   enqueueDecision(payload)    → for checker review decisions
 *   drainQueue()                → POST every pending record to the server
 *   getQueueCount()             → total pending records
 */

window.offlineQueue = (() => {
  const SYNC_ENDPOINT = '/invcount/counter/api_sync.php';
  const BATCH_LIMIT   = 50;

  /* ── Enqueue helpers ─────────────────────────────────────────── */
  function enqueueCount(payload) {
    const record = {
      type:            'count',
      assignment_id:   payload.assignment_id,
      counted_quantity:payload.counted_quantity,
      count_method:    payload.count_method,
      notes:           payload.notes,
    };
    return IDB.enqueueCount(record);
  }

  function enqueueBulkCounts(payloads) {
    const promises = payloads.map(p => enqueueCount(p));
    return Promise.all(promises);
  }

  function enqueueDecision(payload) {
    const record = {
      type:           'decision',
      assignment_id:  payload.assignment_id,
      decision:       payload.decision,
      comments:       payload.comments,
      check_review_id: payload.check_review_id ?? null,
    };
    return IDB.enqueueDecision(record);
  }

  /* ── Read helpers ────────────────────────────────────────────── */
  function getQueueCount() {
    return Promise.all([IDB.count('countQueue'), IDB.count('decisionQueue')])
      .then(([c, d]) => c + d);
  }

  /* ── Drain ───────────────────────────────────────────────────── */
  function drainQueue(signal) {
    return persistSyncFlag('draining', true).then(() => showStatusPill('Syncing…'))
      .then(() => drainCounts(signal))
      .then(() => drainDecisions(signal))
      .then(() => {
        persistSyncFlag('lastSync', Date.now());
        showStatusPill('Synced');
        setTimeout(() => hideStatusPill(), 3000);
      })
      .catch(err => {
        console.warn('[OfflineQueue] drain failed:', err);
        showStatusPill('Offline — will retry');
      })
      .finally(() => persistSyncFlag('draining', false));
  }

  function drainCounts(signal) {
    return IDB.getCountQueue().then(records => {
      if (!records.length) return;
      let batch = records.slice(0, BATCH_LIMIT);
      const recs = batch.map(r => {
        const { localId, createdAt, ...body } = r;
        return body;
      });
      return api_send(SYNC_ENDPOINT, { type: 'counts', records: recs }, signal).then(resp => {
        if (resp && resp.local_ids) {
          resp.local_ids.forEach(id => IDB.clearCountEntry(id));
        }
      }).catch(err => { throw err; });
    });
  }

  function drainDecisions(signal) {
    return IDB.getDecisionQueue().then(records => {
      if (!records.length) return;
      let batch = records.slice(0, BATCH_LIMIT);
      const recs = batch.map(r => {
        const { localId, createdAt, ...body } = r;
        return body;
      });
      return api_send(SYNC_ENDPOINT, { type: 'decisions', records: recs }, signal).then(resp => {
        if (resp && resp.local_ids) {
          resp.local_ids.forEach(id => IDB.clearDecisionEntry(id));
        }
      }).catch(err => { throw err; });
    });
  }

  /* ── Network bridge ──────────────────────────────────────────── */
  function api_send(url, body, signal) {
    return fetch(url, {
      method:  'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Cache-Age':  '0',
      },
      body:     JSON.stringify(body),
      signal,
    }).then(resp => {
      if (!resp.ok) throw new Error('HTTP ' + resp.status);
      return resp.json();
    });
  }

  /* ── Background Sync trigger ─────────────────────────────────── */
  function registerSyncTag(tag) {
    if (!('serviceWorker' in navigator) || !('SyncManager' in window)) return;
    navigator.serviceWorker.ready.then(reg => {
      return reg.sync.register(tag);
    }).catch(err => console.warn('[OfflineQueue] sync tag failed:', err));
  }

  /* ── Sync flag storage (IndexedDB metadata) ───────────────────── */
  function persistSyncFlag(key, value) {
    return IDB.setMeta(key, value);
  }

  /* ── Visibility change drain ─────────────────────────────────── */
  function onVisibilityChange() {
    if (document.visibilityState === 'visible' && navigator.onLine) {
      drainQueue();
    }
  }

  /* ── Status pill ─────────────────────────────────────────────── */
  let _pillEl = null;

  function getOrCreatePill() {
    if (_pillEl) return _pillEl;
    _pillEl = document.createElement('div');
    _pillEl.id = 'sync-status-pill';
    Object.assign(_pillEl.style, {
      position:      'fixed',
      bottom:        '12px',
      right:         '12px',
      padding:       '6px 14px',
      background:    '#16213e',
      color:         '#fff',
      borderRadius:  '20px',
      fontSize:      '.8rem',
      fontWeight:    '500',
      zIndex:        '9999',
      display:       'none',
      transition:    'opacity .3s',
      boxShadow:     '0 2px 8px rgba(0,0,0,.25)',
    });
    document.body.appendChild(_pillEl);
    return _pillEl;
  }

  function showStatusPill(msg) {
    const pill = getOrCreatePill();
    pill.textContent = msg;
    pill.style.display  = 'block';
    pill.style.opacity  = '1';
  }

  function hideStatusPill() {
    if (_pillEl) { _pillEl.style.opacity = '0'; setTimeout(() => { _pillEl.style.display = 'none'; }, 300); }
  }

  /* ── Init ────────────────────────────────────────────────────── */
  function init() {
    // Drain whenever connectivity is restored
    window.addEventListener('online', () => drainQueue());
    window.addEventListener('visibilitychange', onVisibilityChange);
    // Drain once on page load if we have queued records and are online
    if (navigator.onLine) {
      getQueueCount().then(n => {
        if (n > 0) drainQueue();
      });
    }
  }

  /* Auto-init */
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }

  /* Public API */
  return {
    enqueueCount, enqueueBulkCounts, enqueueDecision,
    drainQueue, getQueueCount, registerSyncTag,
    showStatusPill, hideStatusPill,
  };
})();
