/* ═══════════════════════════════════════════════════════════════════
   Al Moasis · Dashboard v3 — WhatsApp tab
   ═══════════════════════════════════════════════════════════════════

   Lifecycle (called by app.js pane router):
     onShow()  — start polling status when tab becomes visible
     onHide()  — stop polling when tab is dismissed

   Reads from existing gateway endpoints (already exercised in v3.0.0-rc.2):
     GET  /api/tenants/:id/whatsapp/status     — read-only peek (our v3.0.1 fix)
     POST /api/tenants/:id/whatsapp/qr         — explicit pair start
     POST /api/tenants/:id/whatsapp/pair-code  — alternate pair via 8-char code
     POST /api/tenants/:id/whatsapp/reset      — wipe creds + fresh pair
     POST /api/tenants/:id/whatsapp/disconnect — log out
*/

'use strict';

(function () {
  // Polling intervals. Aggressive polling during pairing causes the QR
  // to LOOK like it's flickering (even when content is identical) because
  // the browser re-decodes the image. 2.5s is the sweet spot — fast
  // enough to catch ref rotation, slow enough that the human scanning
  // the QR with their phone can hold still.
  const POLL_FAST = 2500;
  const POLL_SLOW = 5000;

  let pollTimer = null;
  let countdownTimer = null;
  let lastQrAt = null;
  let codeDeadline = 0;
  let codeCountdownTimer = null;
  let visible = false;
  // Self-heal: if the backend stops emitting fresh QRs (circuit-breaker gave
  // up after un-scanned attempts), the displayed code freezes and every scan
  // fails. When the shown QR goes stale we auto-reset for a fresh session.
  let lastAutoResetAt = 0;
  // (v3.1) Lock the displayed QR for a SHORT window so the user has a stable
  // scanning target, but well under WhatsApp's ~20s ref validity. The old 25s
  // lock guaranteed that a scan in the back half of the window hit a ref
  // WhatsApp had already rotated+invalidated → "couldn't link the device".
  // 14s keeps a steady image AND always shows a still-valid ref (14s + one
  // 2.5s poll < 20s). The `isDifferent` guard already prevents flicker on
  // identical refs, so this is purely a freshness ceiling.
  // Anchor freshness to backend's last_qr_at, not paint time. Baileys
  // rotates the QR ref ~20s after EMISSION, regardless of when the
  // dashboard painted it. The old 14s-from-paint lock could keep showing
  // a stale image after WhatsApp already invalidated the ref, so the
  // phone scanned a dead code and saw "couldn't link the device".
  // Pin from emission and accept a fresh QR slightly before expiry.
  const QR_MAX_AGE_MS = 16_000;

  const $ = (sel) => document.querySelector(sel);

  function setStatus(state, label) {
    const dot   = $('[data-bind="wa-status-dot"]');
    const lbl   = $('[data-bind="wa-status-label"]');
    const navDot = $('[data-bind="wa-nav-dot"]');
    if (lbl) lbl.textContent = label;
    if (!dot) return;
    dot.classList.remove('bg-emerald-500','bg-amber-500','bg-rose-500','bg-muted','dot-pulse-emerald');
    if (state === 'connected') {
      dot.classList.add('bg-emerald-500','dot-pulse-emerald');
      if (navDot) navDot.hidden = false;
    } else if (state === 'pending_qr' || state === 'connecting') {
      dot.classList.add('bg-amber-500');
      if (navDot) navDot.hidden = true;
    } else if (state === 'logged_out' || state === 'disconnected') {
      dot.classList.add('bg-rose-500');
      if (navDot) navDot.hidden = true;
    } else {
      dot.classList.add('bg-muted');
      if (navDot) navDot.hidden = true;
    }
  }

  function statusLabel(state, lastError) {
    if (state === 'connected')   return 'متصل';
    if (state === 'pending_qr')  return 'بانتظار المسح…';
    if (state === 'connecting')  return 'جارٍ الاتصال…';
    if (state === 'disconnected') return lastError ? `مفصول · ${lastError.slice(0, 32)}` : 'مفصول';
    if (state === 'logged_out')  return 'تسجيل خروج — يحتاج إقران جديد';
    return 'غير معروف';
  }

  function renderQrFrame(data) {
    const img   = $('[data-bind="wa-qr-img"]');
    const ph    = $('[data-bind="wa-qr-placeholder"]');
    const cd    = $('[data-bind="wa-qr-countdown"]');

    if (data.qr_png && data.status === 'pending_qr') {
      // Decision: paint the current backend QR if (a) we haven't painted yet,
      // (b) the backend rotated the QR (new last_qr_at), OR (c) the QR we're
      // showing is older than QR_MAX_AGE_MS from its EMISSION time — i.e. the
      // phone is about to scan a ref WhatsApp has already invalidated.
      const emittedAt = Number(data.last_qr_at) || 0;
      const currentAge = emittedAt ? Date.now() - emittedAt : Infinity;
      const isFirstPaint = !img.dataset.lastSrc;
      const isDifferent = img.dataset.lastSrc !== data.qr_png;
      const rotatedByBackend = isDifferent && emittedAt && emittedAt > (Number(img.dataset.lastEmittedAt) || 0);
      const overAge = currentAge > QR_MAX_AGE_MS;

      if (img && (isFirstPaint || rotatedByBackend || overAge)) {
        img.src = data.qr_png;
        img.dataset.lastSrc = data.qr_png;
        img.dataset.lastEmittedAt = String(emittedAt);
        img.classList.remove('hidden');
        lastQrAt = emittedAt || Date.now();
      } else if (img && img.classList.contains('hidden')) {
        img.classList.remove('hidden');
      }
      if (ph) ph.classList.add('hidden');
      if (cd) cd.classList.remove('hidden');
    } else if (data.status === 'connected') {
      if (img) img.classList.add('hidden');
      if (ph)  {
        ph.classList.remove('hidden');
        ph.innerHTML = `
          <i data-lucide="check-circle-2" class="w-8 h-8 inline-block mb-2 text-emerald-600"></i>
          <div class="text-emerald-700 font-medium">متصل بنجاح</div>
          <div class="text-[11px] text-muted mt-1">جاهز للردّ على العملاء</div>`;
        if (window.lucide?.createIcons) window.lucide.createIcons({ attrs: { 'stroke-width': 1.75 } });
      }
      if (cd) cd.classList.add('hidden');
    } else {
      if (img) img.classList.add('hidden');
      if (ph) {
        ph.classList.remove('hidden');
        ph.innerHTML = data.status === 'disconnected'
          ? `<i data-lucide="wifi-off" class="w-6 h-6 inline-block mb-2 text-rose-500"></i>
             <div>غير متصل</div>
             <div class="text-[11px] mt-1">اضغط "تجديد الرمز" للبدء</div>`
          : `<i data-lucide="loader" class="w-6 h-6 animate-spin inline-block mb-2"></i>
             <div>جارٍ تجهيز الرمز…</div>`;
        if (window.lucide?.createIcons) window.lucide.createIcons({ attrs: { 'stroke-width': 1.75 } });
      }
      if (cd) cd.classList.add('hidden');
    }

    // Connected-state card visibility
    const card = $('[data-bind="wa-connected-card"]');
    if (card) card.classList.toggle('hidden', data.status !== 'connected');
    const jid = $('[data-bind="wa-jid"]');
    if (jid && data.jid) jid.textContent = data.jid.split('@')[0];
  }

  function updateQrCountdown() {
    const el = $('[data-bind="wa-qr-countdown-seconds"]');
    if (!el || !lastQrAt) return;
    const ageSec = Math.floor((Date.now() - lastQrAt) / 1000);
    const left = Math.max(0, 60 - ageSec);
    el.textContent = left;
  }

  async function fetchStatus() {
    if (!window.CURRENT_TENANT_ID) return;
    try {
      const r = await window.__moasis.api(`/api/tenants/${window.CURRENT_TENANT_ID}/whatsapp/status`);
      const d = r?.data || {};
      setStatus(d.status, statusLabel(d.status, d.last_error));
      renderQrFrame(d);

      // Self-heal a frozen/stale QR: if we're still waiting to pair but the
      // shown code hasn't refreshed in >45s, the backend likely stopped
      // emitting (gave-up circuit breaker). Force a fresh session once, with a
      // 60s cooldown so we never reset-loop.
      if (d.status === 'pending_qr' && lastQrAt &&
          (Date.now() - lastQrAt > 45_000) && (Date.now() - lastAutoResetAt > 60_000)) {
        lastAutoResetAt = Date.now();
        const imgEl = $('[data-bind="wa-qr-img"]');
        if (imgEl) {
          imgEl.dataset.lastSrc = '';      // force repaint of the new QR
          imgEl.dataset.lastEmittedAt = '0';
        }
        console.info('WA: QR stale >45s — auto-resetting for a fresh code');
        try { await window.__moasis.api(`/api/tenants/${window.CURRENT_TENANT_ID}/whatsapp/reset`, { method: 'POST' }); } catch (e) { /* non-fatal */ }
      }

      const interval = (d.status === 'pending_qr' || d.status === 'connecting') ? POLL_FAST : POLL_SLOW;
      if (visible) pollTimer = setTimeout(fetchStatus, interval);
    } catch (err) {
      console.warn('WA status fetch failed:', err.message);
      setStatus('disconnected', 'تعذّر الاتصال بالخادم');
      if (visible) pollTimer = setTimeout(fetchStatus, POLL_SLOW * 2);
    }
  }

  async function triggerQr() {
    if (!window.CURRENT_TENANT_ID) return;
    try {
      await window.__moasis.api(`/api/tenants/${window.CURRENT_TENANT_ID}/whatsapp/qr`, { method: 'POST' });
      fetchStatus();
    } catch (err) {
      console.warn('WA QR trigger failed:', err.message);
    }
  }

  // Visual feedback helper — turns a button into "جارٍ التنفيذ…" while the
  // async action runs. Tauri's native confirm() dialog is unreliable, and
  // even when it works it adds a confirmation gate the user didn't ask for.
  // Just do the thing + show progress.
  async function withButtonFeedback(btn, label, fn) {
    if (!btn) return fn();
    const originalHtml = btn.innerHTML;
    const originalDisabled = btn.disabled;
    btn.disabled = true;
    btn.innerHTML = `
      <i data-lucide="loader-circle" class="w-4 h-4 animate-spin"></i>
      <span>${label}</span>
    `;
    if (window.lucide?.createIcons) window.lucide.createIcons({ attrs: { 'stroke-width': 1.75 } });
    try {
      await fn();
    } finally {
      btn.innerHTML = originalHtml;
      btn.disabled = originalDisabled;
      if (window.lucide?.createIcons) window.lucide.createIcons({ attrs: { 'stroke-width': 1.75 } });
    }
  }

  async function resetSession(ev) {
    if (!window.CURRENT_TENANT_ID) return;
    const btn = ev?.currentTarget;
    await withButtonFeedback(btn, 'جارٍ التجديد…', async () => {
      try {
        await window.__moasis.api(`/api/tenants/${window.CURRENT_TENANT_ID}/whatsapp/reset`, { method: 'POST' });
        await fetchStatus();
      } catch (err) {
        const errEl = document.querySelector('[data-bind="wa-status-label"]');
        if (errEl) errEl.textContent = `فشل التجديد: ${err.message}`;
      }
    });
  }

  async function disconnect(ev) {
    if (!window.CURRENT_TENANT_ID) return;
    const btn = ev?.currentTarget;
    await withButtonFeedback(btn, 'جارٍ القطع…', async () => {
      try {
        await window.__moasis.api(`/api/tenants/${window.CURRENT_TENANT_ID}/whatsapp/disconnect`, { method: 'POST' });
        await fetchStatus();
      } catch (err) {
        const errEl = document.querySelector('[data-bind="wa-status-label"]');
        if (errEl) errEl.textContent = `فشل القطع: ${err.message}`;
      }
    });
  }

  function startCodeCountdown(seconds) {
    if (codeCountdownTimer) clearInterval(codeCountdownTimer);
    codeDeadline = Date.now() + seconds * 1000;
    const tick = () => {
      const left = Math.max(0, Math.ceil((codeDeadline - Date.now()) / 1000));
      const el = $('[data-bind="wa-code-timer"]');
      const val = $('[data-bind="wa-code-value"]');
      if (el) {
        if (left > 0) {
          el.textContent = `⏱ ${left} ث`;
          el.style.color = left < 15 ? '#E11D48' : '#0E9A6F';
        } else {
          el.textContent = '⛔ انتهت الصلاحية — اطلب كود جديد';
          el.style.color = '#E11D48';
          if (val) {
            val.style.textDecoration = 'line-through';
            val.style.opacity = '0.5';
          }
          clearInterval(codeCountdownTimer);
          codeCountdownTimer = null;
        }
      }
    };
    tick();
    codeCountdownTimer = setInterval(tick, 500);
  }

  async function requestPairCode() {
    if (!window.CURRENT_TENANT_ID) return;
    const phoneEl = $('#wa-phone-input');
    const errEl   = $('[data-bind="wa-code-error"]');
    const resBox  = $('[data-bind="wa-code-result"]');
    const valEl   = $('[data-bind="wa-code-value"]');

    const phone = (phoneEl?.value || '').trim();
    if (!/^\+?\d{10,15}$/.test(phone)) {
      if (errEl) {
        errEl.textContent = 'أدخل رقماً بصيغة دولية صحيحة (مثل +966581978135).';
        errEl.classList.remove('hidden');
      }
      return;
    }
    if (errEl) errEl.classList.add('hidden');

    // Reset previous result UI
    if (valEl) {
      valEl.style.textDecoration = '';
      valEl.style.opacity = '';
    }

    try {
      const r = await window.__moasis.api(
        `/api/tenants/${window.CURRENT_TENANT_ID}/whatsapp/pair-code`,
        { method: 'POST', body: JSON.stringify({ phone }) }
      );
      if (r.success && r.data?.formatted) {
        if (valEl) valEl.textContent = r.data.formatted;
        if (resBox) resBox.classList.remove('hidden');
        startCodeCountdown(60);
      } else {
        throw new Error(r.error || 'لم يصدر الكود');
      }
    } catch (err) {
      if (errEl) {
        errEl.textContent = `فشل: ${err.message || err}. جرّب QR أو انتظر ١٠ دقائق.`;
        errEl.classList.remove('hidden');
      }
    }
  }

  function switchMethod(method) {
    document.querySelectorAll('[data-wa-method]').forEach((b) => {
      b.classList.toggle('wa-method-active', b.dataset.waMethod === method);
    });
    document.querySelectorAll('[data-wa-view]').forEach((v) => {
      v.classList.toggle('hidden', v.dataset.waView !== method);
    });
  }

  function wire() {
    document.querySelectorAll('[data-wa-method]').forEach((b) => {
      b.addEventListener('click', () => switchMethod(b.dataset.waMethod));
    });
    document.querySelectorAll('[data-action="wa-reset"]').forEach((b) => {
      b.addEventListener('click', (ev) => resetSession(ev));
    });
    document.querySelectorAll('[data-action="wa-disconnect"]').forEach((b) => {
      b.addEventListener('click', (ev) => disconnect(ev));
    });
    document.querySelectorAll('[data-action="wa-pair-code"]').forEach((b) => {
      b.addEventListener('click', requestPairCode);
    });
    // QR-countdown ticker (one per second, independent of poll cadence)
    if (countdownTimer) clearInterval(countdownTimer);
    countdownTimer = setInterval(updateQrCountdown, 1000);
  }

  function onShow() {
    visible = true;
    if (pollTimer) clearTimeout(pollTimer);
    fetchStatus().then(() => {
      // If the session is in a dead state (logged_out / disconnected with
      // "Connection Failure" / any last_error), POST /qr won't help — the
      // Baileys socket is stuck. Only /reset wipes the auth dir + clears
      // the rate-limit bucket + spawns a fresh socket. Use that instead.
      window.__moasis.api(`/api/tenants/${window.CURRENT_TENANT_ID}/whatsapp/status`)
        .then((r) => {
          const d = r?.data || {};
          const s = d.status;
          // Already healthy → nothing to do
          if (s === 'connected' || s === 'pending_qr' || s === 'connecting') return;
          // Stuck → full reset
          if (s === 'logged_out' || s === 'disconnected' || d.last_error) {
            window.__moasis.api(
              `/api/tenants/${window.CURRENT_TENANT_ID}/whatsapp/reset`,
              { method: 'POST' }
            ).then(() => fetchStatus())
             .catch((err) => console.warn('WA reset failed:', err.message));
            return;
          }
          // No session yet (first open) → simple /qr is fine
          triggerQr();
        })
        .catch(() => { /* main poll will retry */ });
    });
  }

  function onHide() {
    visible = false;
    if (pollTimer) { clearTimeout(pollTimer); pollTimer = null; }
  }

  // Initialize after DOM is ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', wire);
  } else {
    wire();
  }

  window.__moasisWhatsApp = { onShow, onHide, fetchStatus };
})();
