'use client';

import { useState, useEffect, useRef, useCallback } from 'react';
import { useRouter } from 'next/navigation';
import { useLanguage } from '@/context/LanguageContext';
import { useAuth } from '@/context/AuthContext';
import { ticketsApi, eventsApi, Event, TicketValidationResult, LiveSearchResult } from '@/lib/api';
import {
  QrCodeIcon,
  CheckCircleIcon,
  XCircleIcon,
  XMarkIcon,
  MagnifyingGlassIcon,
  ArrowPathIcon,
  ClockIcon,
  UserIcon,
  ArrowLeftIcon,
  VideoCameraIcon,
} from '@heroicons/react/24/outline';
import toast from 'react-hot-toast';
import { parseDate, formatCurrency, EVENT_TIMEZONE } from '@/lib/utils';
import clsx from 'clsx';

// ─── Types ───────────────────────────────────────────────────
type ActiveTab = 'scan' | 'search' | 'recent';
type ScanState = 'idle' | 'scanning' | 'valid' | 'invalid';
type InvalidReason = 'already_checked_in' | 'cancelled' | 'not_found' | 'pending' | 'wrong_event' | 'unknown';

interface ScanResultData {
  state: ScanState;
  validation?: TicketValidationResult;
  invalidReason?: InvalidReason;
  error?: string;
}

interface RecentCheckin {
  name: string;
  time: string;
  ticketId: string;
}

// ─── Haptic + Sound Feedback ─────────────────────────────────
function playSuccessSound() {
  try {
    const ctx = new AudioContext();
    const osc = ctx.createOscillator();
    const gain = ctx.createGain();
    osc.connect(gain);
    gain.connect(ctx.destination);
    osc.frequency.value = 880;
    osc.type = 'sine';
    gain.gain.value = 0.3;
    osc.start();
    gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.15);
    osc.stop(ctx.currentTime + 0.15);
  } catch {}
}

function playErrorSound() {
  try {
    const ctx = new AudioContext();
    const osc = ctx.createOscillator();
    const gain = ctx.createGain();
    osc.connect(gain);
    gain.connect(ctx.destination);
    osc.frequency.value = 300;
    osc.type = 'square';
    gain.gain.value = 0.2;
    osc.start();
    gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.3);
    osc.stop(ctx.currentTime + 0.3);
  } catch {}
}

function vibrate(pattern: number | number[]) {
  try {
    if (navigator.vibrate) navigator.vibrate(pattern);
  } catch {}
}

// ─── Stop all tracks on a media stream ───────────────────────
function stopAllTracks() {
  try {
    // Find all video elements and stop their streams
    document.querySelectorAll('video').forEach((video) => {
      const stream = video.srcObject as MediaStream | null;
      if (stream) {
        stream.getTracks().forEach((track) => track.stop());
        video.srcObject = null;
      }
    });
  } catch {}
}

