<script lang="ts">
// *** Import Svelte specific
import { onDestroy, onMount, tick } from 'svelte';
import { afterNavigate } from '$app/navigation';

// *** Import other supporting libraries
// import { liveQuery } from "dexie";
import {
    Loader,
    Lock,
    LockOpen,
    ShieldEllipsis,
    ShieldMinus,
    ShieldPlus,
    ShieldUser,
    User,
    UserCheck,
    UserRound,
    Wand2
} from '@lucide/svelte';
// *** Import Aether specific variables and functions
import { ae_util } from '$lib/ae_utils/ae_utils';
import {
    ae_loc,
    ae_sess,
    ae_api,
    slct,
    slct_trigger
} from '$lib/stores/ae_stores';
// import { core_func } from '$lib/ae_core/ae_core_functions';
// import { db_events } from "$lib/db_events";

// export let hidden: boolean = false;

// *** Setup Svelte properties
interface Props {
    log_lvl?: number;
    hide?: null | boolean;
    focus_input: boolean;
    expand?: boolean;
    show_passcode_input: boolean;
    trigger_clear_access: null | boolean;
}

let {
    log_lvl = $bindable(0),
    hide = $bindable(false),
    focus_input = $bindable(false),
    expand = $bindable(false),
    show_passcode_input = $bindable(false),
    trigger_clear_access = $bindable(null)
}: Props = $props();

let entered_passcode: null | string = $state(null);
let checked_passcode: null | string = $state(null);
// let password_checked: boolean = $state(false);
// let entered_passcode: null|string = '';
// let show_passcode_input: boolean = $state(false);
// let show_passcode_input: boolean = false;

// let trigger: null|string|boolean = null;
let trigger: null | string | boolean = $state(null);

// ── Secure passcode auth (API-verified) ──────────────────────────────────────
// Set USE_API_PASSCODE_AUTH = true to activate the new API-verified path.
// When false, the original local comparison runs unchanged.
// When true, the component POSTs to /api/authenticate_passcode and stores the
// returned JWT. On network or unexpected API errors it falls back to the local
// method automatically so IDAA staff and other users are never left locked out.
const USE_API_PASSCODE_AUTH = true;

let auth_pending: boolean = $state(false);
let auth_error: string | null = $state(null);

// const dispatch = createEventDispatcher();

// WARNING: There is a bug (I think) around here related to the entered_passcode not being cleared. There seems to be something different about how Svelte handles state in this component compared to the others. This might be related to the `$effect` or `$derived` usage. Maybe there are conflicting things trying to update the $ae_loc store at the same time.
onMount(() => {
    // log_lvl = 2;
    if (log_lvl > 1) {
        console.log('** Element Mounted: ** Element Access Type');
    }
    entered_passcode = '';
    trigger = null;

    // /** @type {HTMLElement | null} */
    // const to_focus = document.getElementById('access_passcode_input');
    // to_focus?.focus();
});

onDestroy(() => {
    if (log_lvl > 1) {
        console.log('** Element Destroyed: ** Element Access Type');
    }

    // Clean up any references or listeners if needed
    entered_passcode = null; // Clear the entered passcode
    show_passcode_input = false;

    // Reset trigger
    trigger = null;
});

// afterNavigate(() => {
// 	/** @type {HTMLElement | null} */
// 	const to_focus = document.getElementById('access_passcode_input');
// 	to_focus?.focus();
// });

$effect(() => {
    if (!USE_API_PASSCODE_AUTH) {
        // Local path: synchronous comparison, safe to auto-fire on each qualifying keystroke.
        if (entered_passcode && entered_passcode.length >= 5 && entered_passcode != checked_passcode) {
            checked_passcode = entered_passcode;
            if (log_lvl) console.log(`entered_passcode=${entered_passcode}`);
            handle_check_passcode_local();
        }
        return;
    }
    // API path: debounce — fire 600ms after the user stops typing.
    // The $effect cleanup (returned fn) cancels the previous timer on each new keystroke.
    // Enter key bypasses the debounce via the onkeydown handler on the input.
    if (!entered_passcode || entered_passcode.length < 5) return;
    const timer = setTimeout(() => handle_check_access_type_passcode(), 600);
    return () => clearTimeout(timer);
});

