<?php
require_once __DIR__ . '/../config.php';
checkerGuard();

$eventTitle   = $_SESSION['event_title'] ?? 'Event';
$checkerName  = $_SESSION['checker_name'] ?? '';
$eventId      = $_SESSION['checker_event'] ?? 0;

// Stats for this session
$db = db();
$totalGuests  = $db->prepare('SELECT COUNT(*) FROM guests WHERE event_id=?');
$totalGuests->execute([$eventId]);
$totalGuests = (int)$totalGuests->fetchColumn();

$totalChecked = $db->prepare('SELECT COUNT(*) FROM guests WHERE event_id=? AND checked_in=1');
$totalChecked->execute([$eventId]);
$totalChecked = (int)$totalChecked->fetchColumn();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Check-in — <?= htmlspecialchars($eventTitle) ?></title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" media="print" onload="this.media='all'" href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:wght@300;400;500&display=swap">
<link rel="stylesheet" href="<?= BASE_URL ?>/assets/css/main.css">
<script src="<?= BASE_URL ?>/assets/js/loader.js" defer></script>
<!-- QR Scanner library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5-qrcode/2.3.8/html5-qrcode.min.js"></script>
</head>
<body>

<div class="checker-wrap">

  <!-- Header -->
  <div style="text-align:center;margin-bottom:28px">
    <div class="label-ui" style="color:var(--gold);margin-bottom:4px">Check-in Station</div>
    <h2 style="font-family:var(--font-display);font-size:1.5rem"><?= htmlspecialchars($eventTitle) ?></h2>
    <div class="text-muted text-sm" style="margin-top:4px">
      Logged in as <strong style="color:var(--white)"><?= htmlspecialchars($checkerName) ?></strong>
      · <a href="<?= BASE_URL ?>/checker/logout.php" style="color:var(--danger);font-size:.8rem">Sign out</a>
    </div>
  </div>

  <!-- Stats bar -->
  <div style="display:flex;gap:12px;margin-bottom:24px">
    <div class="stat-card" style="flex:1;padding:14px 16px">
      <div class="stat-value" id="stat-checked" style="font-size:1.6rem"><?= $totalChecked ?></div>
      <div class="stat-label">Checked In</div>
    </div>
    <div class="stat-card" style="flex:1;padding:14px 16px">
      <div class="stat-value" style="font-size:1.6rem"><?= $totalGuests ?></div>
      <div class="stat-label">Total Guests</div>
    </div>
    <div class="stat-card" style="flex:1;padding:14px 16px">
      <div class="stat-value" id="stat-pct" style="font-size:1.6rem"><?= $totalGuests>0?round($totalChecked/$totalGuests*100):0 ?>%</div>
      <div class="stat-label">Attendance</div>
    </div>
  </div>

  <!-- Mode tabs -->
  <div style="display:flex;gap:0;margin-bottom:20px;border:1px solid var(--border);border-radius:var(--radius);overflow:hidden">
    <button id="tab-qr" onclick="switchMode('qr')"
            style="flex:1;padding:11px;background:var(--gold);color:var(--obsidian);
                   font-family:var(--font-ui);font-size:.75rem;font-weight:700;
                   letter-spacing:.08em;text-transform:uppercase;border:none;cursor:pointer">
      📷 Scan QR
    </button>
    <button id="tab-manual" onclick="switchMode('manual')"
            style="flex:1;padding:11px;background:transparent;color:var(--muted);
                   font-family:var(--font-ui);font-size:.75rem;font-weight:700;
                   letter-spacing:.08em;text-transform:uppercase;border:none;cursor:pointer">
      🔍 Search Guest
    </button>
    <button id="tab-walkin" onclick="switchMode('walkin')"
            style="flex:1;padding:11px;background:transparent;color:var(--muted);
                   font-family:var(--font-ui);font-size:.75rem;font-weight:700;
                   letter-spacing:.08em;text-transform:uppercase;border:none;cursor:pointer">
      ➕ Walk-in
    </button>
  </div>

  <!-- Offline sync indicator -->
  <div id="sync-pill" class="sync-pill">
    <span id="sync-text">0 waiting to sync</span>
  </div>

  <!-- Result display -->
  <div id="result-area"></div>

  <!-- QR Scanner panel -->
  <div id="panel-qr">
    <div class="scanner-box">
      <div id="qr-reader" style="width:100%;height:100%"></div>
      <div class="scan-line" id="scanLine"></div>
      <button type="button" id="torch-btn" class="torch-btn" onclick="toggleTorch()" aria-label="Flashlight">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="20" height="20"><path d="M9 2h6l-1 7 3 2-6 11-1-9-3-2z"/></svg>
      </button>
    </div>
    <p class="text-muted text-sm" style="text-align:center">Point camera at guest's QR code on their invite</p>
  </div>

  <!-- Manual search panel -->
  <div id="panel-manual" style="display:none">
    <div class="search-bar">
      <input class="form-control" type="text" id="searchInput"
             placeholder="Name, email, or phone…"
             oninput="debounceSearch(this.value)">
      <button class="btn btn-gold" onclick="doSearch()">Search</button>
    </div>
    <div id="search-results"></div>
  </div>

  <!-- Walk-in panel -->
  <div id="panel-walkin" style="display:none">
    <div class="card">
      <div class="label-ui mb-2">Register a walk-in guest</div>
      <div class="form-group">
        <label class="form-label">Full Name *</label>
        <input class="form-control" type="text" id="walkinName" placeholder="Guest name">
      </div>
      <div class="form-group">
        <label class="form-label">Category</label>
        <input class="form-control" type="text" id="walkinCat" placeholder="VIP, Regular… (optional)">
      </div>
      <button class="btn btn-gold w-100" onclick="checkinWalkin()">Add &amp; Check In</button>
    </div>
  </div>

