<script>
  import { onMount, onDestroy } from 'svelte'
  import { liveQuery } from 'dexie'
  import { db } from '../db.js'
  import { api } from '../api.js'

  let { session, onLogout } = $props()

  let search = $state('')
  let error = $state('')
  let scannerMsg = $state('')
  let qrSupported = $state(false)
  let scanning = $state(false)
  let videoRef = $state(null)
  let stream = $state(null)
  let detector = $state(null)
  let scanInterval = $state(null)

  const attendees = liveQuery(() =>
    db.attendees.filter(a => !a.deleted_at).toArray()
  )

  const recentCheckIns = liveQuery(() =>
    db.attendees
      .filter(a => a.checked_in && !a.deleted_at)
      .toArray()
      .then(arr => arr
        .filter(a => a.checked_in_at)
        .sort((a, b) => b.checked_in_at.localeCompare(a.checked_in_at))
        .slice(0, 10)
      )
  )

  const filtered = $derived.by(() => {
    const s = search.trim().toLowerCase()
    if (!s || s.length < 2) return []
    return ($attendees ?? [])
      .filter(a => a.name.toLowerCase().includes(s) || a.ticket_id?.toLowerCase().includes(s) || a.email?.toLowerCase().includes(s))
      .sort((a, b) => a.name.localeCompare(b.name))
      .slice(0, 8)
  })

  const selected = $derived.by(() => {
    if (filtered.length === 1) return filtered[0]
    const s = search.trim().toLowerCase()
    return filtered.find(a => a.ticket_id?.toLowerCase() === s) ?? null
  })

  onMount(() => {
    qrSupported = 'BarcodeDetector' in window
  })

  onDestroy(() => {
    stopScanner()
  })

  async function toggleScanner() {
    if (scanning) {
      stopScanner()
    } else {
      await startScanner()
    }
  }

  async function startScanner() {
    scannerMsg = ''
    try {
      stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } })
      if (videoRef) videoRef.srcObject = stream
      detector = new BarcodeDetector({ formats: ['qr_code'] })
      scanning = true
      scanInterval = setInterval(doScan, 150)
    } catch (err) {
      scannerMsg = 'Camera access denied or unavailable.'
    }
  }

  function stopScanner() {
    clearInterval(scanInterval)
    scanInterval = null
    stream?.getTracks().forEach(t => t.stop())
    stream = null
    scanning = false
    if (videoRef) videoRef.srcObject = null
  }

  async function doScan() {
    if (!detector || !videoRef || videoRef.readyState < 2) return
    try {
      const codes = await detector.detect(videoRef)
      if (codes.length > 0) {
        const val = codes[0].rawValue
        search = val
        stopScanner()
      }
    } catch {}
  }

  async function checkIn(attendee, count = 1) {
    error = ''
    try {
      const result = await api.attendees.checkIn(attendee.id, { count })
      if (result.attendee) {
        await db.attendees.put(result.attendee)
      }
    } catch (err) {
      error = err.message
    }
  }

  async function checkInWithVolunteer(attendee) {
    error = ''
    try {
      const result = await api.attendees.checkIn(attendee.id, { count: 1, also_volunteer: true })
      if (result.attendee) await db.attendees.put(result.attendee)
      if (result.volunteer) await db.volunteers.put(result.volunteer)
    } catch (err) {
      error = err.message
    }
  }

  function remaining(a) {
    return (a.party_size ?? 1) - (a.checked_in_count ?? 0)
  }

  function progressLabel(a) {
    const ps = a.party_size ?? 1
    const ci = a.checked_in_count ?? 0
    if (ps <= 1) return null
    return `${ci}/${ps} checked in`
  }

  function fmt(ts) {
    if (!ts) return ''
    return new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
  }
</script>