$effect(() => {
    if (trigger && $ae_loc.access_type) {
        trigger = false;
        if (log_lvl) {
            console.log(`$ae_loc.access_type=${$ae_loc.access_type}`);
        }

        let access_checks_results = ae_util.process_permission_checks(
            $ae_loc.access_type
        );

        $ae_loc = { ...$ae_loc, ...access_checks_results };
        $ae_loc = $ae_loc;
        $ae_loc.sys_menu.expand = false;
    } else if (trigger) {
        trigger = false;
        if (log_lvl) {
            console.log(`$ae_loc.access_type=not set`);
        }

        // Send an empty string to reset the permissions. This is the same as sending 'anonymous'.
        let access_checks_results = ae_util.process_permission_checks('');

        $ae_loc = { ...$ae_loc, ...access_checks_results };
        $ae_loc = $ae_loc;
    }
});

// This does not seem to work. I feel like it should though...?
$effect(() => {
    if (!hide && focus_input) {
        focus_input = false;
        // log_lvl = 2;
        // await tick();
        // document.getElementById('access_passcode_input')?.focus();
        if (log_lvl > 1) {
            console.log('Effect: Setting focus on the passcode input field');
        }
        /** @type {HTMLElement | null} */
        const to_focus = document.getElementById('access_passcode_input');
        to_focus?.focus();
    }
});

$effect(() => {
    if (trigger_clear_access) {
        trigger_clear_access = false;
        if (log_lvl) {
            console.log(`trigger_clear_access=${trigger_clear_access}`);
        }
        handle_clear_access();
    }
});

// Clear the API auth error as soon as the user changes their input after a rejection.
// Reset the local-path guard (checked_passcode) when input is fully cleared so the
// user can retype the same code after clearing the field.
$effect(() => {
    if (entered_passcode) {
        auth_error = null;
    } else {
        checked_passcode = null;
    }
});

// Dispatcher — called from the Enter-key handler on the input (API path) or
// from the $effect auto-check (local path). Guards against concurrent API calls.
function handle_check_access_type_passcode() {
    if (USE_API_PASSCODE_AUTH) {
        if (auth_pending || !entered_passcode || entered_passcode.length < 5) return;
        handle_check_passcode_api(); // async, intentionally not awaited
    } else {
        handle_check_passcode_local();
    }
}

// ── New: API-verified passcode auth ──────────────────────────────────────────
// POSTs to /api/authenticate_passcode. On success stores the returned JWT so
// the session has a TTL and passcodes never need to be cached client-side.
// Falls back to the local method on any network or unexpected API error to
// ensure IDAA staff and onsite users are never locked out.
async function handle_check_passcode_api() {
    const site_id = $ae_loc?.site_id;
    if (!site_id || site_id === 'ghost' || !entered_passcode) {
        // No valid site context yet — fall back to local comparison.
        handle_check_passcode_local();
        return;
    }

    auth_pending = true;
    auth_error = null;

    try {
        const api_key =
            ($ae_api?.headers?.['x-aether-api-key'] as string) ??
            ($ae_api?.api_secret_key as string) ??
            '';

        const resp = await fetch(`${$ae_api.base_url}/v3/action/auth/authenticate_passcode`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'x-aether-api-key': api_key
            },
            body: JSON.stringify({ site_id, passcode: entered_passcode })
        });

        const json = await resp.json();

        if (resp.ok && json?.data?.role) {
            const role = json.data.role as string;
            const jwt = json.data.jwt as string | null;

            $ae_loc.access_type = role as typeof $ae_loc.access_type;
            if (jwt) $ae_loc.jwt = jwt;
            window.localStorage.setItem('access_type', role);

            entered_passcode = '';
            show_passcode_input = false;
            trigger = 'process_permission_check';

            $ae_loc.app_cfg.show_element__menu = false;
            $ae_loc.app_cfg.show_element__menu_btn = true;

            if (!$ae_loc.iframe && $ae_loc.authenticated_access) {
                $ae_loc.app_cfg.show_element__access_type = true;
                $ae_loc.app_cfg.show_element__cfg = true;
            } else if ($ae_loc.iframe && $ae_loc.trusted_access) {
                $ae_loc.app_cfg.show_element__access_type = true;
                $ae_loc.app_cfg.show_element__cfg = true;
            } else {
                $ae_loc.app_cfg.show_element__access_type = true;
                $ae_loc.app_cfg.show_element__cfg = false;
            }
        } else if (resp.status === 401) {
            auth_error = 'Incorrect passcode.';
        } else if (resp.status === 404) {
            // Site not found — configuration problem; fall back silently.
            console.warn('passcode auth: site not found, falling back to local');
            handle_check_passcode_local();
        } else {
            // Unexpected response — fall back so the user isn't locked out.
            console.warn('passcode auth: unexpected status', resp.status, '— falling back to local');
            handle_check_passcode_local();
        }
    } catch (_err) {
        // Network/parse error — fall back to local comparison.
        console.warn('passcode auth: network error, falling back to local');
        handle_check_passcode_local();
    } finally {
        auth_pending = false;
    }
}