// ─── QR Scanner Component ────────────────────────────────────
// This component fully mounts/unmounts — use a key prop externally
// to force a fresh instance when the scan tab becomes active.
function QRScanner({
  onScan,
  onError,
}: {
  onScan: (code: string) => void;
  onError: () => void;
}) {
  const containerRef = useRef<HTMLDivElement>(null);
  const scannerRef = useRef<any>(null);
  const mountedRef = useRef(true);
  const elementId = useRef(`qr-scanner-${Date.now()}`);
  const [facingMode, setFacingMode] = useState<'environment' | 'user'>('environment');
  const [ready, setReady] = useState(false);

  // Full cleanup helper
  const destroyScanner = useCallback(async () => {
    if (scannerRef.current) {
      try { await scannerRef.current.stop(); } catch {}
      try { scannerRef.current.clear(); } catch {}
      scannerRef.current = null;
    }
    stopAllTracks();
  }, []);

  // Start scanner on mount, destroy on unmount
  useEffect(() => {
    mountedRef.current = true;
    let cancelled = false;

    const init = async () => {
      const container = containerRef.current;
      if (!container) return;

      // Create a fresh div for the scanner
      const id = elementId.current;
      container.innerHTML = '';
      const div = document.createElement('div');
      div.id = id;
      div.style.width = '100%';
      div.style.height = '100%';
      container.appendChild(div);

      try {
        const { Html5Qrcode } = await import('html5-qrcode');
        if (cancelled) return;

        const scanner = new Html5Qrcode(id);
        scannerRef.current = scanner;

        await scanner.start(
          { facingMode },
          { fps: 10, qrbox: { width: 250, height: 250 }, aspectRatio: 1 },
          (decodedText: string) => {
            if (mountedRef.current) onScan(decodedText);
          },
          () => {}
        );

        if (cancelled) {
          await destroyScanner();
          return;
        }

        // Force layout recalculation after camera starts
        requestAnimationFrame(() => {
          if (container) {
            container.style.display = 'none';
            // eslint-disable-next-line @typescript-eslint/no-unused-expressions
            container.offsetHeight; // force reflow
            container.style.display = '';
          }
          if (mountedRef.current) setReady(true);
        });
      } catch (error: any) {
        console.error('Scanner error:', error);
        if (!cancelled && mountedRef.current) {
          toast.error('Failed to start camera. Check permissions.');
          onError();
        }
      }
    };

    init();

    return () => {
      cancelled = true;
      mountedRef.current = false;
      destroyScanner();
    };
  }, [facingMode]); // restart when camera flips

  // Handle browser visibility change (suspend/resume)
  useEffect(() => {
    const handleVisibility = () => {
      if (document.visibilityState === 'hidden') {
        destroyScanner();
      } else if (document.visibilityState === 'visible' && mountedRef.current) {
        // Re-trigger by flipping facingMode back-and-forth (forces useEffect re-run)
        setFacingMode((prev) => {
          // Toggle and toggle back to trigger the effect
          const temp = prev === 'environment' ? 'user' : 'environment';
          setTimeout(() => {
            if (mountedRef.current) setFacingMode(prev);
          }, 100);
          return temp;
        });
      }
    };

    document.addEventListener('visibilitychange', handleVisibility);
    return () => document.removeEventListener('visibilitychange', handleVisibility);
  }, [destroyScanner]);

  const switchCamera = () => {
    setFacingMode((prev) => (prev === 'environment' ? 'user' : 'environment'));
  };

  return (
    <div className="relative w-full bg-black flex-1 min-h-0 overflow-hidden">
      <div
        ref={containerRef}
        className="w-full h-full [&_video]:!object-cover [&_video]:!h-full [&_video]:!w-full"
      />
      {ready && (
        <button
          onClick={switchCamera}
          className="absolute top-3 right-3 z-10 bg-black/50 backdrop-blur-sm text-white p-2.5 rounded-full active:scale-95 transition-transform"
          aria-label="Switch camera"
        >
          <VideoCameraIcon className="w-5 h-5" />
        </button>
      )}
      {!ready && (
        <div className="absolute inset-0 flex items-center justify-center text-gray-400">
          <div className="text-center">
            <QrCodeIcon className="w-16 h-16 mx-auto mb-2 opacity-30" />
            <p className="text-sm opacity-60">Starting camera...</p>
          </div>
        </div>
      )}
    </div>
  );
}

