/**
 * Advanced Barcode/QR Scanner with Camera Integration
 * Uses ZXing WebAssembly for superior barcode and QR code scanning
 * Optimized for mobile devices with rear camera support
 */

class BarcodeScanner {
    constructor(options = {}) {
        this.options = {
            onSuccess: options.onSuccess || function(code) { console.log('Scanned:', code); },
            onError: options.onError || function(err) { console.error('Scanner error:', err); },
            preferredCamera: options.preferredCamera || 'environment', // 'environment' = rear camera, 'user' = front
            formats: options.formats || [], // ZXing auto-detects all formats
            ...options
        };
        
        this.isScanning = false;
        this.stream = null;
        this.codeReader = null;
        this.lastScannedCode = null;
        this.lastScannedTime = 0;
        this.debounceTime = 500; // Prevent duplicate scans within 500ms
        this.videoElement = null;
        this.selectedDeviceId = null;
    }

    /**
     * Initialize and start the scanner
     */
    async start() {
        if (this.isScanning) {
            console.warn('Scanner already running');
            return;
        }

        try {
            // Create scanner UI if not exists
            this.createScannerUI();

            // Initialize ZXing code reader
            await this.initZXing();

            this.isScanning = true;

            // Show scanner modal
            $('#barcodeScannerModal').modal('show');

        } catch (error) {
            console.error('Failed to start scanner:', error);
            this.options.onError(error);
            this.handleError(error);
        }
    }

    /**
     * Initialize ZXing WebAssembly code reader
     */
    async initZXing() {
        try {
            // Check if ZXing library is loaded
            if (typeof ZXing === 'undefined') {
                throw new Error('ZXing library not loaded');
            }

            // Get video element
            this.videoElement = document.getElementById('scanner-video');
            
            if (!this.videoElement) {
                throw new Error('Video element not found');
            }

            // Create BrowserMultiFormatReader for all barcode/QR types
            this.codeReader = new ZXing.BrowserMultiFormatReader();
            
            console.log('ZXing initialized successfully');

            // Get available video devices
            const videoInputDevices = await this.codeReader.listVideoInputDevices();
            console.log('Available cameras:', videoInputDevices.length);

            // Select preferred camera (rear camera for mobile)
            let selectedDevice = videoInputDevices[0];
            
            // Try to find rear camera
            if (this.options.preferredCamera === 'environment') {
                const rearCamera = videoInputDevices.find(device => 
                    device.label.toLowerCase().includes('back') || 
                    device.label.toLowerCase().includes('rear') ||
                    device.label.toLowerCase().includes('environment')
                );
                
                if (rearCamera) {
                    selectedDevice = rearCamera;
                }
            }

            this.selectedDeviceId = selectedDevice?.deviceId;

            // Start continuous decode from video device
            await this.startDecoding();

        } catch (error) {
            console.error('ZXing initialization error:', error);
            throw error;
        }
    }

    /**
     * Start continuous decoding from camera
     */
    async startDecoding() {
        try {
            console.log('Starting ZXing decoding...');
            
            // Use decodeFromVideoDevice for continuous scanning
            await this.codeReader.decodeFromVideoDevice(
                this.selectedDeviceId,
                this.videoElement,
                (result, error) => {
                    if (result) {
                        // Successful scan
                        this.handleZXingResult(result);
                    }
                    // Errors during scanning are normal (no code found), so we don't log them
                }
            );

            console.log('ZXing decoding started');
            
        } catch (error) {
            console.error('Failed to start decoding:', error);
            throw error;
        }
    }

    /**
     * Handle ZXing scan result
     */
    handleZXingResult(result) {
        if (!result || !result.text) return;

        const code = result.text;
        const format = result.format || result.getBarcodeFormat()?.toString() || 'UNKNOWN';
        
        // Debounce to prevent duplicate scans
        const now = Date.now();
        if (this.lastScannedCode === code && (now - this.lastScannedTime) < this.debounceTime) {
            return;
        }

        this.lastScannedCode = code;
        this.lastScannedTime = now;

        console.log(`Code detected: ${code} (${format})`);
        this.showSuccess(code, format);
        this.options.onSuccess(code, format);
        
        // Auto-close after successful scan
        setTimeout(() => this.stop(), 1000);
    }

