'use client';

import { useState, useEffect, useRef, useCallback } from 'react';
import { QrCodeIcon, XMarkIcon, VideoCameraIcon } from '@heroicons/react/24/outline';
import toast from 'react-hot-toast';

// The camera is a fullscreen overlay opened from the search row, not a tab. It
// only exists while a scan is happening, so it never holds the camera (or the
// screen) while staff are typing a name.

/** Release any camera stream html5-qrcode left attached to a <video> element. */
function stopAllTracks() {
  try {
    document.querySelectorAll('video').forEach((video) => {
      const stream = video.srcObject as MediaStream | null;
      if (stream) {
        stream.getTracks().forEach((track) => track.stop());
        video.srcObject = null;
      }
    });
  } catch {}
}

export function QRScannerOverlay({
  onScan,
  onClose,
}: {
  onScan: (code: string) => void;
  onClose: () => 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);

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

  useEffect(() => {
    mountedRef.current = true;
    let cancelled = false;

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

      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 a layout pass: some browsers leave the video mis-sized until reflow.
        requestAnimationFrame(() => {
          if (container) {
            container.style.display = 'none';
            // eslint-disable-next-line @typescript-eslint/no-unused-expressions
            container.offsetHeight;
            container.style.display = '';
          }
          if (mountedRef.current) setReady(true);
        });
      } catch (error) {
        console.error('Scanner error:', error);
        if (!cancelled && mountedRef.current) {
          toast.error('Failed to start camera. Check permissions.');
          onClose();
        }
      }
    };

    init();

    return () => {
      cancelled = true;
      mountedRef.current = false;
      destroyScanner();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [facingMode]);

  // Backgrounding the browser suspends the camera; drop it and rebuild on return.
  useEffect(() => {
    const handleVisibility = () => {
      if (document.visibilityState === 'hidden') {
        destroyScanner();
      } else if (document.visibilityState === 'visible' && mountedRef.current) {
        setFacingMode((prev) => {
          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]);

  return (
    <div className="fixed inset-0 z-50 bg-black flex flex-col">
      <div className="flex-shrink-0 flex items-center justify-between px-4 py-3 safe-area-top">
        <p className="text-white font-semibold">Scan ticket</p>
        <div className="flex items-center gap-2">
          {ready && (
            <button
              onClick={() => setFacingMode((prev) => (prev === 'environment' ? 'user' : 'environment'))}
              className="min-w-[48px] min-h-[48px] flex items-center justify-center bg-white/10 text-white rounded-full active:scale-95 transition-transform"
              aria-label="Switch camera"
            >
              <VideoCameraIcon className="w-6 h-6" />
            </button>
          )}
          <button
            onClick={onClose}
            className="min-w-[48px] min-h-[48px] flex items-center justify-center bg-white/10 text-white rounded-full active:scale-95 transition-transform"
            aria-label="Close scanner"
          >
            <XMarkIcon className="w-6 h-6" />
          </button>
        </div>
      </div>

      <div className="relative 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 && (
          <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>

      <div className="flex-shrink-0 px-6 py-5 pb-safe">
        <p className="text-center text-gray-400 text-sm">
          Point at the ticket QR — it checks in and closes automatically.
        </p>
      </div>
    </div>
  );
}
