/**
 * Corelatin React Islands — Babel Standalone (no build step)
 * Components: NotificationPanel, StatCounterGrid
 *
 * TIMING STRATEGY:
 *   Babel compiles this file asynchronously, so we must not rely
 *   on DOMContentLoaded for mounting — the event may have already
 *   fired before Babel finishes. Instead, we mount synchronously
 *   at the bottom of this file (DOM nodes already exist because
 *   the <script> tag is at the very end of <body>), and we install
 *   window.toggleNotifPanel as a simple queuing stub before any
 *   React code runs, so the bell button always works.
 */

const { useState, useEffect, useCallback, useRef } = React;

/* ─────────────────────────────────────────────────────────────
   GLOBAL STUBS — installed before React mounts so PHP-rendered
   buttons (onclick="toggleNotifPanel()") never throw undefined.
   The real implementations replace these once React is ready.
───────────────────────────────────────────────────────────── */
(function installStubs() {
  let _pendingOpen = false;

  window.toggleNotifPanel = function () {
    _pendingOpen = !_pendingOpen;
    // Will be overwritten by React component once mounted
  };
  window.openNotifPanel   = function () { _pendingOpen = true; };
  window.closeNotifPanel  = function () { _pendingOpen = false; };
  window.markAllRead      = function () {};
  window.markRead         = function () {};
  window.fetchNotifCount  = function () {};
  window.fetchNotifications = function () {};
  window._notifPendingOpen = () => _pendingOpen;
  window._notifClearPending = () => { _pendingOpen = false; };
})();

/* ─────────────────────────────────────────────────────────────
   UTILITIES
───────────────────────────────────────────────────────────── */
const NOTIF_TYPES = {
  new_booking:       { icon: 'fa-calendar-plus',         bg: '#fef3c7', color: '#d97706' },
  booking_confirmed: { icon: 'fa-calendar-check',        bg: '#dcfce7', color: '#16a34a' },
  assigned:          { icon: 'fa-user-check',            bg: '#dbeafe', color: '#1d4ed8' },
  status:            { icon: 'fa-info-circle',           bg: '#dcfce7', color: '#15803d' },
  service_updated:   { icon: 'fa-hand-holding-medical', bg: '#ede9fe', color: '#6d28d9' },
  email:             { icon: 'fa-envelope-open-text',    bg: '#e0f2fe', color: '#0284c7' },
  cancelled_by_user: { icon: 'fa-triangle-exclamation', bg: '#fef9c3', color: '#b45309' },
  cancelled:         { icon: 'fa-times-circle',          bg: '#fee2e2', color: '#dc2626' },
  push:              { icon: 'fa-bullhorn',              bg: '#f3e8ff', color: '#7c3aed' },
  info:              { icon: 'fa-bell',                  bg: '#f0f9ff', color: '#0284c7' },
};

function timeSince(dateStr) {
  const d = new Date(dateStr.replace(' ', 'T'));
  const s = Math.floor((Date.now() - d) / 1000);
  if (s < 60)    return 'just now';
  if (s < 3600)  return Math.floor(s / 60) + 'm ago';
  if (s < 86400) return Math.floor(s / 3600) + 'h ago';
  return Math.floor(s / 86400) + 'd ago';
}

function getCsrf() {
  return document.querySelector('meta[name="csrf-token"]')?.content || '';
}

function syncNavBadges(unread, pending, isAdmin) {
  ['notifBadgeDesktop', 'notifBadgeMobile'].forEach(id => {
    const el = document.getElementById(id);
    if (!el) return;
    if (unread > 0) { el.textContent = unread > 99 ? '99+' : unread; el.style.display = ''; }
    else el.style.display = 'none';
  });
  if (isAdmin) {
    ['navNewBookingsBadge', 'adminQuickNewBookingsBadge', 'dropdownNewBookingsBadge'].forEach(id => {
      const el = document.getElementById(id);
      if (!el) return;
      if (pending > 0) { el.textContent = pending > 99 ? '99+' : pending; el.style.display = ''; }
      else el.style.display = 'none';
    });
  }
}

