/**
 * A container that includes a file field for uploading QR code images 
 * and a scanner button to launch a QR scanner dialog using the camera input. 
 * The scanning functionality is powered by the Html5Qrcode library.
 * 
 * @since 8.0.0
 * 
 * ## Example
 * 
 * ```javascript
 * @example({ framework: 'extjs' })
 * Ext.application({
 *     name: 'QRReaderApp',
 *     launch: function() {
 *         Ext.create('Ext.qrcode.reader.QRCodeReader', {
 *             renderTo: Ext.getBody(),
 *             layout: 'fit',
 *             padding: 20,
 *             listeners: {
 *                 qrscanned: function(reader, qrData) {
 *                     console.log('QR Code scanned:', qrData);
 *                 }
 *             }
 *         });
 *     }
 * });
 * ```
 */
Ext.define('Ext.qrcode.reader.QRCodeReader', {
    extend: 'Ext.qrcode.reader.ReaderBase',
 
    xtype: 'qrcodereader',
 
    layout: 'hbox',
 
    config: {
        /**
         * @cfg {Object} scannerConfig
         * Configuration object for the Html5Qrcode scanner
         * 
         * @since 8.0.0
         */
        scannerConfig: {
            fps: 10,
            qrbox: 250,
            aspectRatio: 1.1
        },
 
        /**
         * @cfg {String} scanButtonText
         * Label text for the scanner button
         * 
         * @since 8.0.0
         */
        scanButtonText: 'Open Scanner',
 
        /**
         * @cfg {Boolean} autoStopAfterScan
         * Whether to automatically stop scanning after successful scan
         * 
         * @since 8.0.0
         */
        autoStopAfterScan: true,
 
        /**
         * @cfg {Number} scanDialogHeight
         * height for scanner window
         * 
         * @since 8.0.0
         */
        scanViewHeight: 400,
 
        /**
         * @cfg {Number} scanWindowWidth
         * Width for scanner window
         * 
         * @since 8.0.0
         */
        scanViewWidth: 400,
 
        /**
         * @cfg cameraId
         * Id of the camera to be opened by default
         * 
         * @since 8.0.0
        */
        cameraId: undefined
    },
 
    qrScanner: null,
 
    isScanning: false,
 
    scannerWindow: {
        xtype: 'window',
        modal: true,
        width: 400,
        height: 400,
        closable: false,
        header: false,
        border: false,
        bbar: {
            layout: {
                pack: 'center'
            },
            items: [{ text: 'Stop Scanning',
                      handler: function(btn) {
                          var scanWindow = btn.up('window');
 
                          scanWindow.parentScope.stopScanner();
                      }
            }]
        },
        items: [{
            xtype: 'component',
            html: '<div id="qr-scanner-preview" ' +
                        'style="position: relative; width: 100%; height: 100%;"></div>'
        }]
    },
 
    /**
     * @event qrscanned
     * Fired when a QR code is successfully scanned
     * @param {Ext.qrcode.reader.QRCodeReader} this 
     * @param {String} qrData The decoded QR code data
     */
 
    /**
     * @event scanerror
     * Fired when an error occurs during scanning
     * @param {Ext.qrcode.reader.QRCodeReader} this 
     * @param {Error} error The error object
     */
 
    /**
     * @event scannerstarted
     * Fired when the camera scanner is started
     * @param {Ext.qrcode.reader.QRCodeReader} this 
     */
 
    /**
     * @event scannerstopped
     * Fired when the camera scanner is stopped
     * @param {Ext.qrcode.reader.QRCodeReader} this 
     */
 
    /**
     * @private
     * adds scanner file field and scanner button
     */
    addItems: function() {
        var me = this;
 
        me.add([{
            xtype: 'component',
            hidden: true
        }, {
            xtype: 'filefield',
            margin: '0 10 0 0',
            flex: 1,
            accept: me.config.acceptedFileTypes,
            hidden: Ext.isEmpty(me.config.showScannerfield) ? false : !me.getShowScannerfield(),
            listeners: {
                change: 'onFileChange',
                scope: 'owner'
            }
        }, {
            xtype: 'button',
            width: 150,
            text: me.config.scanButtonText,
            hidden: Ext.isEmpty(me.config.showScanButton) ? false : !me.getShowScanButton(),
            handler: me.onScanButtonClick,
            scope: me
        }]);
    },
 
    handleScanSuccess: function(qrData) {
        var me = this;
 
        this.fireEvent('qrscanned', me, qrData);
    },
 
    handleScanError: function(error) {
        var me = this;
 
        me.fireEvent('scanerror', me, error);
        //<debug>
        Ext.log.error('QR Scan error: ' + error);
        //</debug>
    },
 
    startScanner: function(scanButton) {
        var me = this,
            cameraId, i;
 
        if (me.isScanning) {
            return;
        }
 
        if (!window.Html5Qrcode) {
            me.handleScanError('Html5Qrcode library not found');
 
            return;
        }
 
        // Create scanner dialog if not already created
        if (!me.scannerView) {
            me.scannerWindow.parentScope = me;
            me.scannerView = Ext.create(me.scannerWindow);
        }
 
        me.scannerView.setWidth(me.getScanViewWidth());
        me.scannerView.setHeight(me.getScanViewHeight());
        me.scannerView.show();
 
        // eslint-disable-next-line no-undef
        me.qrScanner = new Html5Qrcode('qr-scanner-preview');
 
        // eslint-disable-next-line no-undef
        Html5Qrcode.getCameras()
            .then(function(cameras) {
                if (!cameras || cameras.length === 0) {
                    me.handleScanError('No cameras found');
 
                    return;
                }
 
                // check if any of the cameras id matches with the provided cameraId config
                if (!Ext.isEmpty(me.getCameraId())) {
                    for (= 0; i < cameras.length; i++) {
                        if (cameras[i].id === me.getCameraId()) {
                            cameraId = cameras[i].id;
                        }
                    }
                }
 
                // if no camera matches with provided cameraId switch to default camera
                if (Ext.isEmpty(cameraId)) {
                    Ext.log.warn('No Camera found with the given cameraId ' + me.getCameraId());
                    cameraId = cameras[0].id;
                }
 
                return me.qrScanner.start(
                    cameraId,
                    me.getScannerConfig(),
                    function(qrCodeMessage) {
                        me.onScanSuccess(qrCodeMessage);
                        me.stopScanner();
                    },
                    function(errorMessage) {
                        me.onScanFailure(errorMessage);
                    }
                );
            })
            .then(function() {
                me.isScanning = true;
 
                me.fireEvent('scannerstarted', me);
            })
            .catch(function(error) {
                me.handleScanError(error);
            });
    },
 
    /**
     * @private
     * Event handler fired when the user selects a file
     */
    onFileChange: function(field) {
        var me = this,
            qrCodeFile = me.getFiles(field),
            qrComponent = me.getQrComponent();
 
        if (!qrCodeFile) {
            return;
        }
 
        me.scanQRFile(qrCodeFile, qrComponent);
    },
 
    scanQRFile: function(qrCodeFile, qrComponent) {
        var me = this,
            html5QrCode;
 
        if (window.Html5Qrcode) {
            // eslint-disable-next-line no-undef
            html5QrCode = new Html5Qrcode(qrComponent.getId());
 
            html5QrCode.scanFile(qrCodeFile, true)
                .then(function(decodedText) {
                    me.handleScanSuccess(decodedText);
                })
                .catch(function(error) {
                    me.handleScanError(error);
                });
        }
        else {
            me.handleScanError('Html5Qrcode library not found');
        }
    },
 
    onScanButtonClick: function(button) {
        var me = this;
 
        if (me.isScanning) {
            me.stopScanner();
        }
        else {
            me.startScanner(button);
        }
 
    },
 
    getQrComponent: function() {
        return this.down('component');
    },
 
    stopScanner: function() {
        var me = this;
 
        if (!me.qrScanner) {
            return;
        }
 
        try {
            me.qrScanner.stop()
            .then(function() {
                me.closeScannerWindow();
                me.fireEvent('scannerstopped', me);
            })
            .catch(function(error) {
                me.closeScannerWindow();
                //<debug>
                Ext.log.error('Failed to stop scanner:', error);
                //</debug>
            });
        }
        catch (e) {
            //<debug>
            Ext.log.error('Failed to stop scanner:', e);
            //</debug>
        }
    },
 
    onScanSuccess: function(qrCodeMessage) {
        var me = this;
 
        me.handleScanSuccess(qrCodeMessage);
 
        if (me.getAutoStopAfterScan()) {
            me.stopScanner();
        }
    },
 
    closeScannerWindow: function() {
        var me = this;
 
        me.qrScanner.clear();
        me.isScanning = false;
 
        if (me.scannerView) {
            me.scannerView.close();
            me.scannerView = null;
        }
    },
 
    onDestroy: function() {
        var me = this;
 
        if (me.isScanning) {
            me.stopScanner();
        }
 
        me.callParent();
    },
 
    onScanFailure: Ext.emptyFn
});