// ── Legacy: local passcode comparison (original method) ──────────────────────
// Kept intact so USE_API_PASSCODE_AUTH=false preserves the existing behaviour
// exactly, and so the API path can fall back here on errors.
function handle_check_passcode_local() {
    if (log_lvl > 1) {
        console.log(
            `*** handle_check_passcode_local() *** passcode list:`,
            $ae_loc.site_access_code_kv
        );
    }

    const kv = $ae_loc?.site_access_code_kv;
    if (!kv) return false;

    // Reminder: super > manager > administrator > trusted > public > authenticated > anonymous

    if (entered_passcode && entered_passcode.length >= 5) {
        if (
            kv.super?.length >= 8 &&
            kv.super == entered_passcode
        ) {
            console.log('Super passcode matched');

            window.localStorage.setItem('access_type', 'super');

            $ae_loc.access_type = 'super';
        } else if (
            kv.manager?.length >= 5 &&
            kv.manager == entered_passcode
        ) {
            console.log('Manager passcode matched');

            window.localStorage.setItem('access_type', 'manager');

            $ae_loc.access_type = 'manager';
        } else if (
            kv.administrator?.length >= 5 &&
            kv.administrator == entered_passcode
        ) {
            console.log('Administrator passcode matched');

            window.localStorage.setItem('access_type', 'administrator');

            $ae_loc.access_type = 'administrator';
        } else if (
            kv.trusted?.length >= 5 &&
            kv.trusted == entered_passcode
        ) {
            console.log('Trusted passcode matched');

            window.localStorage.setItem('access_type', 'trusted');

            $ae_loc.access_type = 'trusted';
        } else if (
            kv.public?.length >= 5 &&
            kv.public == entered_passcode
        ) {
            console.log('Public passcode matched');

            window.localStorage.setItem('access_type', 'public');

            $ae_loc.access_type = 'public';
        } else if (
            kv.authenticated == entered_passcode
        ) {
            console.log('Authenticated passcode matched');

            window.localStorage.setItem('access_type', 'authenticated');

            $ae_loc.access_type = 'authenticated';
        } else {
            if (log_lvl > 1) {
                console.log(
                    'Entered passcode does not match any of the site access codes.'
                );
            }

            if ($ae_loc.access_type != 'anonymous') {
                console.log('Access type is not anonymous');
            }
            // window.localStorage.setItem('access_type', 'anonymous');

            // $ae_loc.access_type = 'anonymous';

            // trigger = 'process_permission_check';

            // $ae_loc = $ae_loc; // Trigger Svelte just in case
            // ae_loc.set($ae_loc);
            // console.log($ae_loc);

            // dispatch_access_type_changed();

            return false;
        }

        entered_passcode = '';
        show_passcode_input = false;
        trigger = 'process_permission_check';

        $ae_loc.app_cfg.show_element__menu = false;
        $ae_loc.app_cfg.show_element__menu_btn = true;

        // WARNING 2024-08-21: For some reason the config element does not auto show or hide when the access type changes.
        if (!$ae_loc.iframe && $ae_loc.authenticated_access) {
            $ae_loc.app_cfg.show_element__access_type = true;
            $ae_loc.app_cfg.show_element__cfg = true;
        } else if ($ae_loc.iframe && $ae_loc.trusted_access) {
            $ae_loc.app_cfg.show_element__access_type = true;
            $ae_loc.app_cfg.show_element__cfg = true;
        } else {
            $ae_loc.app_cfg.show_element__access_type = true;
            $ae_loc.app_cfg.show_element__cfg = false;
        }

        // dispatch_access_type_changed();

        return true;
    } else {
        if (log_lvl > 1) {
            console.log('Entered passcode too short.');
        }

        // $ae_loc.access_type = null; // 'anonymous';

        // dispatch_access_type_changed()

        return null;
    }
}