/* ─────────────────────────────────────────────────────────────
   NOTIFICATION PANEL SUB-COMPONENTS
───────────────────────────────────────────────────────────── */
function NotifItem({ n, isAdmin, appUrl, onMarkRead }) {
  const cfg = NOTIF_TYPES[n.type] || NOTIF_TYPES.info;
  const unread = n.is_read == 0;
  function handleClick() {
    if (unread) onMarkRead(n.id);
    if (n.booking_id) {
      window.location.href = isAdmin
        ? `${appUrl}/admin/manage_bookings.php?status=pending&search=${encodeURIComponent(n.booking_id)}`
        : `${appUrl}/user/my_bookings.php`;
    }
  }
  return (
    <div className={`cc-notif-item${unread ? ' cc-notif-unread' : ''}`} onClick={handleClick}>
      <div className="cc-notif-icon" style={{ background: cfg.bg, color: cfg.color }}>
        <i className={`fas ${cfg.icon}`} />
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div className="cc-notif-title">
          {n.title}
          {unread && <span className="cc-notif-new-badge">New</span>}
        </div>
        <div className="cc-notif-msg">{n.message}</div>
        <div className="cc-notif-time">
          <i className="fas fa-clock" style={{ marginRight: 4 }} />
          {timeSince(n.created_at)}
          {n.booking_id && ` · Booking #${n.booking_id}`}
        </div>
        {isAdmin && n.booking_id && (
          <div style={{ marginTop: 4 }}>
            <span className="cc-notif-action-badge">
              <i className="fas fa-user-plus" style={{ marginRight: 4 }} />Take Action
            </span>
          </div>
        )}
      </div>
    </div>
  );
}

function EmptyState() {
  return (
    <div className="cc-notif-empty">
      <div className="cc-notif-empty-icon"><i className="fas fa-bell-slash" /></div>
      <div className="cc-notif-empty-title">All caught up!</div>
      <div className="cc-notif-empty-sub">No notifications yet. You'll be alerted when something happens.</div>
    </div>
  );
}