</div>

<script>
const BASE_URL   = '<?= BASE_URL ?>';
const CHECKER_ID = <?= (int)$_SESSION['checker_id'] ?>;
const EVENT_ID   = <?= (int)$eventId ?>;
const CSRF_TOKEN = '<?= htmlspecialchars(csrfToken()) ?>';
let qrScanner    = null;
let searchTimer  = null;
let scanning     = true;
let torchOn      = false;

// ── Audio + haptic feedback ────────────────────────────────
let audioCtx = null;
function tone(freq, ms, type) {
  try {
    audioCtx = audioCtx || new (window.AudioContext || window.webkitAudioContext)();
    const o = audioCtx.createOscillator(), g = audioCtx.createGain();
    o.type = type || 'sine'; o.frequency.value = freq;
    o.connect(g); g.connect(audioCtx.destination);
    g.gain.setValueAtTime(0.15, audioCtx.currentTime);
    o.start();
    g.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + ms/1000);
    o.stop(audioCtx.currentTime + ms/1000);
  } catch (e) {}
}
function feedback(kind) {
  if (kind === 'ok')      { tone(880, 120); navigator.vibrate && navigator.vibrate(60); }
  else if (kind === 'warn'){ tone(520, 90); setTimeout(()=>tone(520,90),130); navigator.vibrate && navigator.vibrate([40,50,40]); }
  else                    { tone(220, 220, 'square'); navigator.vibrate && navigator.vibrate([80,60,80]); }
}

// ── Offline check-in queue ─────────────────────────────────
const QKEY = 'rsvp_checkin_queue_' + EVENT_ID;
function queueGet()  { try { return JSON.parse(localStorage.getItem(QKEY) || '[]'); } catch(e){ return []; } }
function queueSet(q) { localStorage.setItem(QKEY, JSON.stringify(q)); renderSync(); }
function queueAdd(p) { const q = queueGet(); q.push({ payload: p, ts: Date.now() }); queueSet(q); }
function renderSync() {
  const q = queueGet(), pill = document.getElementById('sync-pill'), txt = document.getElementById('sync-text');
  if (!q.length) { pill.classList.remove('show'); return; }
  pill.classList.add('show'); pill.classList.remove('synced');
  txt.textContent = q.length + ' waiting to sync';
}
function flushQueue() {
  const q = queueGet();
  if (!q.length || !navigator.onLine) return;
  const item = q[0];
  fetch(BASE_URL + '/api/checkin.php', {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(item.payload)
  }).then(r => r.json()).then(() => {
    const q2 = queueGet(); q2.shift(); queueSet(q2);
    if (q2.length) flushQueue();
    else { const pill = document.getElementById('sync-pill');
           pill.classList.add('synced'); document.getElementById('sync-text').textContent = 'All synced ✓';
           setTimeout(renderSync, 2500); }
    updateStats();
  }).catch(() => {}); // stay queued; retry later
}
window.addEventListener('online', flushQueue);
setInterval(flushQueue, 8000);

// ── Unified check-in submit (with offline fallback) ────────
function submitCheckin(payload, onResult) {
  fetch(BASE_URL + '/api/checkin.php', {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
  })
  .then(r => r.json())
  .then(data => onResult(data))
  .catch(() => {
    // Network failure — never lose the scan. Queue and accept optimistically.
    if (payload.action !== 'undo') queueAdd(payload);
    onResult({ success: true, offline: true, method: payload.method || 'qr',
               guest: { name: payload._name || 'Guest', category: payload._cat || '' } });
  });
}