// ─── Fullscreen Valid Ticket State ───────────────────────────
function ValidTicketScreen({
  validation,
  onConfirmCheckin,
  onClose,
  checkingIn,
}: {
  validation: TicketValidationResult;
  onConfirmCheckin: () => void;
  onClose: () => void;
  checkingIn: boolean;
}) {
  return (
    <div className="fixed inset-0 z-50 bg-emerald-600 flex flex-col animate-in fade-in duration-200">
      {/* Close button (dismiss without check-in) */}
      <div className="flex justify-end p-4">
        <button
          onClick={onClose}
          className="p-2 rounded-full bg-white/20 text-white active:scale-95 transition-transform"
          aria-label="Close"
        >
          <XMarkIcon className="w-6 h-6" />
        </button>
      </div>
      <div className="flex-1 flex flex-col items-center justify-center px-6 -mt-14 text-white">
        <div className="w-24 h-24 rounded-full bg-white/20 flex items-center justify-center mb-6">
          <CheckCircleIcon className="w-16 h-16 text-white" />
        </div>
        <h2 className="text-3xl font-bold mb-1 text-center">
          {validation.ticket?.attendeeName || 'Guest'}
        </h2>
        {validation.ticket?.attendeeEmail && (
          <p className="text-emerald-100 text-lg mb-4">{validation.ticket.attendeeEmail}</p>
        )}
        {/* Unpaid tickets are valid for entry but the balance is collected at the door */}
        {validation.ticket?.paymentStatus === 'unpaid' && (
          <div className="bg-orange-500 rounded-2xl px-6 py-3 w-full max-w-sm text-center mb-3">
            <p className="font-bold text-lg">UNPAID — collect payment</p>
            {!!validation.ticket.amountDue && (
              <p className="text-orange-100 text-sm">
                Balance due: {formatCurrency(validation.ticket.amountDue)}
              </p>
            )}
          </div>
        )}
        <div className="bg-white/15 rounded-2xl px-6 py-4 w-full max-w-sm space-y-2 text-center">
          {validation.event && (
            <p className="font-semibold text-lg">{validation.event.title}</p>
          )}
          <p className="text-emerald-100 font-mono text-sm">
            Ticket: {validation.ticket?.id.slice(0, 12)}...
          </p>
        </div>
      </div>
      <div className="p-6 pb-safe">
        <button
          onClick={onConfirmCheckin}
          disabled={checkingIn}
          className="w-full py-5 bg-white text-emerald-700 font-bold text-xl rounded-2xl active:scale-[0.98] transition-transform disabled:opacity-50 flex items-center justify-center gap-3"
        >
          {checkingIn ? (
            <div className="w-6 h-6 border-3 border-emerald-700 border-t-transparent rounded-full animate-spin" />
          ) : (
            <>
              <CheckCircleIcon className="w-7 h-7" />
              Confirm Check-in
            </>
          )}
        </button>
      </div>
    </div>
  );
}

// ─── Fullscreen Invalid Ticket State ─────────────────────────
function InvalidTicketScreen({
  reason,
  validation,
  error,
  onScanNext,
}: {
  reason: InvalidReason;
  validation?: TicketValidationResult;
  error?: string;
  onScanNext: () => void;
}) {
  const reasonText: Record<InvalidReason, string> = {
    already_checked_in: 'Already Checked In',
    cancelled: 'Ticket Cancelled',
    not_found: 'Ticket Not Found',
    pending: 'Payment Pending',
    wrong_event: 'Wrong Event',
    unknown: 'Invalid Ticket',
  };

  const reasonDetail: Record<InvalidReason, string> = {
    already_checked_in: validation?.ticket?.checkinAt
      ? `Checked in at ${parseDate(validation.ticket.checkinAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', timeZone: EVENT_TIMEZONE })}${validation.ticket.checkedInBy ? ` by ${validation.ticket.checkedInBy}` : ''}`
      : 'This ticket was already used',
    cancelled: 'This ticket has been cancelled and is no longer valid.',
    not_found: error || 'No ticket matching this code was found.',
    pending: 'This ticket has not been paid for yet.',
    wrong_event: 'This ticket belongs to a different event.',
    unknown: error || 'This ticket could not be validated.',
  };

  return (
    <div className="fixed inset-0 z-50 bg-red-600 flex flex-col animate-in fade-in duration-200">
      <div className="flex-1 flex flex-col items-center justify-center px-6 text-white">
        <div className="w-24 h-24 rounded-full bg-white/20 flex items-center justify-center mb-6">
          <XCircleIcon className="w-16 h-16 text-white" />
        </div>
        <h2 className="text-3xl font-bold mb-2 text-center">{reasonText[reason]}</h2>
        <p className="text-red-100 text-center text-lg max-w-sm">{reasonDetail[reason]}</p>
        {validation?.ticket && (
          <div className="bg-white/15 rounded-2xl px-6 py-4 mt-6 w-full max-w-sm space-y-1 text-center">
            <p className="font-semibold text-lg">{validation.ticket.attendeeName}</p>
            {validation.ticket.attendeeEmail && (
              <p className="text-red-100 text-sm">{validation.ticket.attendeeEmail}</p>
            )}
          </div>
        )}
      </div>
      <div className="p-6 pb-safe">
        <button
          onClick={onScanNext}
          className="w-full py-5 bg-white text-red-700 font-bold text-xl rounded-2xl active:scale-[0.98] transition-transform flex items-center justify-center gap-3"
        >
          <ArrowPathIcon className="w-7 h-7" />
          Scan Next
        </button>
      </div>
    </div>
  );
}

