<script lang="ts">
    import { run, preventDefault } from 'svelte/legacy';

    // *** Import Svelte core
    import { createEventDispatcher, onDestroy, onMount } from 'svelte';
    // import 'html5-qrcode';
    import {
        Html5Qrcode,
        Html5QrcodeSupportedFormats
    } from 'html5-qrcode';

    // *** Import Aether core variables and functions
    import { api } from '$lib/api/api';
    import { ae_api } from '$lib/stores/ae_stores';

    // *** Import Aether core components
    // import Element_input from './element_input.svelte';
    // import ae from '/element_input.svelte';
    // import Input_element from '/element_input.svelte';

    // *** Import Aether module variables and functions

    // *** Import Aether module components

    interface Props {
        // *** Export/Exposed variables and functions for component
        start_qr_scanner?: boolean;
        show_pause_btn?: boolean; // pause and resume buttons
        show_qr_manual_text_entry_option?: boolean;
        show_qr_manual_badge_id_entry_option?: boolean;
        show_qr_scan_result?: boolean;
        qr_fps?: number;
        qr_viewfinder_width?: number; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.
        qr_facing_mode?: string; // environment, user, { exact: 'environment'}, { exact: 'user'}
    }

    let {
        start_qr_scanner = $bindable(true),
        show_pause_btn = false,
        show_qr_manual_text_entry_option = false,
        show_qr_manual_badge_id_entry_option = false,
        show_qr_scan_result = true,
        qr_fps = 10,
        qr_viewfinder_width = 275,
        qr_facing_mode = 'environment'
    }: Props = $props();

    const dispatch = createEventDispatcher();

    // *** Set initial variables
    let scanning_status: string = $state('not_started');
    let qr_scan_result: null | string = $state(null);
    let qr_found_text: null | string = null;
    let qr_entered_text: null | string = $state(null);
    let qr_entered_badge_id: null | string = $state(null);
    let show_qr_manual_entry: null | boolean = $state(null);
    let disable_submit_badge_id_btn: boolean = $state(true);

    let search_query_str = $state('');

    function handle_oninput_search_query_str(e: Event) {
        search_query_str = (e.target as HTMLInputElement).value;
    }

    let user_media_status = 'not_requested';

    let debug_comment: string = 'Debugging QR Scanner';
    let debug_info: any;

    let html5_qr_code: any | null | string = null;

    // let qr_scan_cfg = { fps: 10, qrbox: 400 }; // default was 250 and using 300 when 600px
    let qr_scan_cfg = { fps: qr_fps, qrbox: qr_viewfinder_width }; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.

    // const html5QrCode = new Html5Qrcode(
    //     'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
    // );

    onMount(() => {
        console.log('** Element Mounted: ** QR Scanner');

        // html5_qr_code = new Html5Qrcode(
        //     'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
        // );

        // navigator.mediaDevices.getUserMedia({video: true})
        // .then(get_user_media_success, get_user_media_error);
        // console.log('** Element Mounted: ** QR Scanner - getUserMedia in setTimeout');
    });

    onDestroy(async () => {
        console.log('** Element Destroyed: ** QR Scanner');

        qr_scan_result = null;
        qr_found_text = null;

        await handle_stop_qr_scanning();
    });

    var get_user_media_success = function (error: any) {
        console.log('Camera access allowed');
        user_media_status = 'allowed';

        debug_comment = 'Camera Access Allowed';
        debug_info = JSON.stringify(error);

        if (html5_qr_code) {
            console.log('html5_qr_code object found. Clearing and creating new Html5Qrcode...');
            debug_info = 'html5_qr_code object found. Clearing and creating new Html5Qrcode...';
            html5_qr_code.clear();
            // document.getElementById('qr_scanner_viewfinder').classList.remove('d_none');
        } else {
            console.log('html5_qr_code not found. Creating new Html5Qrcode...');
            debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...';

            html5_qr_code = new Html5Qrcode('qr_scanner_viewfinder', {
                formatsToSupport: [Html5QrcodeSupportedFormats.QR_CODE],
                verbose: false
            });
        }

        // html5_qr_code = new Html5Qrcode(
        //     'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
        // );

        debug_info = 'new Html5Qrcode for element id=qr_scanner_viewfinder';

        if (start_qr_scanner && 1 == 2) {
            console.log('Ready to start QR scanning! (after x500ms)');
            debug_comment = 'Starting QR after 500ms...';
            debug_info = 'Ready to start QR scanning! (after 2500ms)';
            setTimeout(() => {
                console.log('Inside QR scanning timeout after x500ms...');
                handle_start_qr_scanning_trust();
            }, 2500);
            console.log('Started QR scanning after x500ms...');
        }

        // let subject = 'Camera Access Allowed';
        // let message = error;
        // send_init_confirm_email(subject, message);

        console.log('Dispatching qr_camera');
        debug_info = 'Dispatching qr_camera';

        dispatch('qr_camera', {
            status: 'allowed'
        });
    };

    var get_user_media_error = function (error: any) {
        if (error.name == 'NotAllowedError') {
            console.log('Camera access not allowed!');
            user_media_status = 'denied';

            debug_comment = 'Camera Access Denied';
            debug_info = JSON.stringify(error);
            // alert('Error trying to start camera');
            // alert(error);

            let subject = 'Camera Access Denied';
            let message = error;
            send_init_confirm_email(subject, message);

            // dispatch('qr_camera', {
            //     status: 'denied',
            // });
        }
    };

    // $: if (start_qr_scanner && user_media_status == 'allowed' && (scanning_status == 'not_started' || scanning_status == 'paused')) {
    //     console.log('START QR SCANNING');
    //     handle_start_qr_scanning();
    // } else {
    //     // console.log('STOP QR SCANNING');
    //     // handle_stop_qr_scanning();
    // }

    // $: if (mounted && start_qr_scanner) {
    //     console.log('START QR SCANNING');
    //     handle_start_qr_scanning();
    // } else if (mounted && !start_qr_scanner) {
    //     console.log('STOP QR SCANNING');
    //     handle_stop_qr_scanning();
    // }

    async function handle_start_qr_scanning_trust() {
        console.log('*** handle_start_qr_scanning_trust() ***');

        qr_scan_result = null;
        qr_found_text = null;

        debug_comment = 'Starting trusting QR scanning...';

        debug_info = 'Just start!';
        await html5_qr_code.clear();
        html5_qr_code
            .start(
                { facingMode: qr_facing_mode },
                qr_scan_cfg,
                handle_qr_scan_success,
                handle_qr_scan_error
            )
            .then((ignore: any) => {
                console.log('Scanning has started');
                scanning_status = 'scanning';

                debug_info = 'Scanning has started';

                // let subject = 'QR Scanning Started';
                // let message = ignore;
                // send_init_confirm_email(subject, message);

                return true;
            })
            .catch((err: any) => {
                console.log('There was an error while trying to start the QR scanner');
                scanning_status = 'start_error';

                debug_info = 'Error starting scanner: ' + JSON.stringify(err);

                // let subject = 'QR Scanning Start Error';
                // let message = err;
                // send_init_confirm_email(subject, message);

                // Error getting userMedia, error = NotReadableError: Could not start video source

                return false;
            });

        return true;
    }

    async function handle_stop_qr_scanning() {
        start_qr_scanner = false;

        if (!html5_qr_code) {
            console.log('html5_qr_code object found. Nothing to stop?');
            scanning_status = 'not_started';
            return false;
        }

        await html5_qr_code.stop();
        scanning_status = 'not_started';

        await html5_qr_code.clear();
        return true;
    }

    // Callback function for QrcodeSuccessCallback (decodedText: string, result: Html5QrcodeResult)
    function handle_qr_scan_success(decoded_text: string, decoded_result: any) {
        console.log(
            `*** handle_qr_scan_success() *** QR scanned = ${decoded_text}`,
            decoded_result
        );

        qr_scan_result = decoded_text; // NOTE: decoded_result is not currently used by html5-qrcode
        qr_found_text = decoded_text;

        dispatch('qr_scan_result', {
            result: qr_scan_result, // This text will need to be parsed to get more info.
            text: qr_found_text, // This text will need to be parsed to get more info.
            entry_method: 'QR'
        });

        // handle_pause_qr_scanning();
        handle_stop_qr_scanning();
    }

    // Callback function for QrcodeErrorCallback (errorMessage: string, error: Html5QrcodeError)
    // NOTE: Most of the time this is normal and not an actual error. It just did not find something to scan.
    function handle_qr_scan_error(qr_error_message: string, qr_code_error: any) {
        // console.log('*** handle_qr_scan_error() ***');

        if (qr_code_error.type) {
            console.log(`Error scanning code = ${qr_error_message}`, qr_code_error);
            return;
        }
    }

    run(() => {
        if (
            qr_entered_badge_id &&
            qr_entered_badge_id.length >= 11 &&
            qr_entered_badge_id &&
            qr_entered_badge_id.length <= 14
        ) {
            disable_submit_badge_id_btn = false;
        } else {
            disable_submit_badge_id_btn = true;
        }
    });

    function handle_qr_manual_entry() {
        console.log('*** handle_qr_manual_entry() ***');

        if (qr_entered_text) {
            console.log(`QR entered text = ${qr_entered_text}`);
        } else if (qr_entered_badge_id) {
            console.log(`QR entered badge ID = ${qr_entered_badge_id}`);
            qr_entered_text = `OBJ:ot:event_badge,oi:${qr_entered_badge_id}`;
            console.log(`Parse to proper QR badge ID = ${qr_entered_text}`);
        }

        // html5_qr_code.stop().then((ignore) => {
        //     console.log('Scanning has stopped');
        //     document.getElementById('qr_scanner_viewfinder').classList.add('d_none');
        // }).catch((err) => {
        //     console.log('There was an error while trying to stop the scanning');
        // });

        qr_scan_result = qr_entered_text;

        dispatch('qr_scan_result', {
            result: qr_scan_result,
            entry_method: 'manual'
        });

        qr_scan_result = null;
        qr_entered_text = null;
    }

    function send_init_confirm_email(subject: string, message: any) {
        console.log(`*** send_init_confirm_email() *** ${subject}`);

        let to_email = 'scott.idem+skdev@oneskyit.com';

        // let origin_url = encodeURI(`${data.url.origin}`);

        let full_subject = `${subject} Aether QR Scanner Debugging`;

        let body_html = `
    <div>Scott,
    <p>This is an automatic debug email from the Aether QR scanner.</p>
    </div>

    <br>

    <div>
    Message:<br>
    <pre>
    ${JSON.stringify(message)}
    </pre>
    </div>
    `;

        api.send_email({
            api_cfg: $ae_api,
            from_email: 'noreply+ae_qr_debug@oneskyit.com',
            from_name: 'AE QR Debug',
            to_email: to_email,
            subject: full_subject,
            body_html: body_html
        });
    }