// ── Mode switching ─────────────────────────────────────────
function switchMode(mode) {
  document.getElementById('panel-qr').style.display     = mode==='qr'     ? '' : 'none';
  document.getElementById('panel-manual').style.display = mode==='manual' ? '' : 'none';
  document.getElementById('panel-walkin').style.display = mode==='walkin' ? '' : 'none';

  const tabs = { qr: 'tab-qr', manual: 'tab-manual', walkin: 'tab-walkin' };
  for (const [m, id] of Object.entries(tabs)) {
    const el = document.getElementById(id);
    el.style.background = (m === mode) ? 'var(--gold)' : 'transparent';
    el.style.color      = (m === mode) ? 'var(--obsidian)' : 'var(--muted)';
  }

  if (mode === 'qr') {
    startScanner();
  } else {
    stopScanner();
    if (mode === 'manual') document.getElementById('searchInput').focus();
    else document.getElementById('walkinName').focus();
  }
}

// ── Walk-in check-in ───────────────────────────────────────
function checkinWalkin() {
  const name = document.getElementById('walkinName').value.trim();
  const cat  = document.getElementById('walkinCat').value.trim();
  if (!name) { showResult('error', 'Name required', 'Enter the guest\'s name.', null); return; }
  submitCheckin(
    { action: 'walkin', name, category: cat, method: 'manual',
      checker_id: CHECKER_ID, event_id: EVENT_ID, csrf_token: CSRF_TOKEN, _name: name, _cat: cat },
    data => {
      if (data.success) {
        document.getElementById('walkinName').value = '';
        document.getElementById('walkinCat').value  = '';
        showResult('success', 'Walk-in checked in', name + (cat ? ' · ' + cat : ''), null);
        updateStats();
      } else {
        showResult('error', 'Failed', data.message || 'Could not add walk-in.', null);
      }
    }
  );
}

// ── Torch / flashlight (where supported) ───────────────────
function toggleTorch() {
  try {
    const track = qrScanner && qrScanner.getRunningTrackCameraCapabilities
      ? null : null;
    const stream = document.querySelector('#qr-reader video')?.srcObject;
    const t = stream && stream.getVideoTracks ? stream.getVideoTracks()[0] : null;
    if (!t) return;
    torchOn = !torchOn;
    t.applyConstraints({ advanced: [{ torch: torchOn }] });
    document.getElementById('torch-btn').classList.toggle('on', torchOn);
  } catch (e) {}
}
function detectTorch() {
  setTimeout(() => {
    try {
      const stream = document.querySelector('#qr-reader video')?.srcObject;
      const t = stream && stream.getVideoTracks ? stream.getVideoTracks()[0] : null;
      const caps = t && t.getCapabilities ? t.getCapabilities() : {};
      if (caps && 'torch' in caps) document.getElementById('torch-btn').classList.add('available');
    } catch (e) {}
  }, 1200);
}

// ── QR Scanner ─────────────────────────────────────────────
function startScanner() {
  scanning = true;
  if (qrScanner) { qrScanner.resume(); return; }
  qrScanner = new Html5Qrcode('qr-reader');
  qrScanner.start(
    { facingMode: 'environment' },
    { fps: 10, qrbox: { width: 220, height: 220 } },
    onQRScan,
    () => {}
  ).then(() => detectTorch())
   .catch(err => {
    showResult('error', '⚠ Camera unavailable', err.toString(), null);
  });
}

function stopScanner() {
  scanning = false;
  if (qrScanner && qrScanner.isScanning) {
    qrScanner.pause(true);
  }
}

function onQRScan(decodedText) {
  if (!scanning) return;
  scanning = false; // prevent double-fire
  stopScanner();

  // Extract token from URL if full URL was encoded
  let token = decodedText;
  try {
    const url = new URL(decodedText);
    token = url.searchParams.get('token') || decodedText;
  } catch(e) {}

  checkinByToken(token);
}

// ── Check-in by token (QR) ─────────────────────────────────
function checkinByToken(token) {
  submitCheckin(
    { token, method: 'qr', checker_id: CHECKER_ID, event_id: EVENT_ID, csrf_token: CSRF_TOKEN },
    data => renderResult(data, true)
  );
}

// ── Check-in by guest ID (manual) ─────────────────────────
function checkinManual(guestId, name) {
  submitCheckin(
    { guest_id: guestId, method: 'manual', checker_id: CHECKER_ID, event_id: EVENT_ID, csrf_token: CSRF_TOKEN, _name: name || 'Guest' },
    data => renderResult(data, false)
  );
}