function handle_clear_access() {
    // console.log('handle_clear_access()');
    // NOTE: I think it makes since to reset this to anonymous even if logged in as an admin or similar.
    window.localStorage.setItem('access_type', 'anonymous');

    // $ae_loc.access_type = null; // 'anonymous';
    // Revert back to the user's access type after quick access (temporarily escalate permissions) is turned off.
    $ae_loc.access_type = $ae_loc.user_access_type ?? 'anonymous';
    trigger = 'process_permission_check';

    entered_passcode = ''; // Clear the entered passcode
    // Reset so the same passcode can be re-entered after clearing.
    // Without this, the $effect guard (entered_passcode != checked_passcode) silently
    // blocks re-entry of the same passcode until the component remounts (page refresh).
    checked_passcode = null;
    show_passcode_input = true;

    $ae_loc.app_cfg.show_element__menu = false;
    $ae_loc.app_cfg.show_element__menu_btn = true;

    $ae_loc.edit_mode = false;

    return true;
}
</script>

<section
    id="AE-Quick-Access-Type"
    class="
        ae_access_type
        hidden-print

        flex w-full
        flex-col flex-wrap

        items-end justify-center gap-1 border-2
        border-gray-200 bg-blue-100

        p-1
        text-gray-900
        transition-all delay-150

        duration-300 hover:delay-1000 hover:ease-out dark:bg-blue-800
        dark:text-gray-200
        "
    class:hidden={hide}>
    <!-- class:hidden={!$ae_sess.show__sign_in_out__fields} -->
    <header class="ae_header hidden">
        <h2 class="text-center text-sm font-semibold">Passcode Sign In</h2>
    </header>

    <!-- Show list of authorized sessions and presentations for a user -->
    <!-- {#if $ae_loc.access_type == 'administrator'}
        {#if $events_loc.auth__kv.session}
        Sessions:
        <ul>
        {#each Object.entries($events_loc.auth__kv.session) as [key, value] (key)}
        <li><a href="/events/{event_id}/session/{key}">
            {key}
            </a></li>
        {/each}
        </ul>
        {/if}
    {/if} -->

    <div class="transition-all">
        {#if $ae_loc.trusted_access && $ae_loc.edit_mode}
            <!-- Removed 2026-06-16: dead "Lock Config" Sync/Unlink toggle. It wrote to
                 $ae_loc.sync_local_config/lock_config and pres_mgmt_loc.current.sync_local_config/
                 lock_config, but nothing in the codebase ever read any of those four fields —
                 confirmed via full-repo grep. It also confusingly shared a name with the Pres
                 Mgmt Config page's own "Lock Config" checkbox, which has since been removed
                 entirely too — sync_config__event_pres_mgmt() now syncs unconditionally.
                 See PROJECT__AE_Events_PressMgmt_Config_Cleanup.md. -->

            <!-- {#if $ae_loc.edit_mode}
            <button
                type="button"
                onclick={() => {
                    $ae_loc.edit_mode = false;
                    // dispatch_edit_mode_changed();
                }}
                class="btn btn-sm px-2 variant-ghost-success hover:variant-filled-success transition-all"
                title="Edit mode is currently enabled. Click to disable."
                >
                <span class="fas fa-toggle-on mx-1"></span>
                Edit Mode On
            </button>
        {:else}
            <button
                type="button"
                onclick={() => {
                    $ae_loc.edit_mode = true;
                    // dispatch_edit_mode_changed();
                }}
                class="btn btn-sm px-2 variant-ghost-warning hover:variant-filled-warning transition-all space-x-1 *:hover:inline"
                title="Edit mode is currently disabled. Click to enable."
                >
                <span class="fas fa-toggle-off mx-1"></span>
                Edit
                <span class="hidden">
                    Mode?
                </span>
            </button>
        {/if} -->
        {/if}
    </div>

    <div
        class="flex w-full flex-row flex-wrap items-end justify-end gap-1 transition-all">
        {#if $ae_loc?.access_type && $ae_loc?.access_type == 'anonymous'}
            <span>
                <button
                    type="button"
                    onclick={() => {
                        // Toggle the passcode input — show it if hidden, hide it (cancel) if shown.
                        show_passcode_input = !show_passcode_input;
                    }}
                    class="btn btn-sm preset-tonal-success hover:preset-filled-warning-500 access_type_unlock_btn transition-all"
                    title={show_passcode_input
                        ? 'Cancel passcode entry'
                        : 'Enter a passcode to unlock access'}>
                    {#if show_passcode_input}
                        <LockOpen size="1em" class="mx-1" />
                        <span>Cancel</span>
                    {:else}
                        <Lock size="1em" class="mx-1" />
                        <span class="lock_icon">Locked</span>
                        <LockOpen size="1em" class="unlock_icon mx-1 hidden" />
                        <span class="unlock_text">Access?</span>
                    {/if}
                </button>
            </span>
        {/if}

        {#if $ae_loc?.access_type && $ae_loc?.access_type != 'anonymous'}
            <span class="flex flex-row items-center justify-center gap-1">
                <!-- <span class="fas fa-unlock mx-1"></span> -->
                <ShieldPlus class="inline-block" />

                <span
                    class="*:hover:inline"
                    title={`Current access type/level: ${$ae_loc.access_type}`}>
                    {#if $ae_loc.access_type == 'super'}
                        <Wand2 size="1em" class="m-1" />
                        <span class="hidden">Super</span>
                    {:else if $ae_loc.access_type == 'manager'}
                        <ShieldUser size="1em" class="m-1" />
                        <span class="hidden">Manager</span>
                    {:else if $ae_loc.access_type == 'administrator'}
                        <UserRound size="1em" class="m-1" />
                        <span class="hidden">Administrator</span>
                    {:else if $ae_loc.access_type == 'trusted'}
                        <UserCheck size="1em" class="m-1" />
                        <span class="hidden">Trusted Access</span>
                    {:else if $ae_loc.access_type == 'public'}
                        Public
                        <span class="hidden">Access</span>
                    {:else if $ae_loc.access_type == 'authenticated'}
                        Authenticated
                        <span class="hidden">Access</span>
                    {:else if $ae_loc.access_type == 'anonymous'}
                        Anonymous Access
                    {:else}
                        Unknown Access
                    {/if}
                </span>

                {#if $ae_loc?.user_access_type && $ae_loc?.access_type == $ae_loc?.user_access_type && !show_passcode_input}
                    <button
                        type="button"
                        onclick={() => {
                            // handle_clear_access();
                            // trigger_clear_access = true;
                            show_passcode_input = true;
                        }}
                        class="btn btn-sm variant-outline-surface hover:preset-tonal-warning border-warning-500 border transition-all"
                        title={`Current user access level: "${$ae_loc.user_access_type}". Click use passcode for a different access level.`}>
                        <!-- <span class="fas fa-lock mx-1"></span> -->
                        <!-- <ShieldMinus /> -->
                        <ShieldEllipsis class="inline-block" />
                        Passcode?
                    </button>
                {:else if !show_passcode_input}
                    <button
                        type="button"
                        onclick={() => {
                            // handle_clear_access();
                            trigger_clear_access = true;
                            show_passcode_input = true;
                            // show_passcode_input = true;
                        }}
                        class="btn btn-sm variant-outline-warning hover:preset-tonal-warning border-warning-500 border transition-all"
                        title={`Current access level: "${$ae_loc.access_type}". Click to clear the temporary access level.`}>
                        <!-- <span class="fas fa-lock mx-1"></span> -->
                        <ShieldMinus class="inline-block" />
                        Clear?
                    </button>
                {/if}
            </span>
        {/if}

        {#if show_passcode_input}
            <span
                class="flex w-full flex-row items-center justify-between gap-1">
                <span>
                    <ShieldEllipsis class="inline-block text-gray-500" />
                    <span class="unlock_text text-sm">Passcode:</span>
                </span>

                <!-- svelte-ignore a11y_autofocus -->
                <input
                    id="access_passcode_input"
                    bind:value={entered_passcode}
                    class="input w-32 transition-all"
                    class:hidden={!show_passcode_input}
                    type="text"
                    placeholder="Passcode"
                    onkeydown={(e) => { if (e.key === 'Enter') handle_check_access_type_passcode(); }}
                    autofocus={show_passcode_input} />

                {#if auth_pending}
                    <Loader size="1em" class="animate-spin text-gray-400" />
                {/if}
            </span>
        {/if}
    </div>

    {#if auth_error}
        <span class="text-xs text-red-600 dark:text-red-400">{auth_error}</span>
    {/if}
</section>

<style lang="scss">
/* BEGIN: AE's Svelte Quick Access Type component  */
/*
#xxx-AE-Quick-Access-Type {
    // position: absolute;
    position: fixed;
    // position: relative;
    // position: static;
    // position: sticky;
    // top: 1em;
    bottom: 1.5rem;
    right: 0rem;

    padding: .5rem;

    // lightyellow
    // background-color: hsla(60,100%,90%,.30);
    // background-color: rgba(var(--color-surface-500) / .5);

    border-top: solid thin hsla(0,0%,0%,.25);
    border-left: solid thin hsla(0,0%,0%,.25);
    border-bottom: solid thin hsla(0,0%,0%,.25);
    border-top-left-radius: .5em;
    border-bottom-left-radius: .5em;

    opacity: .15;
    // opacity: 1;

    font-size: .75rem;

    z-index: 5;

    // NOTE: transition when no longer hovering
    transition-property: opacity, background-color;
    transition-delay: 1.25s;
    transition-duration: .75s;
    transition-timing-function: ease-out;
}
*/

/*
#xxx-AE-Quick-Access-Type:hover {

    border-top: solid thin hsla(0,0%,0%,.95);
    border-left: solid thin hsla(0,0%,0%,.95);
    border-bottom: solid thin hsla(0,0%,0%,.95);

    opacity: 1;

    // NOTE: transition when hover starts
    transition-property: opacity, background-color;
    transition-delay: .5s;
    transition-duration: .25s;
    transition-timing-function: ease-in;
}
*/

/* #Access-Type .unlock_text {
    transition: width 2s, height 2s, background-color 2s, transform 2s;
} */
/* END: Svelte Access Type component  */

.access_type_unlock_btn .unlock_text {
    display: none;
}

.access_type_unlock_btn:hover .unlock_text {
    display: initial;
    /* outline: solid thin red; */
}

/*
.ae_access_type .current_text {
    display: none;
}

.ae_access_type:hover .current_text {
    display: initial;
    outline: solid thin red;
}
*/
</style>
