import React, { useEffect, useRef, useState, useCallback } from 'react';
import { startScanner, resumeScanner, stopCurrentScanner } from '../../services/scanner';
import { parseQRCode } from '../../utils/qr';
import { useCheckIn } from '../../hooks/useCheckIn';
import { ScanResult } from './ScanResult';
import {
  playCheckInSuccess,
  playDuplicate,
  playError,
  unlockAudio,
} from '../../utils/audio';
import type { CheckInResult, Guest } from '../../types/guest';

const SINGLE_DISMISS_MS  = 2800;
const DONE_DISMISS_MS    = 2200;
const SINGLE_COOLDOWN_MS = 4000;

interface ActiveScan {
  result: CheckInResult;
  qrText: string;
}

const isMulti = (g: Guest) => g.total_attendees > 1;
const isDone  = (g: Guest) => g.checked_in_count >= g.total_attendees;

export function QRScanner() {
  const videoRef = useRef<HTMLVideoElement>(null);
  const { handleScan } = useCheckIn();

  const [activeScan,  setActiveScan]  = useState<ActiveScan | null>(null);
  const [cameraError, setCameraError] = useState<string | null>(null);
  const [processing,  setProcessing]  = useState(false);

  const activeScanRef = useRef<ActiveScan | null>(null);
  const processingRef = useRef(false);
  const cooldownRef   = useRef<Map<string, number>>(new Map());
  const dismissTimer  = useRef<ReturnType<typeof setTimeout> | null>(null);

  const updateActiveScan = (scan: ActiveScan | null) => {
    activeScanRef.current = scan;
    setActiveScan(scan);
  };

  const clearDismiss = () => {
    if (dismissTimer.current) { clearTimeout(dismissTimer.current); dismissTimer.current = null; }
  };

  const dismiss = useCallback(() => {
    clearDismiss();
    updateActiveScan(null);
    resumeScanner();
  }, []);

  const scheduleDismiss = useCallback((ms: number) => {
    clearDismiss();
    dismissTimer.current = setTimeout(dismiss, ms);
  }, [dismiss]);

  // ─── Core scan handler ─────────────────────────────────────────────────────
  const onQRDetected = useCallback(async (qrText: string) => {
    const now    = Date.now();
    const active = activeScanRef.current;

    // ── A: Same QR on open group/double card → check in next attendee ────────
    if (
      active?.result.guest &&
      active.qrText === qrText &&
      isMulti(active.result.guest) &&
      !isDone(active.result.guest)
    ) {
      if (processingRef.current) { resumeScanner(); return; }

      const parsed = parseQRCode(qrText);
      if (!parsed) { resumeScanner(); return; }

      processingRef.current = true;
      setProcessing(true);
      try {
        const res = await handleScan(parsed);
        if (res.status === 'checked_in' && res.guest) {
          updateActiveScan({ result: res, qrText });
          clearDismiss();
          playCheckInSuccess();
          if (isDone(res.guest)) { scheduleDismiss(DONE_DISMISS_MS); }
        }
      } finally {
        processingRef.current = false;
        setProcessing(false);
      }
      resumeScanner();
      return;
    }

    // ── B: Another modal is open → ignore ────────────────────────────────────
    if (active) { resumeScanner(); return; }

    // ── C: Cooldown on recently-done single card → ignore ────────────────────
    const cooldownExpiry = cooldownRef.current.get(qrText);
    if (cooldownExpiry && now < cooldownExpiry) { resumeScanner(); return; }

    // ── D: Fresh scan ─────────────────────────────────────────────────────────
    if (processingRef.current) { resumeScanner(); return; }

    const parsed = parseQRCode(qrText);
    if (!parsed) {
      playError();
      updateActiveScan({ result: { status: 'not_found', message: 'Unrecognized QR code.' }, qrText });
      scheduleDismiss(2000);
      resumeScanner();
      return;
    }

    processingRef.current = true;
    setProcessing(true);
    try {
      const res = await handleScan(parsed);
      updateActiveScan({ result: res, qrText });

      if (res.status === 'checked_in' && res.guest) {
        playCheckInSuccess();
        if (isMulti(res.guest) && !isDone(res.guest)) {
          resumeScanner(); // keep scanning same card for next person
        } else {
          cooldownRef.current.set(qrText, now + SINGLE_COOLDOWN_MS);
          scheduleDismiss(SINGLE_DISMISS_MS);
          resumeScanner();
        }
      } else if (res.status === 'already_checked_in') {
        playDuplicate();
        scheduleDismiss(2200);
        resumeScanner();
      } else {
        playError();
        scheduleDismiss(2000);
        resumeScanner();
      }
    } finally {
      processingRef.current = false;
      setProcessing(false);
    }
  }, [handleScan, scheduleDismiss]);

  // ─── Next-attendee button handler ─────────────────────────────────────────
  const handleNextAttendee = useCallback(async () => {
    const active = activeScanRef.current;
    if (!active?.result.guest) return;
    if (!isMulti(active.result.guest) || isDone(active.result.guest)) return;
    if (processingRef.current) return;

    const parsed = parseQRCode(active.qrText);
    if (!parsed) return;

    processingRef.current = true;
    setProcessing(true);
    try {
      const res = await handleScan(parsed);
      if (res.status === 'checked_in' && res.guest) {
        updateActiveScan({ result: res, qrText: active.qrText });
        clearDismiss();
        playCheckInSuccess();
        if (isDone(res.guest)) { scheduleDismiss(DONE_DISMISS_MS); }
      }
    } finally {
      processingRef.current = false;
      setProcessing(false);
    }
  }, [handleScan, scheduleDismiss]);

  // ─── Camera init ───────────────────────────────────────────────────────────
  const activate = useCallback(async () => {
    if (!videoRef.current) return;
    setCameraError(null);
    clearDismiss();
    updateActiveScan(null);
    setProcessing(false);

    try {
      await startScanner(videoRef.current, onQRDetected);
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : String(err);
      if (/permission|notallowed/i.test(msg)) {
        setCameraError('Camera permission denied. Allow camera access and reload.');
      } else {
        setCameraError('Camera not available. Tap to retry.');
      }
    }
  }, [onQRDetected]);

  useEffect(() => {
    activate();
    return () => { clearDismiss(); stopCurrentScanner(); };
  }, [activate]);

  return (
    <div
      className="relative h-full bg-black overflow-hidden"
      onClick={unlockAudio}
    >
      <video
        ref={videoRef}
        className="absolute inset-0 w-full h-full object-cover"
        playsInline
        muted
        autoPlay
      />

      {/* ── Viewfinder overlay ─────────────────────────────────────────────── */}
      {!activeScan && !cameraError && (
        <div className="absolute inset-0 flex flex-col items-center justify-center pointer-events-none">
          <div className="relative w-72 h-72">
            <div
              className="absolute inset-0"
              style={{
                boxShadow: '0 0 0 9999px rgba(0,0,0,0.52)',
                borderRadius: '16px',
                border: '1px solid rgba(255,255,255,0.08)',
              }}
            />

            {/* Corner brackets */}
            {(['tl','tr','bl','br'] as const).map(c => (
              <span
                key={c}
                className={[
                  'absolute w-10 h-10 border-4 border-white/90',
                  c === 'tl' ? 'top-0 left-0 border-r-0 border-b-0 rounded-tl-2xl' : '',
                  c === 'tr' ? 'top-0 right-0 border-l-0 border-b-0 rounded-tr-2xl' : '',
                  c === 'bl' ? 'bottom-0 left-0 border-r-0 border-t-0 rounded-bl-2xl' : '',
                  c === 'br' ? 'bottom-0 right-0 border-l-0 border-t-0 rounded-br-2xl' : '',
                ].join(' ')}
              />
            ))}

            {/* Animated scan line */}
            <div className="absolute left-3 right-3 h-0.5 rounded-full bg-gradient-to-r from-transparent via-emerald-400 to-transparent animate-scan-line" />
          </div>

          {/* Status text below viewfinder */}
          {processing ? (
            <div className="mt-6 flex items-center gap-2">
              <svg className="w-4 h-4 text-emerald-400 animate-spin" fill="none" viewBox="0 0 24 24">
                <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
                <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8H4z" />
              </svg>
              <span className="text-emerald-400 text-sm font-semibold tracking-wide">Checking in…</span>
            </div>
          ) : (
            <p className="mt-6 text-white/75 text-sm font-medium tracking-wide">
              Point camera at QR code
            </p>
          )}
        </div>
      )}

      {/* ── Camera error ───────────────────────────────────────────────────── */}
      {cameraError && (
        <div
          className="absolute inset-0 flex flex-col items-center justify-center bg-black/85 text-white p-8 cursor-pointer"
          onClick={activate}
        >
          <div className="w-20 h-20 rounded-full bg-white/10 flex items-center justify-center mb-4">
            <svg className="w-9 h-9 text-white/50" fill="none" stroke="currentColor" strokeWidth={1.5} viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" d="M15 10l4.553-2.069A1 1 0 0121 8.82v6.36a1 1 0 01-1.447.894L15 14M3 8a2 2 0 012-2h8a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2V8z" />
            </svg>
          </div>
          <p className="text-center text-sm text-white/90 mb-1">{cameraError}</p>
          <span className="text-xs text-white/45 mt-1">Tap to retry</span>
        </div>
      )}

      {/* ── Result modal ───────────────────────────────────────────────────── */}
      {activeScan && (
        <ScanResult
          result={activeScan.result}
          onDismiss={dismiss}
          onNextAttendee={handleNextAttendee}
          isProcessing={processing}
        />
      )}
    </div>
  );
}
