<script lang="ts">
    /**
     * src/lib/element_qr_scanner_v3.svelte
     * QR Scanner v3 — Svelte 5 runes, auto-starts, no manual permission step.
     *
     * html5-qrcode's .start() handles camera permission internally.
     * A unique viewfinder ID is generated per instance so multiple scanners
     * can coexist on the same page without collision.
     *
     * Props:
     *   start_qr_scanner  (bindable) — true = scan, false = stop
     *   on_qr_scan_result — callback fired with { detail: { result, entry_method } }
     *   qr_fps            — scan frames per second (default 10)
     *   qr_facing_mode    — 'environment' (rear) or 'user' (front)
     */
    import { onDestroy, untrack } from 'svelte';
    import { Html5Qrcode, Html5QrcodeSupportedFormats } from 'html5-qrcode';

    interface Props {
        start_qr_scanner?: boolean;
        on_qr_scan_result?: (event: { detail: { result: string; entry_method: string } }) => void;
        qr_fps?: number;
        qr_facing_mode?: string;
    }

    let {
        start_qr_scanner = $bindable(true),
        on_qr_scan_result,
        qr_fps = 10,
        qr_facing_mode = 'environment'
    }: Props = $props();

    // Unique DOM ID per instance — prevents conflicts when multiple scanners mount
    const viewfinder_id = `qr_vf_${Math.random().toString(36).substring(2, 9)}`;

    let scanner: Html5Qrcode | null = null;
    let status = $state<'idle' | 'starting' | 'scanning' | 'error'>('idle');
    let error_msg = $state('');

    // React to start_qr_scanner prop changes from the parent
    $effect(() => {
        const should_scan = start_qr_scanner;

        untrack(() => {
            if (should_scan && (status === 'idle' || status === 'error')) {
                start_scanning();
            } else if (!should_scan && status === 'scanning') {
                stop_scanning();
            }
        });
    });

    onDestroy(() => {
        stop_scanning();
    });

    async function start_scanning() {
        if (status === 'starting' || status === 'scanning') return;
        status = 'starting';
        error_msg = '';

        try {
            scanner = new Html5Qrcode(viewfinder_id, {
                formatsToSupport: [Html5QrcodeSupportedFormats.QR_CODE],
                verbose: false
            });

            await scanner.start(
                { facingMode: qr_facing_mode },
                {
                    fps: qr_fps,
                    // Use a percentage of the viewfinder so it scales on any screen size
                    qrbox: (w: number, h: number) => {
                        const side = Math.floor(Math.min(w, h) * 0.82);
                        return { width: side, height: side };
                    }
                },
                on_scan_success,
                on_scan_error
            );

            status = 'scanning';
        } catch (e: any) {
            status = 'error';
            if (e?.name === 'NotAllowedError') {
                error_msg = 'Camera access denied. Please allow camera in your browser settings and try again.';
            } else {
                error_msg = 'Could not start camera. Please try again.';
            }
            console.warn('[QR v3] Scanner start failed:', e);
        }
    }

    async function stop_scanning() {
        if (!scanner) return;
        const s = scanner;
        scanner = null;
        try {
            await s.stop();
            await s.clear();
        } catch {
            // Ignore cleanup errors — component may be unmounting
        }
        status = 'idle';
    }

    function on_scan_success(decoded_text: string) {
        // Stop scanning before notifying parent so the camera shuts down cleanly
        stop_scanning().then(() => {
            start_qr_scanner = false;
        });

        if (on_qr_scan_result) {
            on_qr_scan_result({ detail: { result: decoded_text, entry_method: 'QR' } });
        }
    }

    function on_scan_error(_msg: string) {
        // Called on every frame that doesn't contain a QR code — expected, not an error
    }
</script>

<!-- Viewfinder fills whatever container the parent provides -->
<div class="qr-scanner-v3 w-full h-full flex flex-col items-center justify-center">
    <div id={viewfinder_id} class="w-full h-full"></div>

    {#if status === 'starting'}
        <div class="absolute inset-0 flex items-center justify-center bg-surface-900/40 rounded-xl">
            <p class="text-sm font-semibold opacity-70 animate-pulse">Starting camera...</p>
        </div>
    {:else if status === 'error'}
        <div class="absolute inset-0 flex flex-col items-center justify-center gap-4 bg-surface-900/80 rounded-xl p-6 text-center">
            <p class="text-sm text-error-400 font-semibold leading-snug">{error_msg}</p>
            <button
                type="button"
                class="btn btn-sm variant-filled-primary"
                onclick={start_scanning}
            >
                Try Again
            </button>
        </div>
    {/if}
</div>