// ─── Search Tab Content ──────────────────────────────────────
function SearchTab({
  eventId,
  onSelectTicket,
}: {
  eventId: string;
  onSelectTicket: (ticket: LiveSearchResult) => void;
}) {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState<LiveSearchResult[]>([]);
  const [loading, setLoading] = useState(false);
  const [hasSearched, setHasSearched] = useState(false);
  const inputRef = useRef<HTMLInputElement>(null);
  const debounceRef = useRef<ReturnType<typeof setTimeout>>();

  // Auto-focus search field
  useEffect(() => {
    setTimeout(() => inputRef.current?.focus(), 100);
  }, []);

  // Debounced live search
  useEffect(() => {
    if (debounceRef.current) clearTimeout(debounceRef.current);

    if (query.trim().length < 2) {
      setResults([]);
      setHasSearched(false);
      return;
    }

    debounceRef.current = setTimeout(async () => {
      setLoading(true);
      setHasSearched(true);
      try {
        const { tickets } = await ticketsApi.searchLive(query.trim(), eventId || undefined);
        setResults(tickets);
      } catch (err: any) {
        console.error('Search error:', err);
        setResults([]);
      } finally {
        setLoading(false);
      }
    }, 300);

    return () => {
      if (debounceRef.current) clearTimeout(debounceRef.current);
    };
  }, [query, eventId]);

  const statusBadge = (status: string) => {
    const config: Record<string, { bg: string; text: string; label: string }> = {
      confirmed: { bg: 'bg-emerald-100', text: 'text-emerald-700', label: 'Confirmed' },
      checked_in: { bg: 'bg-blue-100', text: 'text-blue-700', label: 'Checked In' },
      pending: { bg: 'bg-yellow-100', text: 'text-yellow-700', label: 'Pending' },
      cancelled: { bg: 'bg-red-100', text: 'text-red-700', label: 'Cancelled' },
    };
    const c = config[status] || { bg: 'bg-gray-100', text: 'text-gray-700', label: status };
    return (
      <span className={clsx('inline-block px-2.5 py-1 rounded-full text-xs font-semibold', c.bg, c.text)}>
        {c.label}
      </span>
    );
  };

  return (
    <div className="flex flex-col flex-1 min-h-0">
      {/* Search input */}
      <div className="px-4 pt-4 pb-3">
        <div className="relative">
          <MagnifyingGlassIcon className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400" />
          <input
            ref={inputRef}
            type="text"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            placeholder="Search by name, email, or ticket ID..."
            className="w-full pl-12 pr-4 py-4 bg-gray-800 border border-gray-700 rounded-2xl text-white placeholder:text-gray-500 text-lg focus:outline-none focus:ring-2 focus:ring-primary-yellow focus:border-transparent"
            autoComplete="off"
            autoCorrect="off"
            spellCheck={false}
          />
          {loading && (
            <div className="absolute right-4 top-1/2 -translate-y-1/2">
              <div className="w-5 h-5 border-2 border-gray-500 border-t-primary-yellow rounded-full animate-spin" />
            </div>
          )}
        </div>
      </div>

      {/* Results */}
      <div className="flex-1 overflow-y-auto px-4 pb-4 space-y-2">
        {!hasSearched && query.length < 2 && (
          <div className="text-center text-gray-500 pt-12">
            <MagnifyingGlassIcon className="w-12 h-12 mx-auto mb-3 opacity-30" />
            <p className="text-sm">Type at least 2 characters to search</p>
          </div>
        )}
        {hasSearched && !loading && results.length === 0 && (
          <div className="text-center text-gray-500 pt-12">
            <p className="text-sm">No tickets found</p>
          </div>
        )}
        {results.map((ticket) => (
          <button
            key={ticket.ticket_id}
            onClick={() => onSelectTicket(ticket)}
            className="w-full text-left bg-gray-800 border border-gray-700 rounded-2xl p-4 active:scale-[0.98] transition-all hover:border-gray-600"
          >
            <div className="flex items-center gap-3">
              <div className="w-12 h-12 rounded-full bg-gray-700 flex items-center justify-center flex-shrink-0">
                <UserIcon className="w-6 h-6 text-gray-400" />
              </div>
              <div className="flex-1 min-w-0">
                <p className="font-semibold text-white text-lg truncate">{ticket.name}</p>
                {ticket.email && (
                  <p className="text-gray-400 text-sm truncate">{ticket.email}</p>
                )}
              </div>
              <div className="flex-shrink-0">{statusBadge(ticket.status)}</div>
            </div>
          </button>
        ))}
      </div>
    </div>
  );
}

