<?php


class barcodeReader
{
    public $extra_js_function_to_call;

    function add_js_function_to_call($function_name)
    {
        $this->extra_js_function_to_call = $function_name;
    }

    function add_button($barcodeInputId, $index = 0, $style = "")
    {
        $barcodeInputId = htmlspecialchars($barcodeInputId, ENT_QUOTES, 'UTF-8');
        $uniqueId = 'barcode-scan-area-' . $index;
        $startButtonId = 'barcode-start-button-' . $index;
        $videoAreaId = 'barcode-video-area-' . $index;
        $videoStreamId = 'barcode-video-stream-' . $index;
        $videoCanvasId = 'barcode-video-canvas-' . $index;
        ?>

        <div id="<?php echo $uniqueId; ?>">
            <button style="<?php echo $style; ?>" id="<?php echo $startButtonId; ?>" class="submit_btn"
                onclick="startBarcodeScanner('<?php echo $barcodeInputId; ?>',<?php echo $index; ?>)"
                style='font-size: 2em;margin: 2vw;width: 80vw;height: 20vh;'>SCAN
                BARCODE</button>
            <div id="<?php echo $videoAreaId; ?>"
                style="position: relative; overflow: hidden; display: none; width: 100%; max-width: 300px; height: 200px; margin: auto; border: 2px solid #333; border-radius: 8px;">
                <video id="<?php echo $videoStreamId; ?>" playsinline muted autoplay
                    style="width: 100%; height: 100%; object-fit: cover; background: #000;"></video>
                <canvas id="<?php echo $videoCanvasId; ?>"
                    style="display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
            </div>
        </div>

        <?php
    }

    function __destruct()
    {
        ?>

        <script src="https://cdnjs.cloudflare.com/ajax/libs/quagga/0.12.1/quagga.min.js"></script>
        <script>
            function startBarcodeScanner(barcodeInputId, index) {
                event.preventDefault();

                const videoArea = document.getElementById('barcode-video-area-' + index);
                const videoStream = document.getElementById('barcode-video-stream-' + index);
                const videoCanvas = document.getElementById('barcode-video-canvas-' + index);
                const startButton = document.getElementById('barcode-start-button-' + index);
                targetInputId = barcodeInputId;

                videoArea.style.display = 'block';

                function stopCamera() {
                    Quagga.stop();
                    videoStream.pause();
                    if (videoStream.srcObject) {
                        videoStream.srcObject.getVideoTracks().forEach(track => {
                            track.stop();
                            track.enabled = false;
                        });
                    }
                    videoArea.style.display = 'none';
                    if (typeof executeOnce === 'undefined') {
                        console.log("CALLED: <?php echo $this->extra_js_function_to_call . ";"; ?>");
                        <?php
                        if (strlen($this->extra_js_function_to_call) > 1) {
                            echo $this->extra_js_function_to_call . ";";
                        }
                        ?>
                        var executeOnce = true;
                    }
                }

                navigator.mediaDevices.getUserMedia({
                    audio: false,
                    video: {
                        facingMode: { ideal: 'environment' },
                        width: { ideal: 640 },
                        height: { ideal: 480 },
                        zoom: 3 // try 3x zoom
                    }
                }).then(function (stream) {
                    videoStream.srcObject = stream;
                    videoStream.setAttribute('playsinline', true);
                    videoStream.muted = true;
                    videoStream.autoplay = true;
                    videoStream.play();

                    const track = stream.getVideoTracks()[0];
                    const capabilities = track.getCapabilities();

                    // Apply 3x zoom if supported
                    if (capabilities.zoom) {
                        const maxZoom = capabilities.zoom.max || 3;
                        const zoomToApply = Math.min(3, maxZoom);
                        track.applyConstraints({ advanced: [{ zoom: zoomToApply }] }).catch(e => {
                            console.warn("Zoom apply failed:", e);
                        });
                    }

                    // Try autofocus continuous mode if supported
                    if (capabilities.focusMode && capabilities.focusMode.includes('continuous')) {
                        track.applyConstraints({ advanced: [{ focusMode: "continuous" }] }).catch(() => { });
                    }

                    Quagga.init({
                        inputStream: {
                            name: "Live",
                            type: "LiveStream",
                            target: videoStream,
                            constraints: {
                                facingMode: "environment",
                                width: { min: 300 },
                                height: { min: 300 },
                                aspectRatio: { min: 1 }
                            },
                            area: {
                                top: "25%",    // center horizontal band
                                right: "10%",
                                left: "10%",
                                bottom: "25%"
                            }
                        },
                        decoder: {
                            readers: [
                                "code_128_reader",
                                "ean_reader",
                                "ean_8_reader",
                                "upc_reader"
                            ],
                            multiple: false
                        },
                        locator: {
                            patchSize: "large",
                            halfSample: false
                        },
                        locate: true,
                        numOfWorkers: 4,
                        frequency: 20
                    }, function (err) {
                        if (err) {
                            console.error("Error initializing Quagga: ", err);
                            return;
                        }
                        Quagga.start();
                    });

                    let lastBarcode = null;
                    let matchCount = 0;

                    Quagga.onDetected(function (result) {
                        const codes = result.codeResult.decodedCodes;
                        const errors = codes.filter(c => typeof c.error !== 'undefined').map(c => c.error);
                        const avgError = errors.length ? errors.reduce((a, b) => a + b, 0) / errors.length : 0;

                        if (avgError < 0.25) { // Only accept low-error scans
                            const barcode = result.codeResult.code;

                            if (barcode === lastBarcode) {
                                matchCount++;
                            } else {
                                lastBarcode = barcode;
                                matchCount = 1;
                            }

                            if (matchCount >= 2) { // 2 matches is enough now
                                console.log("Inserted into " + targetInputId);
                                document.getElementById(targetInputId).value = barcode;
                                stopCamera();
                            }
                        }
                    });

                    Quagga.onProcessed(function (result) {
                        if (result && result.codeResult) {
                            console.log("Processing result: ", result.codeResult.code);
                        }
                    });

                }).catch(function (error) {
                    console.error("Error accessing camera: ", error);
                    alert("Unable to access camera. Please check permissions.");
                    videoArea.style.display = 'none';
                });
            }
        </script>

        <?php
    }
}