</script>

<section
    class="ae_element qr_scanner border-2 border-slate-500/10 space-y-2 flex flex-col gap-1 justify-center items-center min-w-full max-w-full"
    class:not_started={scanning_status == 'not_started'}
    class:paused={scanning_status == 'paused'}
    class:scanning={scanning_status == 'scanning'}
>
    <!-- <header>
        <h2>QR Scanner</h2>
    </header> -->

    <!-- <fieldset class=""> -->
    <!-- <legend class="d_none">QR Scanner:</legend> -->

    <div class="ae_container qr_scanning_container">
        <div class="ae_options flex flex-row justify-center items-center gap-1 m-1">
            <button
                type="button"
                onclick={() => {
                    navigator.mediaDevices
                        .getUserMedia({ video: true })
                        .then(get_user_media_success, get_user_media_error);
                }}
                class="ae_btn__allow_camera btn btn-sm preset-tonal-primary"
            >
                <span class="fas fa-camera mx-1"></span>
                Allow Camera Access
            </button>

            <button
                type="button"
                onclick={() => {
                    handle_start_qr_scanning_trust();
                    // Select back camera or fail with `OverconstrainedError`.
                    // html5_qr_code.start({ facingMode: { exact: "environment"} }, config, qrCodeSuccessCallback);
                }}
                class="ae_btn__start btn btn-sm preset-tonal-primary"
            >
                <span class="fas fa-qrcode mx-1"></span>
                Start Scanning
            </button>

            <!-- <button
                on:click={ () => {
                    html5_qr_code.start({ facingMode: { exact: "environment"} }, config, qrCodeSuccessCallback);
                }}
                class="ae_btn__resume btn btn-sm variant-soft-primary">
                <span class="fas fa-play"></span>
                Resume
            </button> -->

            {#if scanning_status == 'scanning'}
                <button
                    onclick={handle_stop_qr_scanning}
                    class="ae_btn__stop btn btn-sm preset-tonal-secondary"
                >
                    <span class="fas fa-crosshairs fa-spin opacity-50 m-1"></span>
                    <!-- <span class="fas fa-stop-circle m-1"></span> -->
                    Stop
                </button>
            {/if}
        </div>

        <div
            id="qr_scanner_viewfinder"
            class="qr_scanner_viewfinder grow flex flex-col justify-center items-center"
            style=""
        ></div>
        <!-- width: 600px -->
    </div>

    {#if show_qr_manual_text_entry_option}
        <div class="ae_container qr_manual_entry text_entry">
            {#if show_qr_manual_entry}
                <label for="entered_text" class="">Enter text</label>
                <input
                    type="text"
                    name="entered_text"
                    id="entered_text"
                    bind:value={qr_entered_text}
                />
                <button onclick={handle_qr_manual_entry} class="btn btn-md preset-tonal-warning"
                    ><span class="fas fa-paper-plane"></span> Submit Text</button
                >

                <div class="search_by_text">
                    <input
                        type="text"
                        placeholder="Name or Email"
                        aria-label="Name or Email"
                        value={search_query_str}
                        oninput={handle_oninput_search_query_str}
                    />
                </div>
            {:else}
                <button
                    onclick={() => {
                        handle_stop_qr_scanning();
                        show_qr_manual_entry = true;
                    }}
                    class="btn btn-md preset-tonal-warning m-1"
                >
                    <span class="fas fa-keyboard mx-1"></span> Enter Text
                </button>
            {/if}
        </div>
    {/if}

    {#if show_qr_manual_badge_id_entry_option}
        <div class="ae_container qr_manual_entry badge_id_entry">
            {#if show_qr_manual_entry}
                <form onsubmit={preventDefault(() => handle_qr_manual_entry)} class="flex">
                    <!-- <label for="entered_badge_id" class="">Enter badge ID</label>
                    <input type="text" name="entered_badge_id" id="entered_badge_id" bind:value="{qr_entered_badge_id}"> -->

                    <input
                        bind:value={qr_entered_badge_id}
                        type="text"
                        name="entered_badge_id"
                        id="entered_badge_id"
                        required
                        placeholder="Enter Badge ID"
                        class="input max-w-52"
                    />

                    <button
                        type="submit"
                        onclick={handle_qr_manual_entry}
                        disabled={disable_submit_badge_id_btn}
                        class="btn btn-md preset-tonal-primary border border-primary-500 m-1"
                        class:btn_default={disable_submit_badge_id_btn}
                        class:btn_primary={!disable_submit_badge_id_btn}
                    >
                        <span class="fas fa-paper-plane mx-1"></span> Submit Badge ID
                    </button>
                </form>
            {:else}
                <button
                    onclick={() => {
                        handle_stop_qr_scanning();
                        show_qr_manual_entry = true;
                    }}
                    class="btn btn-md preset-tonal-secondary m-1"
                >
                    <span class="fas fa-keyboard mx-1"></span> Enter Badge ID
                </button>
            {/if}
        </div>
    {/if}

    {#if show_qr_scan_result && qr_scan_result}
        <div class="ae_container qr_scan_result">
            <span class="label">Raw Result:</span>
            <span id="qr_scan_result_value" class="value">{qr_scan_result}</span>
        </div>
    {/if}

    <!-- {debug_comment ?? 'Debugging QR Scanner'}
        {#if debug_info}
        <div class="ae_container debug_info">
            <span class="label">Debug Info:</span>
            <span class="value">{debug_info}</span>
        </div>
        {/if} -->
    <!-- </fieldset> -->

    <p>
        v2 - Try pressing the "Allow Camera Access" button and then the "Start Scanning" button if
        it does not start on its own. This fix is not perfect. A permanent solution is actively
        being worked on in the development version.
    </p>
</section>

<style>
    .not_started {
        background-color: hsla(0, 100%, 75%, 0.3);
        border-color: hsla(0, 100%, 75%, 0.6);
    }
    .paused {
        background-color: hsla(60, 100%, 75%, 0.3);
        border-color: hsla(60, 100%, 75%, 0.6);
    }
    .scanning {
        background-color: hsla(120, 100%, 75%, 0.3);
        border-color: hsla(120, 100%, 75%, 0.6);
    }

    .qr_scanner {
        /* outline: solid thin pink; */

        max-width: 100vw;

        /* overflow-x: scroll; */

        display: flex;
        flex-direction: column;
        /* flex-wrap: wrap; */

        justify-content: flex-start;
        align-items: center; /* center */
        align-content: stretch;
    }

    .qr_scanner .qr_scanner_viewfinder {
        /* outline: dashed medium blue; */
        min-width: 400px;

        width: 100%;
        /* max-width: 100%; */
        max-width: 500px;
        /* max-width: 100vw; */
        /* outline: solid thin red; */

        contain: contain;
        overflow-x: scroll;
    }

    @media (max-width: 767px) {
        .qr_scanner .qr_scanner_viewfinder {
            /* outline: dashed medium red; */
            min-width: 80vw;
            /* width: 100%; */
            /* max-width: 100%; */
            /* max-width: 450px; */
            max-width: 100vw;

            margin: 0;
            padding: 0;
        }
    }
</style>