// ─── Ticket Detail View (from search) ────────────────────────
function TicketDetailView({
  validation,
  onCheckin,
  onBack,
  checkingIn,
}: {
  validation: TicketValidationResult;
  onCheckin: () => void;
  onBack: () => void;
  checkingIn: boolean;
}) {
  const isValid = validation.status === 'valid' && validation.canCheckIn;
  const isCheckedIn = validation.status === 'already_checked_in';
  const isPending = validation.status === 'pending_payment';
  const isCancelled = validation.status === 'cancelled';

  const bgColor = isValid ? 'bg-emerald-600' : isCheckedIn ? 'bg-blue-600' : isPending ? 'bg-amber-600' : 'bg-red-600';

  return (
    <div className={clsx('fixed inset-0 z-50 flex flex-col animate-in fade-in duration-200', bgColor)}>
      {/* Back button */}
      <div className="p-4">
        <button
          onClick={onBack}
          className="flex items-center gap-2 text-white/80 hover:text-white active:scale-95 transition-all"
        >
          <ArrowLeftIcon className="w-5 h-5" />
          <span className="font-medium">Back</span>
        </button>
      </div>

      <div className="flex-1 flex flex-col items-center justify-center px-6 text-white">
        <div className="w-20 h-20 rounded-full bg-white/20 flex items-center justify-center mb-5">
          {isValid ? (
            <CheckCircleIcon className="w-12 h-12" />
          ) : isCheckedIn ? (
            <CheckCircleIcon className="w-12 h-12" />
          ) : (
            <XCircleIcon className="w-12 h-12" />
          )}
        </div>

        <h2 className="text-3xl font-bold mb-1 text-center">
          {validation.ticket?.attendeeName || 'Unknown'}
        </h2>
        {validation.ticket?.attendeeEmail && (
          <p className="text-white/70 text-lg mb-4">{validation.ticket.attendeeEmail}</p>
        )}

        <div className="bg-white/15 rounded-2xl px-6 py-4 w-full max-w-sm space-y-2 text-center">
          <p className="text-sm uppercase tracking-wide text-white/60">Status</p>
          <p className="font-bold text-xl">
            {isValid ? 'Ready for Check-in' : isCheckedIn ? 'Already Checked In' : isPending ? 'Payment Pending' : isCancelled ? 'Cancelled' : 'Invalid'}
          </p>
          {validation.event && (
            <p className="text-white/70 text-sm mt-2">{validation.event.title}</p>
          )}
          <p className="text-white/50 font-mono text-xs mt-1">
            ID: {validation.ticket?.id.slice(0, 12)}...
          </p>
        </div>
      </div>

      <div className="px-6 pb-safe mb-12">
        {isValid ? (
          <button
            onClick={onCheckin}
            disabled={checkingIn}
            className="w-full py-5 bg-white text-emerald-700 font-bold text-xl rounded-2xl active:scale-[0.98] transition-transform disabled:opacity-50 flex items-center justify-center gap-3"
          >
            {checkingIn ? (
              <div className="w-6 h-6 border-3 border-emerald-700 border-t-transparent rounded-full animate-spin" />
            ) : (
              <>
                <CheckCircleIcon className="w-7 h-7" />
                Check In
              </>
            )}
          </button>
        ) : (
          <button
            onClick={onBack}
            className="w-full py-5 bg-white/20 text-white font-bold text-xl rounded-2xl active:scale-[0.98] transition-transform"
          >
            Back to Search
          </button>
        )}
      </div>
    </div>
  );
}