    /**
     * Create scanner UI modal
     */
    createScannerUI() {
        // Check if modal already exists
        if ($('#barcodeScannerModal').length > 0) {
            return;
        }

        const modalHTML = `
            <div class="modal fade" id="barcodeScannerModal" tabindex="-1" role="dialog" data-backdrop="static" data-keyboard="false">
                <div class="modal-dialog modal-dialog-centered modal-fullscreen-scanner" role="document">
                    <div class="modal-content scanner-modal-content">
                        <div class="modal-header bg-dark text-white py-2 px-3">
                            <h6 class="modal-title mb-0">
                                <i class="fas fa-camera"></i> Scan Barcode/QR Code
                            </h6>
                            <button type="button" class="close text-white" id="closeScannerBtn">
                                <span>&times;</span>
                            </button>
                        </div>
                        <div class="modal-body p-0 scanner-body">
                            <!-- Scanner viewport -->
                            <div id="scanner-container" class="scanner-container">
                                <video id="scanner-video" class="scanner-video" playsinline autoplay></video>
                                <canvas id="scanner-canvas" class="scanner-canvas"></canvas>
                                
                                <!-- Scanning frame overlay -->
                                <div class="scanner-overlay">
                                    <div class="scanner-frame">
                                        <div class="corner top-left"></div>
                                        <div class="corner top-right"></div>
                                        <div class="corner bottom-left"></div>
                                        <div class="corner bottom-right"></div>
                                        <div class="scanning-line"></div>
                                    </div>
                                </div>

                                <!-- Instructions -->
                                <div class="scanner-instructions">
                                    <p class="mb-1"><i class="fas fa-info-circle"></i> Position barcode within the frame</p>
                                    <p class="mb-0 small">Hold steady for automatic detection</p>
                                </div>

                                <!-- Status indicator -->
                                <div class="scanner-status" id="scannerStatus">
                                    <div class="status-content">
                                        <i class="fas fa-search"></i>
                                        <span>Searching for barcode...</span>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="modal-footer bg-light py-2 px-3">
                            <button type="button" class="btn btn-sm btn-secondary" id="switchCameraBtn">
                                <i class="fas fa-sync-alt"></i> Switch Camera
                            </button>
                            <button type="button" class="btn btn-sm btn-primary" id="toggleFlashlightBtn" style="display:none;">
                                <i class="fas fa-lightbulb"></i> Flashlight
                            </button>
                            <button type="button" class="btn btn-sm btn-danger" id="stopScannerBtn">
                                <i class="fas fa-times"></i> Close
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        `;

        $('body').append(modalHTML);

        // Bind close events
        $('#closeScannerBtn, #stopScannerBtn').on('click', () => this.stop());
        $('#switchCameraBtn').on('click', () => this.switchCamera());
        
        // Prevent modal from closing on backdrop click
        $('#barcodeScannerModal').on('hide.bs.modal', (e) => {
            if (this.isScanning) {
                e.preventDefault();
                this.stop();
            }
        });
    }

    /**
     * Show success feedback
     */
    showSuccess(code, format) {
        const statusDiv = $('#scannerStatus');
        statusDiv.html(`
            <div class="status-content success-animation">
                <i class="fas fa-check-circle text-success"></i>
                <span class="text-success">Code Detected!</span>
                <div class="small mt-1">${code}</div>
            </div>
        `);

        // Play success sound (optional)
        this.playBeep();

        // Flash effect
        $('.scanner-frame').addClass('scan-success');
        setTimeout(() => $('.scanner-frame').removeClass('scan-success'), 500);
    }

    /**
     * Play beep sound on successful scan
     */
    playBeep() {
        try {
            const audioContext = new (window.AudioContext || window.webkitAudioContext)();
            const oscillator = audioContext.createOscillator();
            const gainNode = audioContext.createGain();
            
            oscillator.connect(gainNode);
            gainNode.connect(audioContext.destination);
            
            oscillator.frequency.value = 800;
            oscillator.type = 'sine';
            
            gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
            gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.2);
            
            oscillator.start(audioContext.currentTime);
            oscillator.stop(audioContext.currentTime + 0.2);
        } catch (e) {
            console.warn('Could not play beep sound:', e);
        }
    }

    /**
     * Switch between front and rear camera
     */
    async switchCamera() {
        try {
            // Get available video devices
            const videoInputDevices = await this.codeReader.listVideoInputDevices();
            
            if (videoInputDevices.length < 2) {
                alert('Only one camera available');
                return;
            }

            // Find current device index
            const currentIndex = videoInputDevices.findIndex(
                device => device.deviceId === this.selectedDeviceId
            );

            // Switch to next camera
            const nextIndex = (currentIndex + 1) % videoInputDevices.length;
            this.selectedDeviceId = videoInputDevices[nextIndex].deviceId;

            // Restart scanner with new camera
            if (this.codeReader) {
                this.codeReader.reset();
            }
            
            await this.startDecoding();

        } catch (error) {
            console.error('Failed to switch camera:', error);
            alert('Failed to switch camera: ' + error.message);
        }
    }

    /**
     * Stop scanner and cleanup
     */
    async stop() {
        this.isScanning = false;

        // Stop ZXing code reader
        if (this.codeReader) {
            try {
                this.codeReader.reset();
            } catch (e) {
                console.warn('Error resetting code reader:', e);
            }
        }

        // Clear video element
        if (this.videoElement) {
            this.videoElement.srcObject = null;
        }

        // Hide modal
        $('#barcodeScannerModal').modal('hide');

        // Reset last scanned code
        this.lastScannedCode = null;
        this.lastScannedTime = 0;
    }

    /**
     * Handle scanner errors
     */
    handleError(error) {
        let errorMessage = 'Scanner Error';
        let errorDetails = error.message || 'Unknown error occurred';

        if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {
            errorMessage = 'Camera Permission Denied';
            errorDetails = 'Please allow camera access to use the scanner.';
        } else if (error.name === 'NotFoundError' || error.name === 'DevicesNotFoundError') {
            errorMessage = 'No Camera Found';
            errorDetails = 'No camera device found on this device.';
        } else if (error.name === 'NotReadableError' || error.name === 'TrackStartError') {
            errorMessage = 'Camera In Use';
            errorDetails = 'Camera is being used by another application.';
        }

        alert(`${errorMessage}\n\n${errorDetails}`);
        this.stop();
    }
}

// Export for use
window.BarcodeScanner = BarcodeScanner;