function NotifSkeleton() {
  return (
    <div style={{ padding: '12px 16px' }}>
      {[1,2,3].map(i => (
        <div key={i} style={{ display:'flex', gap:12, marginBottom:16 }}>
          <div className="skeleton" style={{ width:38, height:38, borderRadius:11, flexShrink:0 }} />
          <div style={{ flex:1 }}>
            <div className="skeleton" style={{ height:13, borderRadius:6, marginBottom:6, width:'65%' }} />
            <div className="skeleton" style={{ height:11, borderRadius:6, marginBottom:4, width:'88%' }} />
            <div className="skeleton" style={{ height:10, borderRadius:6, width:'38%' }} />
          </div>
        </div>
      ))}
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   MAIN NOTIFICATION PANEL
───────────────────────────────────────────────────────────── */
function NotificationPanel({ apiUrl, appUrl, isLoggedIn, isAdmin, ctaUrl }) {
  const [open,         setOpen]    = useState(false);
  const [closing,      setClosing] = useState(false);
  const [notifications,setNotifs] = useState([]);
  const [unread,       setUnread]  = useState(0);
  const [pending,      setPending] = useState(0);
  const [loading,      setLoading] = useState(false);
  const lastSeenRef = useRef(parseInt(localStorage.getItem('admin_last_seen_pending_id') || '0', 10));

  /* chime */
  function playChime() {
    try {
      const AC = window.AudioContext || window.webkitAudioContext;
      if (!AC) return;
      const ctx = new AC();
      const now = ctx.currentTime;
      [[587.33, 0, 0.35, 0.15], [880, 0.14, 0.65, 0.2]].forEach(([freq, start, stop, vol]) => {
        const o = ctx.createOscillator(), g = ctx.createGain();
        o.type = 'sine';
        o.frequency.setValueAtTime(freq, now + start);
        g.gain.setValueAtTime(vol, now + start);
        g.gain.exponentialRampToValueAtTime(0.001, now + stop);
        o.connect(g); g.connect(ctx.destination);
        o.start(now + start); o.stop(now + stop);
      });
    } catch (_) {}
  }

  /* admin live alert card */
  function showBookingAlert(booking) {
    if (!booking?.id) return;
    const alertId = `cc-alert-${booking.id}`;
    if (document.getElementById(alertId)) return;
    playChime();
    let container = document.getElementById('adminLiveAlertContainer');
    if (!container) {
      container = document.createElement('div');
      container.id = 'adminLiveAlertContainer';
      container.style.cssText = 'position:fixed;bottom:24px;right:24px;z-index:10070;display:flex;flex-direction:column;gap:12px;max-width:420px;width:calc(100% - 32px);pointer-events:none;';
      document.body.appendChild(container);
    }
    const el = document.createElement('div');
    el.id = alertId;
    el.style.cssText = 'background:#fff;border:2px solid #fde047;border-left:5px solid #eab308;border-radius:16px;box-shadow:0 14px 35px -5px rgba(0,0,0,.2);pointer-events:auto;overflow:hidden;animation:toastIn 0.35s ease forwards;';
    el.innerHTML = `
      <div style="display:flex;align-items:flex-start;gap:12px;padding:14px 16px">
        <div style="width:44px;height:44px;border-radius:50%;background:#fef08a;color:#ca8a04;font-size:20px;display:flex;align-items:center;justify-content:center;flex-shrink:0"><i class="fas fa-bell"></i></div>
        <div style="flex:1;min-width:0">
          <div style="display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px">
            <span style="background:#dc2626;color:#fff;font-size:10px;font-weight:700;padding:2px 8px;border-radius:999px">⚡ NEW BOOKING</span>
            <button onclick="this.closest('[id]').remove()" style="background:none;border:none;cursor:pointer;font-size:13px;color:#94a3b8">✕</button>
          </div>
          <div style="font-weight:700;font-size:14px;color:#1e293b;margin-bottom:4px">Booking #${booking.booking_number || booking.id} — ${booking.patient_name || 'Patient'}</div>
          <div style="font-size:12px;color:#64748b;margin-bottom:10px">${booking.service_title || 'Healthcare Service'} · <strong style="color:#1e293b">₹${Number(booking.total_price || 0).toLocaleString('en-IN')}</strong></div>
          <div style="display:flex;gap:8px">
            <a href="${appUrl}/admin/manage_bookings.php?status=pending" style="background:#1a73e8;color:#fff;border-radius:20px;padding:5px 14px;font-size:12px;font-weight:700;text-decoration:none">Assign →</a>
            <button onclick="this.closest('[id]').remove()" style="background:#f1f5f9;border:none;border-radius:20px;padding:5px 12px;font-size:12px;cursor:pointer;color:#64748b">Dismiss</button>
          </div>
        </div>
      </div>`;
    container.prepend(el);
  }

  /* fetch count — used by polling */
  const fetchCount = useCallback(() => {
    if (!isLoggedIn) return;
    fetch(`${apiUrl}?action=count`)
      .then(r => r.json())
      .then(d => {
        if (!d.ok) return;
        setUnread(d.count || 0);
        setPending(d.pending_bookings || 0);
        syncNavBadges(d.count || 0, d.pending_bookings || 0, isAdmin);
        if (isAdmin && d.latest_pending) {
          const lId = parseInt(d.latest_pending.id, 10);
          if (lastSeenRef.current > 0 && lId > lastSeenRef.current) showBookingAlert(d.latest_pending);
          lastSeenRef.current = Math.max(lastSeenRef.current, lId);
          localStorage.setItem('admin_last_seen_pending_id', String(lastSeenRef.current));
        }
      }).catch(() => {});
  }, [isLoggedIn, isAdmin, apiUrl]);

  /* fetch full list — on panel open */
  const fetchNotifs = useCallback(() => {
    if (!isLoggedIn) return;
    setLoading(true);
    fetch(`${apiUrl}?action=fetch`)
      .then(r => r.json())
      .then(d => {
        if (!d.ok) return;
        setNotifs(d.notifications || []);
        setUnread(d.unread || 0);
        setPending(d.pending_bookings || 0);
        syncNavBadges(d.unread || 0, d.pending_bookings || 0, isAdmin);
        if (isAdmin && d.latest_pending) {
          const lId = parseInt(d.latest_pending.id, 10);
          lastSeenRef.current = Math.max(lastSeenRef.current, lId);
          localStorage.setItem('admin_last_seen_pending_id', String(lastSeenRef.current));
        }
      })
      .catch(() => {})
      .finally(() => setLoading(false));
  }, [isLoggedIn, isAdmin, apiUrl]);

  /* mark one read */
  const markOneRead = useCallback((id) => {
    const fd = new FormData();
    fd.append('id', id);
    fd.append('csrf_token', getCsrf());
    fetch(`${apiUrl}?action=mark_read`, { method: 'POST', body: fd }).then(() => {
      setNotifs(prev => prev.map(n => n.id == id ? { ...n, is_read: 1 } : n));
      setUnread(prev => { const next = Math.max(0, prev - 1); syncNavBadges(next, pending, isAdmin); return next; });
    }).catch(() => {});
  }, [apiUrl, pending, isAdmin]);

  /* mark all read */
  const markAllReadFn = useCallback(() => {
    const fd = new FormData();
    fd.append('id', 0);
    fd.append('csrf_token', getCsrf());
    fetch(`${apiUrl}?action=mark_read`, { method: 'POST', body: fd }).then(() => {
      setNotifs(prev => prev.map(n => ({ ...n, is_read: 1 })));
      setUnread(0);
      syncNavBadges(0, pending, isAdmin);
    }).catch(() => {});
  }, [apiUrl, pending, isAdmin]);

  /* open / close */
  const openPanel = useCallback(() => { setOpen(true); fetchNotifs(); }, [fetchNotifs]);
  const closePanel = useCallback(() => {
    setClosing(true);
    setTimeout(() => { setOpen(false); setClosing(false); }, 260);
  }, []);

  /* ── WIRE UP GLOBAL STUBS as soon as component renders ── */
  useEffect(() => {
    window.toggleNotifPanel   = () => { open ? closePanel() : openPanel(); };
    window.openNotifPanel     = openPanel;
    window.closeNotifPanel    = closePanel;
    window.markAllRead        = markAllReadFn;
    window.markRead           = markOneRead;
    window.fetchNotifCount    = fetchCount;
    window.fetchNotifications = fetchNotifs;

    // If bell was clicked before React mounted, open now
    if (window._notifPendingOpen && window._notifPendingOpen()) {
      window._notifClearPending();
      openPanel();
    }
  }); // no deps — re-run every render so closures stay fresh

  /* escape key */
  useEffect(() => {
    const handler = (e) => { if (e.key === 'Escape' && open) closePanel(); };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, [open, closePanel]);

  /* polling */
  useEffect(() => {
    if (!isLoggedIn) return;
    fetchCount();
    const t = setInterval(fetchCount, isAdmin ? 12000 : 30000);
    return () => clearInterval(t);
  }, [isLoggedIn, isAdmin, fetchCount]);

  const isVisible = open || closing;

  return (
    <>
      {/* Backdrop */}
      {isVisible && (
        <div
          onClick={closePanel}
          style={{
            position: 'fixed', inset: 0,
            background: 'rgba(15,23,42,0.5)',
            backdropFilter: 'blur(3px)',
            zIndex: 99998,
            opacity: closing ? 0 : 1,
            transition: 'opacity 0.26s ease',
          }}
        />
      )}

      {/* Drawer */}
      <div
        role="dialog"
        aria-label="Notifications"
        aria-modal="true"
        style={{
          position: 'fixed', top: 0,
          right: open && !closing ? 0 : '-420px',
          width: 390, maxWidth: '100vw', height: '100vh',
          background: '#fff',
          boxShadow: '-8px 0 40px rgba(0,0,0,0.16)',
          zIndex: 99999,
          display: 'flex', flexDirection: 'column',
          transition: 'right 0.3s cubic-bezier(0.16,1,0.3,1)',
        }}
      >
        {/* Header */}
        <div className="cc-notif-header">
          <div style={{ display:'flex', alignItems:'center', gap:10 }}>
            <div className="cc-notif-header-icon">
              <i className="fas fa-bell" />
              {unread > 0 && <span className="cc-notif-header-badge">{unread > 99 ? '99+' : unread}</span>}
            </div>
            <div>
              <div className="cc-notif-header-title">Notifications</div>
              <div className="cc-notif-header-sub">Real-time alerts &amp; visit updates</div>
            </div>
          </div>
          <div style={{ display:'flex', alignItems:'center', gap:6 }}>
            <button className="cc-notif-mark-btn" onClick={markAllReadFn}>
              <i className="fas fa-check-double" style={{ color:'#10b981', marginRight:4 }} />Mark Read
            </button>
            <button className="cc-notif-close-btn" onClick={closePanel}>
              <i className="fas fa-times" />
            </button>
          </div>
        </div>

        {/* List */}
        <div style={{ flex:1, overflowY:'auto', background:'#fff' }}>
          {loading
            ? <NotifSkeleton />
            : notifications.length === 0
              ? <EmptyState />
              : notifications.map(n => (
                  <NotifItem key={n.id} n={n} isAdmin={isAdmin} appUrl={appUrl} onMarkRead={markOneRead} />
                ))
          }
        </div>

        {/* Footer */}
        <div className="cc-notif-footer">
          <a href={ctaUrl} className="cc-notif-cta-btn" onClick={closePanel}>
            <i className={`fas ${isAdmin ? 'fa-clipboard-list' : 'fa-calendar-check'}`} style={{ marginRight:6 }} />
            {isAdmin ? 'Go to Manage Bookings' : 'Go to My Bookings'}
          </a>
        </div>
      </div>
    </>
  );
}

/* ─────────────────────────────────────────────────────────────
   STAT COUNTER
───────────────────────────────────────────────────────────── */
function useCountUp(target, duration, started) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    if (!started || typeof target !== 'number' || target === 0) return;
    let t0 = null;
    const tick = (ts) => {
      if (!t0) t0 = ts;
      const p = Math.min((ts - t0) / duration, 1);
      setCount(Math.floor((1 - Math.pow(1 - p, 3)) * target));
      if (p < 1) requestAnimationFrame(tick);
    };
    requestAnimationFrame(tick);
  }, [started, target, duration]);
  return count;
}