// ─── Recent Tab Content ──────────────────────────────────────
function RecentTab({ recentCheckins, sessionCount }: { recentCheckins: RecentCheckin[]; sessionCount: number }) {
  return (
    <div className="flex flex-col flex-1 min-h-0">
      {/* Session counter */}
      <div className="px-4 pt-4 pb-3">
        <div className="bg-gray-800 border border-gray-700 rounded-2xl p-4 text-center">
          <p className="text-4xl font-bold text-primary-yellow">{sessionCount}</p>
          <p className="text-gray-400 text-sm mt-1">Checked in this session</p>
        </div>
      </div>

      {/* Recent list */}
      <div className="flex-1 overflow-y-auto px-4 pb-4">
        {recentCheckins.length === 0 ? (
          <div className="text-center text-gray-500 pt-12">
            <ClockIcon className="w-12 h-12 mx-auto mb-3 opacity-30" />
            <p className="text-sm">No check-ins yet</p>
          </div>
        ) : (
          <div className="space-y-2">
            {recentCheckins.map((checkin, i) => (
              <div
                key={`${checkin.ticketId}-${i}`}
                className="bg-gray-800 border border-gray-700 rounded-2xl p-4 flex items-center gap-3"
              >
                <div className="w-10 h-10 rounded-full bg-emerald-900/50 flex items-center justify-center flex-shrink-0">
                  <CheckCircleIcon className="w-5 h-5 text-emerald-400" />
                </div>
                <div className="flex-1 min-w-0">
                  <p className="font-medium text-white truncate">{checkin.name}</p>
                  <p className="text-gray-500 text-xs font-mono truncate">{checkin.ticketId.slice(0, 12)}...</p>
                </div>
                <p className="text-gray-400 text-sm flex-shrink-0">{checkin.time}</p>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════
// ─── Main Scanner Page ───────────────────────────────────────
// ═══════════════════════════════════════════════════════════════
export default function AdminScannerPage() {
  const { locale } = useLanguage();
  const router = useRouter();
  const { user } = useAuth();

  // Determine back destination based on role (staff can only access scanner/events)
  const backHref = user?.role === 'staff' ? '/admin/events' : '/admin';

  // Events
  const [events, setEvents] = useState<Event[]>([]);
  const [selectedEventId, setSelectedEventId] = useState<string>('');
  const [loading, setLoading] = useState(true);

  // Tabs
  const [activeTab, setActiveTab] = useState<ActiveTab>('scan');

  // Scanner state
  const [scannerKey, setScannerKey] = useState(0); // increment to force remount
  const [scanResult, setScanResult] = useState<ScanResultData>({ state: 'idle' });
  const [lastScannedCode, setLastScannedCode] = useState('');
  const [checkingIn, setCheckingIn] = useState(false);

  // Search detail view
  const [searchDetailValidation, setSearchDetailValidation] = useState<TicketValidationResult | null>(null);

  // Stats
  const [checkinCount, setCheckinCount] = useState(0);
  const [recentCheckins, setRecentCheckins] = useState<RecentCheckin[]>([]);

  // Event stats
  const [eventCheckedIn, setEventCheckedIn] = useState(0);
  const [eventCapacity, setEventCapacity] = useState(0);

  // Refs
  const selectedEventIdRef = useRef('');
  const lastScannedCodeRef = useRef('');

  useEffect(() => { selectedEventIdRef.current = selectedEventId; }, [selectedEventId]);
  useEffect(() => { lastScannedCodeRef.current = lastScannedCode; }, [lastScannedCode]);

  // Load events
  useEffect(() => {
    eventsApi.getAll()
      .then((res) => {
        const bookable = res.events.filter((e) => e.status === 'published' || e.status === 'unlisted');
        setEvents(bookable);
        const upcoming = bookable.filter((e) => new Date(e.startDatetime) >= new Date());
        if (upcoming.length === 1) {
          setSelectedEventId(upcoming[0].id);
        }
      })
      .catch(console.error)
      .finally(() => setLoading(false));
  }, []);

  // Load event check-in stats when event changes
  useEffect(() => {
    if (!selectedEventId) {
      setEventCheckedIn(0);
      setEventCapacity(0);
      return;
    }

    const loadStats = async () => {
      try {
        const stats = await ticketsApi.getCheckinStats(selectedEventId);
        setEventCapacity(stats.capacity);
        setEventCheckedIn(stats.checkedIn);
      } catch (err) {
        console.error('Failed to load event stats:', err);
      }
    };
    loadStats();
  }, [selectedEventId]);

  // When scan tab becomes active again or scan result is dismissed, bump key to remount scanner
  const scannerActive = activeTab === 'scan' && scanResult.state === 'idle' && !loading;

  // Validate ticket
  const validateTicket = useCallback(async (code: string) => {
    try {
      const result = await ticketsApi.validate(code, selectedEventIdRef.current || undefined);

      if (result.status === 'valid') {
        vibrate(100);
        playSuccessSound();
        setScanResult({ state: 'valid', validation: result });
      } else {
        vibrate([100, 50, 100]);
        playErrorSound();
        let reason: InvalidReason = 'unknown';
        if (result.status === 'already_checked_in') reason = 'already_checked_in';
        else if (result.status === 'cancelled') reason = 'cancelled';
        else if (result.status === 'pending_payment') reason = 'pending';
        else if (result.status === 'wrong_event') reason = 'wrong_event';
        else if (result.status === 'invalid') reason = 'not_found';
        setScanResult({ state: 'invalid', validation: result, invalidReason: reason });
      }
    } catch (error: any) {
      vibrate([100, 50, 100]);
      playErrorSound();
      setScanResult({
        state: 'invalid',
        invalidReason: 'not_found',
        error: error.message || 'Failed to validate ticket',
      });
    }
  }, []);

  // Handle QR scan
  const handleScan = useCallback((decodedText: string) => {
    if (decodedText === lastScannedCodeRef.current) return;
    lastScannedCodeRef.current = decodedText;
    setLastScannedCode(decodedText);

    let code = decodedText;
    const urlMatch = decodedText.match(/\/ticket\/([a-zA-Z0-9-_]+)/);
    if (urlMatch) code = urlMatch[1];

    validateTicket(code);
  }, [validateTicket]);

  // Check in ticket (from scan)
  const handleCheckin = async () => {
    if (!scanResult.validation?.ticket?.id) return;
    setCheckingIn(true);
    try {
      const result = await ticketsApi.checkin(scanResult.validation.ticket.id);
      vibrate(200);
      toast.success(`${result.ticket.attendeeName || 'Guest'} checked in!`);

      setCheckinCount((p) => p + 1);
      setEventCheckedIn((p) => p + 1);
      setRecentCheckins((prev) => [
        {
          name: result.ticket.attendeeName || 'Guest',
          time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', timeZone: EVENT_TIMEZONE }),
          ticketId: scanResult.validation!.ticket!.id,
        },
        ...prev.slice(0, 19),
      ]);

      // Auto-return to camera after 1.5s
      setTimeout(() => {
        resetScan();
      }, 1500);
    } catch (error: any) {
      toast.error(error.message || 'Check-in failed');
    } finally {
      setCheckingIn(false);
    }
  };

  // Check in from search detail
  const handleSearchCheckin = async () => {
    if (!searchDetailValidation?.ticket?.id) return;
    setCheckingIn(true);
    try {
      const result = await ticketsApi.checkin(searchDetailValidation.ticket.id);
      vibrate(200);
      toast.success(`${result.ticket.attendeeName || 'Guest'} checked in!`);

      setCheckinCount((p) => p + 1);
      setEventCheckedIn((p) => p + 1);
      setRecentCheckins((prev) => [
        {
          name: result.ticket.attendeeName || 'Guest',
          time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', timeZone: EVENT_TIMEZONE }),
          ticketId: searchDetailValidation!.ticket!.id,
        },
        ...prev.slice(0, 19),
      ]);

      setSearchDetailValidation(null);
    } catch (error: any) {
      toast.error(error.message || 'Check-in failed');
    } finally {
      setCheckingIn(false);
    }
  };

  // Select search result → validate and show detail
  const handleSelectSearchResult = async (ticket: LiveSearchResult) => {
    try {
      const result = await ticketsApi.validate(ticket.qrCode || ticket.ticket_id, selectedEventIdRef.current || undefined);
      setSearchDetailValidation(result);
    } catch (err: any) {
      toast.error(err.message || 'Failed to load ticket details');
    }
  };

  // Reset scan state — bump key so scanner fully remounts
  const resetScan = () => {
    setScanResult({ state: 'idle' });
    setLastScannedCode('');
    lastScannedCodeRef.current = '';
    setScannerKey((k) => k + 1);
  };

  // Get selected event name
  const selectedEvent = events.find((e) => e.id === selectedEventId);

  if (loading) {
    return (
      <div className="min-h-screen bg-gray-950 flex items-center justify-center">
        <div className="animate-spin w-8 h-8 border-4 border-primary-yellow border-t-transparent rounded-full" />
      </div>
    );
  }

  return (
    <div className="bg-gray-950 flex flex-col overflow-hidden" style={{ height: '100dvh' }}>
      {/* ── Sticky Header ── */}
      <header className="flex-shrink-0 bg-gray-900 border-b border-gray-800 px-4 py-3 safe-area-top">
        <div className="flex items-center justify-between gap-3">
          {/* Back to dashboard */}
          <button
            onClick={() => router.push(backHref)}
            className="flex-shrink-0 p-2 -ml-1 rounded-xl text-gray-400 hover:text-white active:scale-95 transition-all"
            aria-label="Back to dashboard"
          >
            <ArrowLeftIcon className="w-5 h-5" />
          </button>
          {/* Event selector */}
          <div className="flex-1 min-w-0">
            <select
              value={selectedEventId}
              onChange={(e) => setSelectedEventId(e.target.value)}
              className="w-full bg-gray-800 border border-gray-700 text-white rounded-xl px-3 py-2 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-primary-yellow truncate"
            >
              <option value="">All Events</option>
              {events.map((event) => (
                <option key={event.id} value={event.id}>
                  {event.title}
                </option>
              ))}
            </select>
          </div>
          {/* Live counter */}
          {selectedEventId && eventCapacity > 0 && (
            <div className="flex-shrink-0 bg-gray-800 border border-gray-700 rounded-xl px-3 py-2">
              <p className="text-primary-yellow font-bold text-sm whitespace-nowrap">
                {eventCheckedIn} / {eventCapacity}
              </p>
              <p className="text-gray-400 text-[10px] text-center">Checked in</p>
            </div>
          )}
        </div>
      </header>

      {/* ── Tab Bar ── */}
      <div className="flex-shrink-0 bg-gray-900 border-b border-gray-800">
        <div className="flex">
          {(
            [
              { key: 'scan' as ActiveTab, label: 'Scan', icon: QrCodeIcon },
              { key: 'search' as ActiveTab, label: 'Search', icon: MagnifyingGlassIcon },
              { key: 'recent' as ActiveTab, label: 'Recent', icon: ClockIcon },
            ] as const
          ).map((tab) => (
            <button
              key={tab.key}
              onClick={() => setActiveTab(tab.key)}
              className={clsx(
                'flex-1 flex items-center justify-center gap-2 py-4 text-sm font-semibold transition-colors relative',
                activeTab === tab.key
                  ? 'text-primary-yellow'
                  : 'text-gray-500 active:text-gray-300'
              )}
            >
              <tab.icon className="w-5 h-5" />
              {tab.label}
              {tab.key === 'recent' && checkinCount > 0 && (
                <span className="bg-primary-yellow text-gray-900 text-xs font-bold px-1.5 py-0.5 rounded-full min-w-[20px] text-center">
                  {checkinCount}
                </span>
              )}
              {activeTab === tab.key && (
                <span className="absolute bottom-0 left-4 right-4 h-0.5 bg-primary-yellow rounded-full" />
              )}
            </button>
          ))}
        </div>
      </div>

      {/* ── Tab Content ── */}
      <div className="flex-1 min-h-0 flex flex-col overflow-hidden">
        {/* SCAN TAB — scanner fully unmounts when not active */}
        {scannerActive && (
          <QRScanner
            key={scannerKey}
            onScan={handleScan}
            onError={() => {}}
          />
        )}
        {activeTab === 'scan' && !scannerActive && scanResult.state !== 'idle' && (
          <div className="flex-1 bg-black" />
        )}

        {/* SEARCH TAB */}
        {activeTab === 'search' && (
          <SearchTab eventId={selectedEventId} onSelectTicket={handleSelectSearchResult} />
        )}

        {/* RECENT TAB */}
        {activeTab === 'recent' && (
          <RecentTab recentCheckins={recentCheckins} sessionCount={checkinCount} />
        )}
      </div>

      {/* ── Fullscreen overlays ── */}
      {scanResult.state === 'valid' && scanResult.validation && (
        <ValidTicketScreen
          validation={scanResult.validation}
          onConfirmCheckin={handleCheckin}
          onClose={resetScan}
          checkingIn={checkingIn}
        />
      )}

      {scanResult.state === 'invalid' && (
        <InvalidTicketScreen
          reason={scanResult.invalidReason || 'unknown'}
          validation={scanResult.validation}
          error={scanResult.error}
          onScanNext={resetScan}
        />
      )}

      {searchDetailValidation && (
        <TicketDetailView
          validation={searchDetailValidation}
          onCheckin={handleSearchCheckin}
          onBack={() => setSearchDetailValidation(null)}
          checkingIn={checkingIn}
        />
      )}
    </div>
  );
}