<div class="gate">
  <div class="gate-header">
    <div class="gate-brand">Turn<span>pike</span> &nbsp;<span class="gate-role">Gate Check-in</span></div>
    <button class="gate-logout" onclick={onLogout}>Sign out</button>
  </div>

  <div class="gate-body">
    <!-- Search + QR -->
    <div class="gate-search-row">
      <input
        class="gate-search"
        placeholder="Search name, ticket ID, or scan QR…"
        bind:value={search}
      />
      {#if qrSupported}
        <button class="gbtn {scanning ? 'gbtn-danger' : 'gbtn-ghost'}" onclick={toggleScanner}>
          {scanning ? '■ Stop' : '⊡ Scan QR'}
        </button>
      {/if}
    </div>

    {#if scanning}
      <div class="gate-scanner">
        <video bind:this={videoRef} autoplay playsinline muted class="gate-video"></video>
        <div class="gate-scanner-hint">Point camera at QR code on ticket</div>
      </div>
    {/if}

    {#if scannerMsg}
      <div class="gate-msg gate-msg-warn">{scannerMsg}</div>
    {/if}

    {#if error}
      <div class="gate-msg gate-msg-error">{error}</div>
    {/if}

    <!-- Matched attendee card -->
    {#if selected}
      {@const rem = remaining(selected)}
      {@const prog = progressLabel(selected)}
      <div class="gate-match">
        <div class="gate-match-name">{selected.name}</div>
        {#if selected.ticket_type}
          <div class="gate-match-sub">{selected.ticket_type}</div>
        {/if}
        {#if selected.ticket_id}
          <div class="gate-match-sub text-muted">#{selected.ticket_id}</div>
        {/if}
        {#if prog}
          <div class="gate-party">
            <span class="gate-party-label">{prog}</span>
          </div>
        {/if}

        <div class="gate-match-actions">
          {#if rem > 0}
            <button class="gbtn gbtn-success" onclick={() => checkIn(selected, 1)}>
              ✓ Check in 1
            </button>
            {#if rem > 1}
              <button class="gbtn gbtn-ghost" onclick={() => checkIn(selected, rem)}>
                Check in all {rem}
              </button>
            {/if}
          {:else}
            <span class="gate-done">All checked in</span>
          {/if}

          {#if selected.volunteer_token && !selected.checked_in}
            <button class="gbtn gbtn-ghost" onclick={() => checkInWithVolunteer(selected)}>
              + Volunteer
            </button>
          {/if}
        </div>
      </div>
    {:else if search.trim().length >= 2 && filtered.length > 1}
      <!-- Multiple results list -->
      <div class="gate-results">
        {#each filtered as a}
          <button class="gate-result-row" onclick={() => search = a.ticket_id || a.name}>
            <span>
              <strong>{a.name}</strong>
              {#if a.ticket_type} · {a.ticket_type}{/if}
            </span>
            <span class="badge {a.checked_in ? 'badge-checked' : 'badge-unchecked'}">
              {a.checked_in ? 'In' : 'Pending'}
            </span>
          </button>
        {/each}
      </div>
    {:else if search.trim().length >= 2 && filtered.length === 0}
      <div class="gate-msg gate-msg-warn">No matching attendees found.</div>
    {/if}

    <!-- Recent check-ins -->
    <div class="gate-recent">
      <div class="gate-recent-title">Recent Check-ins</div>
      {#if ($recentCheckIns ?? []).length === 0}
        <div class="gate-recent-empty">No check-ins yet today.</div>
      {:else}
        {#each $recentCheckIns ?? [] as a}
          <div class="gate-recent-row">
            <span>{a.name}</span>
            <span class="text-muted">{fmt(a.checked_in_at)}</span>
          </div>
        {/each}
      {/if}
    </div>
  </div>
</div>

<style>
  .gate {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--c-bg);
    color: var(--c-text);
    font-family: var(--font);
  }
  .gate-header {
    background: var(--c-surface);
    border-bottom: 1px solid var(--c-border);
    padding: 0.85rem 1.5rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
  .gate-brand {
    font-size: 1.1rem;
    font-weight: 700;
    letter-spacing: -0.02em;
  }
  .gate-brand span:first-of-type { color: var(--c-accent); }
  .gate-role {
    font-size: 0.8rem;
    font-weight: 400;
    color: var(--c-muted);
    letter-spacing: 0;
  }
  .gate-logout {
    background: none;
    border: none;
    color: var(--c-muted);
    cursor: pointer;
    font-size: 0.8rem;
    font-family: var(--font);
    padding: 0.3rem 0.6rem;
    border-radius: 4px;
  }
  .gate-logout:hover { color: var(--c-text); background: rgba(255,255,255,0.05); }

  .gate-body {
    max-width: 680px;
    margin: 0 auto;
    padding: 1.5rem 1rem;
    width: 100%;
  }

  .gate-search-row {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 1rem;
  }
  .gate-search {
    flex: 1;
    font-size: 1.1rem;
    padding: 0.7rem 1rem;
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: 8px;
    color: var(--c-text);
    font-family: var(--font);
  }
  .gate-search:focus { outline: none; border-color: var(--c-accent); }

  .gate-scanner {
    margin-bottom: 1rem;
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid var(--c-border);
    position: relative;
  }
  .gate-video {
    width: 100%;
    display: block;
    max-height: 280px;
    object-fit: cover;
    background: #000;
  }
  .gate-scanner-hint {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(0,0,0,0.6);
    color: #fff;
    text-align: center;
    padding: 0.4rem;
    font-size: 0.78rem;
  }

  .gate-msg {
    padding: 0.7rem 1rem;
    border-radius: 6px;
    font-size: 0.875rem;
    margin-bottom: 1rem;
  }
  .gate-msg-error { background: rgba(239,68,68,0.12); border: 1px solid rgba(239,68,68,0.3); color: #fca5a5; }
  .gate-msg-warn  { background: rgba(245,158,11,0.1); border: 1px solid rgba(245,158,11,0.3); color: var(--c-warn); }

  .gate-match {
    background: var(--c-surface);
    border: 1px solid var(--c-accent);
    border-radius: 10px;
    padding: 1.25rem;
    margin-bottom: 1rem;
  }
  .gate-match-name { font-size: 1.4rem; font-weight: 700; margin-bottom: 0.2rem; }
  .gate-match-sub { color: var(--c-muted); font-size: 0.875rem; }
  .gate-party {
    margin: 0.5rem 0;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
  }
  .gate-party-label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--c-warn);
    background: rgba(245,158,11,0.15);
    padding: 0.2rem 0.6rem;
    border-radius: 99px;
  }
  .gate-match-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 1rem;
  }
  .gate-done {
    color: var(--c-success);
    font-size: 0.875rem;
    font-weight: 600;
    display: flex;
    align-items: center;
  }

  .gate-results {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: 8px;
    overflow: hidden;
    margin-bottom: 1rem;
  }
  .gate-result-row {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem 1rem;
    background: none;
    border: none;
    border-bottom: 1px solid var(--c-border);
    color: var(--c-text);
    font-family: var(--font);
    font-size: 0.875rem;
    cursor: pointer;
    text-align: left;
  }
  .gate-result-row:last-child { border-bottom: none; }
  .gate-result-row:hover { background: rgba(255,255,255,0.04); }

  .gate-recent { margin-top: 2rem; }
  .gate-recent-title {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--c-muted);
    margin-bottom: 0.5rem;
  }
  .gate-recent-empty { color: var(--c-muted); font-size: 0.875rem; }
  .gate-recent-row {
    display: flex;
    justify-content: space-between;
    padding: 0.4rem 0;
    font-size: 0.875rem;
    border-bottom: 1px solid var(--c-border);
  }
  .gate-recent-row:last-child { border-bottom: none; }

  .gbtn {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.5rem 1rem; border-radius: 6px;
    border: 1px solid transparent;
    font-size: 0.875rem; font-weight: 500; cursor: pointer;
    font-family: var(--font); white-space: nowrap;
    transition: background 150ms, border-color 150ms;
  }
  .gbtn:disabled { opacity: 0.5; cursor: not-allowed; }
  .gbtn-success { background: var(--c-success); color: #000; font-weight: 600; }
  .gbtn-success:hover:not(:disabled) { filter: brightness(1.1); }
  .gbtn-danger { background: var(--c-danger); color: #fff; }
  .gbtn-danger:hover:not(:disabled) { filter: brightness(1.1); }
  .gbtn-ghost { background: transparent; color: var(--c-muted); border-color: var(--c-border); }
  .gbtn-ghost:hover:not(:disabled) { color: var(--c-text); border-color: var(--c-text); }

  @media (max-width: 480px) {
    .gate-match-name { font-size: 1.2rem; }
    .gate-search { font-size: 1rem; }
  }
</style>