function StatTile({ icon, iconColor, gradientFrom, gradientTo, value, suffix, label, bgIcon, delay }) {
  const [visible, setVisible] = useState(false);
  const ref = useRef(null);

  useEffect(() => {
    const obs = new IntersectionObserver(
      ([e]) => { if (e.isIntersecting) { setVisible(true); obs.disconnect(); } },
      { threshold: 0.25 }
    );
    if (ref.current) obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);

  const isNum = typeof value === 'number';
  const displayed = useCountUp(isNum ? value : 0, 1600, visible && isNum);

  return (
    <div
      ref={ref}
      className="cc-stat-tile"
      style={{ animationDelay: `${delay || 0}ms`, '--grad-from': gradientFrom, '--grad-to': gradientTo }}
    >
      {bgIcon && (
        <div className="cc-stat-tile-bg-icon" style={{ color: iconColor }}>
          <i className={`fas ${bgIcon}`} />
        </div>
      )}
      <div className="cc-stat-tile-icon" style={{ color: iconColor }}>
        <i className={`fas ${icon}`} />
      </div>
      <div className="cc-stat-tile-value" style={{ color: iconColor }}>
        {isNum ? <>{displayed.toLocaleString('en-IN')}{suffix && <span className="cc-stat-tile-suffix">{suffix}</span>}</> : value}
      </div>
      <div className="cc-stat-tile-label">{label}</div>
    </div>
  );
}

function StatCounterGrid({ stats }) {
  return (
    <div className="cc-stat-grid">
      {stats.map((s, i) => <StatTile key={i} {...s} delay={i * 80} />)}
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   MOUNT — runs synchronously once Babel finishes compiling.
   DOM nodes exist because this <script> is at end of <body>.
───────────────────────────────────────────────────────────── */
(function mount() {
  // Notification Panel
  const notifRoot = document.getElementById('cc-notif-root');
  if (notifRoot && window.CC_NOTIF_CONFIG) {
    const cfg = window.CC_NOTIF_CONFIG;
    ReactDOM.createRoot(notifRoot).render(
      <NotificationPanel
        apiUrl={cfg.apiUrl}
        appUrl={cfg.appUrl}
        isLoggedIn={cfg.isLoggedIn}
        isAdmin={cfg.isAdmin}
        ctaUrl={cfg.ctaUrl}
      />
    );
  }

  // Stat Counter Grid
  const statRoot = document.getElementById('cc-stat-root');
  if (statRoot && window.CC_STAT_CONFIG) {
    ReactDOM.createRoot(statRoot).render(
      <StatCounterGrid stats={window.CC_STAT_CONFIG} />
    );
  }
})();
