import { useState, useRef, useEffect } from 'react';
import { Camera, X, CheckCircle2, AlertCircle } from 'lucide-react';
import jsQR from 'jsqr';

interface QRScannerProps {
    onScanSuccess: (data: string | Uint8Array) => void;
    onClose: () => void;
    onError?: (error: string) => void;
}

export default function QRScanner({ onScanSuccess, onClose, onError }: QRScannerProps) {
    const [internalError, setInternalError] = useState<string>('');
    const [success, setSuccess] = useState(false);
    const [hasPermission, setHasPermission] = useState<boolean | null>(null);
    const videoRef = useRef<HTMLVideoElement>(null);
    const canvasRef = useRef<HTMLCanvasElement>(null);

    useEffect(() => {
        let stream: MediaStream | null = null;
        let scanInterval: number | null = null;
        let isCancelled = false;

        const stopScanning = () => {
            if (scanInterval) clearInterval(scanInterval);
            if (stream) stream.getTracks().forEach(track => track.stop());
        };

        const startScanning = async () => {
            try {
                stream = await navigator.mediaDevices.getUserMedia({
                    video: { facingMode: 'environment' }
                });

                if (isCancelled) return stopScanning();

                setHasPermission(true);
                const video = videoRef.current;
                const canvas = canvasRef.current;

                if (video && canvas) {
                    video.srcObject = stream;
                    await video.play();

                    if (isCancelled) return stopScanning();

                    const ctx = canvas.getContext('2d');
                    if (!ctx) {
                        setInternalError('Canvas context not available');
                        return stopScanning();
                    }

                    scanInterval = window.setInterval(() => {
                        if (isCancelled || !video || video.paused || video.ended) return;
                        if (!video.videoWidth || !video.videoHeight) return;

                        canvas.width = video.videoWidth;
                        canvas.height = video.videoHeight;
                        ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

                        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                        const code = jsQR(imageData.data, imageData.width, imageData.height, {
                            inversionAttempts: 'dontInvert'
                        });

                        if (code) {
                            isCancelled = true;
                            stopScanning();
                            setSuccess(true);

                            // jsQR gives us raw bytes!
                            const rawBytes = code.binaryData;

                            // Detect binary (16 or 32 bytes with non-printable chars)
                            const isBinary = (rawBytes.length === 16 || rawBytes.length === 32) &&
                                /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\xFF]/.test(String.fromCharCode(...Array.from(rawBytes)));

                            if (isBinary) {
                                onScanSuccess(new Uint8Array(rawBytes));
                            } else {
                                // Text QR - use the text property
                                onScanSuccess(code.data);
                            }

                            setTimeout(() => onClose(), 1000);
                        }
                    }, 300);
                }
            } catch (err: any) {
                // IMPORTANT: Check for null/undefined err object first.
                if (!err) {
                    console.error('Caught a null or undefined error inside QRScanner.');
                    return; // Exit if error is falsy
                }

                if (isCancelled || err.name === 'AbortError') {
                    console.log('Camera operation was cancelled or aborted, which is expected on unmount.');
                    return; // Ignore abort errors, they are expected on cleanup
                }

                console.error('Camera error:', err);
                setHasPermission(false);
                
                let errorMsg = 'An unknown camera error occurred.';
                if (err.name === 'NotAllowedError') {
                    errorMsg = 'Camera access was denied. Please grant permission in your browser settings.';
                } else if (err.name === 'NotFoundError') {
                    errorMsg = 'No camera found on this device.';
                } else if (err.name === 'NotReadableError') {
                    errorMsg = 'Cannot access the camera. It may be in use by another application or browser tab.';
                } else if (err.name === 'OverconstrainedError') {
                    errorMsg = 'The camera does not meet the required constraints.';
                } else if (err instanceof Error) {
                    errorMsg = `Camera error: ${err.message}`;
                }

                setInternalError(errorMsg);
                onError?.(errorMsg);
            }
        };

        startScanning();

        return () => {
            isCancelled = true;
            stopScanning();
        };
    }, [onScanSuccess, onClose, onError]);

    return (
        <div className="fixed inset-0 bg-black/80 backdrop-blur-sm flex items-center justify-center z-50">
            <div className="bg-[#16213e] rounded-xl border-2 border-[#00f0ff]/50 p-6 max-w-md w-full mx-4 shadow-[0_0_40px_rgba(0,240,255,0.3)]">
                <div className="flex items-center justify-between mb-4">
                    <h3 className="text-lg font-semibold text-[#00f0ff] flex items-center gap-2" style={{ textShadow: '0 0 10px rgba(0,240,255,0.7)' }}>
                        <Camera size={20} />
                        Scan QR Code
                    </h3>
                    <button onClick={onClose} className="p-2 hover:bg-[#1a1a2e] rounded-lg transition-colors border-2 border-[#00f0ff]/30">
                        <X size={20} className="text-[#6ef3f7]" />
                    </button>
                </div>

                {internalError && (
                    <div className="mb-4 p-3 bg-[#ff006e]/10 border-2 border-[#ff006e]/30 rounded-lg flex items-start gap-2 text-[#ff006e] text-sm">
                        <AlertCircle size={16} className="shrink-0 mt-0.5" />
                        <span>{internalError}</span>
                    </div>
                )}

                {success && (
                    <div className="mb-4 p-3 bg-[#39ff14]/10 border-2 border-[#39ff14]/30 rounded-lg flex items-center gap-2 text-[#39ff14] text-sm">
                        <CheckCircle2 size={16} />
                        <span>QR Code detected!</span>
                    </div>
                )}

                <div className="relative bg-black rounded-lg overflow-hidden border-2 border-[#00f0ff]/30">
                    <video ref={videoRef} className="w-full h-64 object-cover" playsInline muted />
                    <canvas ref={canvasRef} className="hidden" />
                </div>

                {!hasPermission && !internalError && (
                    <p className="text-sm text-[#6ef3f7] mt-3 text-center">Requesting camera access...</p>
                )}

                <button
                    onClick={onClose}
                    className="w-full mt-4 py-2 bg-[#1a1a2e] hover:bg-[#16213e] rounded-lg text-[#00f0ff] font-medium transition-all border-2 border-[#00f0ff]/50 hover:shadow-[0_0_15px_rgba(0,240,255,0.3)]"
                >
                    Cancel
                </button>
            </div>
        </div>
    );
}