// ── Undo check-in ──────────────────────────────────────────
function undoCheckin(guestId) {
  const run = () => {
    submitCheckin(
      { guest_id: guestId, action: 'undo', checker_id: CHECKER_ID, event_id: EVENT_ID, csrf_token: CSRF_TOKEN },
      () => { feedback('warn'); showResult('warning', 'Check-in reversed', 'Guest has been unchecked.', null); updateStats(); }
    );
  };
  (window.uiConfirm
    ? uiConfirm({ title: 'Undo this check-in?', message: 'The guest will be marked as not arrived.', confirmText: 'Undo', danger: true })
    : Promise.resolve(confirm('Undo this check-in?'))
  ).then(ok => { if (ok) run(); });
}

// ── Render result ──────────────────────────────────────────
function fmtTime(s) {
  if (!s) return '';
  const d = new Date(String(s).replace(' ', 'T'));
  return isNaN(d) ? String(s) : d.toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'});
}

// Re-arm the QR scanner after a short cooldown WITHOUT clearing the result card,
// so the last outcome stays visible (and Undo stays reachable) until the next scan.
function rearm(resumeScan) {
  setTimeout(() => { scanning = true; if (resumeScan && qrMode()) startScanner(); }, 1500);
}
function qrMode() { return document.getElementById('panel-qr').style.display !== 'none'; }

function renderResult(data, resumeScan) {
  const area = document.getElementById('result-area');
  if (data.success) {
    feedback('ok');
    const now = new Date().toLocaleTimeString([], {hour:'2-digit',minute:'2-digit'});
    const offlineNote = data.offline
      ? `<div class="badge badge-gold" style="margin-top:8px">Saved offline — will sync</div>` : '';
    area.innerHTML = `
      <div class="result-card success">
        <div style="display:flex;justify-content:space-between;align-items:flex-start">
          <div>
            <div style="color:var(--success);font-family:var(--font-ui);font-size:.68rem;
                        font-weight:700;letter-spacing:.1em;text-transform:uppercase;margin-bottom:6px">
              ✓ Checked In · ${now}
            </div>
            <div style="font-family:var(--font-display);font-size:1.6rem">${escHtml(data.guest.name)}</div>
            <div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:7px">
              ${data.guest.category    ? `<span class="badge badge-gold">${escHtml(data.guest.category)}</span>` : ''}
              ${data.guest.table_number? `<span class="badge badge-muted">Table ${escHtml(data.guest.table_number)}</span>` : ''}
              ${data.guest.seat_number ? `<span class="badge badge-muted">Seat ${escHtml(data.guest.seat_number)}</span>`  : ''}
            </div>
            ${data.guest.email ? `<div class="text-muted text-sm" style="margin-top:6px">${escHtml(data.guest.email)}</div>` : ''}
            ${offlineNote}
            <div style="margin-top:8px;font-family:var(--font-ui);font-size:.65rem;color:var(--muted);letter-spacing:.06em">
              BY ${escHtml('<?= addslashes(htmlspecialchars($_SESSION['checker_name'] ?? '')) ?>')} · ${(data.method||'').toUpperCase()}
            </div>
          </div>
          <div style="font-size:2.5rem">✅</div>
        </div>
        ${data.guest.id ? `<button class="btn btn-danger" onclick="undoCheckin(${data.guest.id})">Undo</button>` : ''}
      </div>`;
    updateStats();
  } else if (data.blocked) {
    feedback('warn');
    area.innerHTML = `
      <div class="result-card warning">
        <div style="color:var(--gold);font-family:var(--font-ui);font-size:.68rem;
                    font-weight:700;letter-spacing:.1em;text-transform:uppercase;margin-bottom:6px">
          ⏱ Check-in Closed
        </div>
        <div class="text-muted">${escHtml(data.message || 'Check-in is not open right now.')}</div>
      </div>`;
  } else if (data.already_checked) {
    feedback('warn');
    area.innerHTML = `
      <div class="result-card warning">
        <div style="color:var(--gold);font-family:var(--font-ui);font-size:.68rem;
                    font-weight:700;letter-spacing:.1em;text-transform:uppercase;margin-bottom:6px">
          ⚠ Already Checked In
        </div>
        <div style="font-family:var(--font-display);font-size:1.5rem">${escHtml(data.guest.name)}</div>
        <div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:7px">
          ${data.guest.category     ? `<span class="badge badge-gold">${escHtml(data.guest.category)}</span>` : ''}
          ${data.guest.table_number ? `<span class="badge badge-muted">Table ${escHtml(data.guest.table_number)}</span>` : ''}
        </div>
        <div class="text-muted text-sm" style="margin-top:8px">
          Checked in at ${escHtml(fmtTime(data.guest.check_in_time))}
          ${data.guest.checked_by_name ? ` · by <strong style="color:var(--white)">${escHtml(data.guest.checked_by_name)}</strong>` : ''}
          via ${(data.guest.check_in_method||'').toUpperCase()}
        </div>
        <button class="btn btn-danger" onclick="undoCheckin(${data.guest.id})">Undo Check-in</button>
      </div>`;
  } else {
    feedback('err');
    area.innerHTML = `
      <div class="result-card danger">
        <div style="color:var(--danger);font-family:var(--font-ui);font-size:.68rem;
                    font-weight:700;letter-spacing:.1em;text-transform:uppercase;margin-bottom:6px">
          ✕ Not Found
        </div>
        <div class="text-muted">${escHtml(data.message || 'Guest not found for this event.')}</div>
      </div>`;
  }
  rearm(resumeScan);
}

function showResult(type, title, msg, guestId) {
  const area = document.getElementById('result-area');
  if (type === 'success') feedback('ok'); else if (type === 'error') feedback('err');
  const colorMap = { success:'var(--success)', error:'var(--danger)', warning:'var(--gold)' };
  area.innerHTML = `
    <div class="result-card ${type}">
      <div style="color:${colorMap[type]||'var(--muted)'};font-family:var(--font-ui);font-size:.68rem;
                  font-weight:700;letter-spacing:.1em;text-transform:uppercase;margin-bottom:6px">
        ${escHtml(title)}
      </div>
      <div class="text-muted">${escHtml(msg)}</div>
    </div>`;
  rearm(qrMode());
}

// ── Manual search ──────────────────────────────────────────
function debounceSearch(q) {
  clearTimeout(searchTimer);
  if (!q.trim()) { document.getElementById('search-results').innerHTML=''; return; }
  searchTimer = setTimeout(() => doSearch(), 350);
}

function doSearch() {
  const q = document.getElementById('searchInput').value.trim();
  if (!q) return;
  fetch(`${BASE_URL}/api/search_guest.php?q=${encodeURIComponent(q)}&event_id=${EVENT_ID}`)
    .then(r => r.json())
    .then(data => renderSearchResults(data));
}

function renderSearchResults(guests) {
  const el = document.getElementById('search-results');
  if (!guests.length) {
    el.innerHTML = '<div class="text-muted text-sm" style="padding:12px 0">No guests found.</div>';
    return;
  }
  el.innerHTML = guests.map(g => `
    <div class="result-card" style="margin-bottom:10px;padding:16px 18px">
      <div style="display:flex;justify-content:space-between;align-items:center">
        <div>
          <div style="font-family:var(--font-display);font-size:1.15rem">${escHtml(g.name)}</div>
          <div style="display:flex;gap:6px;margin-top:5px;flex-wrap:wrap">
            ${g.category ? `<span class="badge badge-gold">${escHtml(g.category)}</span>` : ''}
            ${g.table_number ? `<span class="badge badge-muted">Table ${escHtml(g.table_number)}</span>` : ''}
            ${g.checked_in=='1' ? '<span class="badge badge-success">✓ Already In</span>' : ''}
          </div>
          ${g.email ? `<div class="text-muted text-sm" style="margin-top:4px">${escHtml(g.email)}</div>` : ''}
        </div>
        <button class="btn ${g.checked_in=='1'?'btn-danger':'btn-gold'} btn-sm"
                onclick="${g.checked_in=='1' ? `undoCheckin(${g.id})` : `checkinManual(${g.id}, ${JSON.stringify(String(g.name)).replace(/"/g,'&quot;')})`}">
          ${g.checked_in=='1' ? 'Undo' : 'Check In'}
        </button>
      </div>
    </div>`).join('');
}

// ── Stats refresh ──────────────────────────────────────────
function updateStats() {
  fetch(`${BASE_URL}/api/stats.php?event_id=${EVENT_ID}`)
    .then(r => r.json())
    .then(d => {
      document.getElementById('stat-checked').textContent = d.checked;
      document.getElementById('stat-pct').textContent     = d.pct + '%';
    });
}

function escHtml(str) {
  return String(str||'').replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
}

// Start scanner on load
startScanner();
setInterval(updateStats, 30000);
renderSync();       // restore any offline queue from a previous session
flushQueue();       // try to sync immediately
</script>
</body>
</html>
