<script lang="ts">
    /** @type {import('./$types').LayoutData} */
    // /** @type {import('./$types').LayoutProps} */

    let log_lvl: number = 0;

    // *** Import Svelte specific
    import { untrack } from 'svelte';
    import { goto, invalidateAll } from '$app/navigation';

    import '../app.css';

    // *** Import other supporting libraries
    // import {
    //     ArrowBigRight,
    //     CircleX,
    //     RefreshCw,
    //     RefreshCcw,
    //     RefreshCcwDot
    // } from '@lucide/svelte';

    // Highlight JS
    import hljs from 'highlight.js/lib/core';
    import 'highlight.js/styles/github-dark.css';

    import { browser } from '$app/environment';
    import { online } from 'svelte/reactivity/window';
    import xml from 'highlight.js/lib/languages/xml'; // for HTML
    import css from 'highlight.js/lib/languages/css';
    import javascript from 'highlight.js/lib/languages/javascript';
    import typescript from 'highlight.js/lib/languages/typescript';

    hljs.registerLanguage('xml', xml); // for HTML
    hljs.registerLanguage('css', css);
    hljs.registerLanguage('javascript', javascript);
    hljs.registerLanguage('typescript', typescript);

    // *** Import Aether specific variables and functions
    // import Analytics from '$lib/app_components/analytics.svelte';
    import { ae_loc, ae_sess, ae_api, slct, slct_trigger, ae_auth_error } from '$lib/stores/ae_stores';
    // import { events_loc, events_slct } from '$lib/stores/ae_events_stores';

    // import MyClipboard from '$lib/app_components/e_app_clipboard.svelte';
    import E_app_debug_menu from '$lib/app_components/e_app_debug_menu.svelte';
    import E_app_sys_menu from '$lib/app_components/e_app_sys_menu.svelte';

    interface Props {
        data: any;
        children?: import('svelte').Snippet;
    }

    let { data, children }: Props = $props();

    // STABLE DERIVATION: Using prop data directly to avoid store loops
    let ae_acct = $derived(data[data.account_id]);

    let flag_clear_idb: boolean = $state(false);
    let flag_clear_local: boolean = $state(false);
    let flag_clear_sess: boolean = $state(false);
    let flag_reload: boolean = $state(false);

    let flag_new_ver: boolean = $state(false);
    let flag_expired: boolean = $state(false);
    let flag_denied: boolean = $state(false);

    // Connection Status
    let is_offline = $derived(browser && online.current === false);
    let api_unreachable = $derived($ae_loc?.account_id === 'ghost');
    let api_error_msg = $derived($ae_loc?.account_name || 'API Server Unreachable');
    let show_connection_details = $state(true);

    let last_reload_time = 0;

    // Shallow equality guard — avoids triggering Svelte store updates when the merged
    // object is functionally identical to the current one. Comparing JSON.stringify on
    // large objects like $ae_loc (site config, device info, flags) is expensive and
    // runs on every navigation. Key-by-key identity check is O(n keys), not O(n chars).
    function shallow_equal(a: Record<string, any>, b: Record<string, any>): boolean {
        const keys_a = Object.keys(a);
        const keys_b = Object.keys(b);
        if (keys_a.length !== keys_b.length) return false;
        for (const k of keys_a) {
            if (a[k] !== b[k]) return false;
        }
        return true;
    }

    // 1. CONSOLIDATED SYNC EFFECT (One single point of entry for store updates)
    $effect(() => {
        if (!browser || !ae_acct) return;

        untrack(() => {
            if (log_lvl > 1) console.log("ROOT: Running Sync Effect");

            // A. Sync Global Stores
            const current_api = $ae_api;
            const new_api = { ...current_api, ...(ae_acct.api || {}) };
            // Deep check for JWT specifically to avoid extra triggers
            if (current_api.jwt !== $ae_loc.jwt) new_api.jwt = $ae_loc.jwt;
            if (!shallow_equal(current_api, new_api)) {
                $ae_api = new_api;
            }

            const current_loc = $ae_loc;
            const new_loc = { ...current_loc, ...(ae_acct.loc || {}) };
            // Restore structural integrity if clobbered
            if (!new_loc.sys_menu) new_loc.sys_menu = { hide: false, hide_access_type: false, expand_access_type: false, hide_edit_mode: false, expand_edit_mode: false, hide_user: false, expand_user: false, hide_theme: false, expand_theme: false, hide_cfg: false, expand_cfg: false };
            if (!new_loc.debug_menu) new_loc.debug_menu = { hide: false, expand: false };

            if (!shallow_equal(current_loc, new_loc)) {
                $ae_loc = new_loc;
            }

            const current_slct = $slct;
            const new_slct = { ...current_slct, ...(ae_acct.slct || {}) };
            if (!shallow_equal(current_slct, new_slct)) {
                $slct = new_slct;
            }

            // B. Version & Sanity Check
            if (new_loc.ver && $ae_sess.ver && new_loc.ver !== $ae_sess.ver) {
                if (!flag_new_ver) {
                    console.log("ROOT: Version mismatch detected");
                    flag_new_ver = true;
                    flag_reload = true;
                }
            }

            // C. Access Check (Idempotent)
            if (new_loc.site_access_key || new_loc.site_domain_access_key) {
                const key = new_loc.allow_access;
                const match = (new_loc.site_access_key === key || new_loc.site_domain_access_key === key);
                if (!match && !new_loc.trusted_access) {
                    if (new_loc.allow_access !== false) $ae_loc.allow_access = false;
                    if (!flag_denied) flag_denied = true;
                }
            } else if (new_loc.allow_access !== true) {
                $ae_loc.allow_access = true;
            }

            // D. Theme Initialization (Once)
            if (!current_loc.theme_mode) {
                if (window.matchMedia('(prefers-color-scheme: dark)').matches) $ae_loc.theme_mode = 'dark';
                else $ae_loc.theme_mode = 'light';
            }
        });
    });

    // 2. RELOAD THROTTLE EFFECT
    $effect(() => {
        if (!browser) return;

        if (flag_reload) {
            untrack(() => {
                const now = Date.now();
                if (now - last_reload_time < 10000) {
                    console.warn("ROOT: Critical loop prevention - reload suppressed");
                    flag_reload = false;
                    return;
                }
                last_reload_time = now;
                flag_reload = false;

                if (flag_clear_local) clear_local();
                if (flag_clear_sess) clear_sess();

                console.log("ROOT: Executing throttled reload");
                invalidateAll();
            });
        }
    });

    // 3. UI STATE & THEME DOM EFFECT
    let is_hydrating = $state(true);
    $effect(() => {
        if (!browser) return;

        // Theme name — controls which Skeleton color palette is active
        document.documentElement.setAttribute('data-theme', $ae_loc?.theme_name ?? 'nouveau');

        // Dark/light class — controls Tailwind v4 class-based dark mode variant.
        // @custom-variant dark in app.css registers this; without it the class does nothing.
        if ($ae_loc?.theme_mode === 'dark') {
            document.documentElement.classList.add('dark');
            document.documentElement.classList.remove('light');
        } else {
            document.documentElement.classList.add('light');
            document.documentElement.classList.remove('dark');
        }

        // Font size mode — cycles default | larger | smaller.
        // CSS classes are defined in app.css; no class = browser default (16px).
        document.documentElement.classList.remove('font-size-larger', 'font-size-smaller');
        if ($ae_loc?.font_size_mode === 'larger') {
            document.documentElement.classList.add('font-size-larger');
        } else if ($ae_loc?.font_size_mode === 'smaller') {
            document.documentElement.classList.add('font-size-smaller');
        }

        // Hydration overlay timer
        if ($ae_loc?.account_id) {
            const timer = setTimeout(() => is_hydrating = false, 500);
            return () => clearTimeout(timer);
        }
    });

    function clear_idb() {
        indexedDB.deleteDatabase('ae_archives_db');
        indexedDB.deleteDatabase('ae_core_db');
        indexedDB.deleteDatabase('ae_events_db');
        indexedDB.deleteDatabase('ae_journals_db');
        indexedDB.deleteDatabase('ae_posts_db');
        indexedDB.deleteDatabase('ae_sponsorships_db');
    }

    function clear_local() {
        localStorage.clear();
    }

    function clear_sess() {
        sessionStorage.clear();
    }

    // 4. EXTERNAL INTERFACES EFFECT
    $effect(() => {
        if (!browser) return;

        // Save DS to local
        let ae_ds = ae_acct?.ds;
        if (ae_ds) {
            for (let [key, value] of Object.entries(ae_ds)) {
                localStorage.setItem(`ae_ds__${key}`, JSON.stringify(value));
            }
        }

        // Message Bridge
        const handler = (event: MessageEvent) => {
            if (event.data.type === 'api_download_blob') {
                $ae_sess.api_download_kv[event.data.task_id] = { ...event.data };
            } else if (event.data.type === 'api_post_json_form') {
                $ae_sess.api_upload_kv[event.data.task_id] = { ...event.data };
            }
        };
        window.addEventListener('message', handler);

        // Iframe Detection
        let iframe = data.url.searchParams.get('iframe');
        if (iframe === 'true') $ae_loc.iframe = true;
        else if (iframe === 'false') $ae_loc.iframe = false;

        // Theme URL params — ?theme=AE_Firefly_SteelBlue&theme_mode=dark
        // Applied once on load, then silently removed from the URL (no history entry).
        const url_theme = data.url.searchParams.get('theme');
        const url_theme_mode = data.url.searchParams.get('theme_mode');
        if (url_theme || url_theme_mode) {
            if (url_theme) $ae_loc.theme_name = url_theme;
            if (url_theme_mode === 'light' || url_theme_mode === 'dark') $ae_loc.theme_mode = url_theme_mode;
            const clean_url = new URL(data.url.href);
            clean_url.searchParams.delete('theme');
            clean_url.searchParams.delete('theme_mode');
            goto(clean_url.pathname + clean_url.search + clean_url.hash, {
                replaceState: true,
                noScroll: true,
                keepFocus: true
            });
        }

        // Electron Detection
        if ((window as any).native_app || (window as any).aetherNative) {
            if (!$ae_loc.is_native) $ae_loc.is_native = true;
        }

        return () => window.removeEventListener('message', handler);
    });

    // 5. SESSION EXPIRED EFFECT — watches ae_auth_error and raises the banner when the API signals 401/403.
    // Guards on $ae_loc.jwt so that unauthenticated first-loads (no stored JWT) never trigger it —
    // 401s are expected on first visit and should not look like a session expiry.
    $effect(() => {
        if ($ae_auth_error?.type === 'expired') {
            untrack(() => {
                if ($ae_loc?.jwt) flag_expired = true;
            });
        }
    });
</script>

<svelte:head>
    <link rel="stylesheet" href={ae_acct?.loc?.site_style_href} />
</svelte:head>

{#if browser && (is_offline || api_unreachable)}
    <div class="fixed top-0 left-0 right-0 z-100 p-4 bg-orange-600/90 text-white text-center shadow-2xl flex items-center justify-center gap-4">
        <span class="text-xl font-bold">{is_offline ? 'Offline' : api_error_msg}</span>
        <button class="btn btn-sm variant-filled-white text-orange-600" onclick={() => window.location.reload()}>Retry</button>
    </div>
{/if}

{#if browser && flag_expired}
    <div class="fixed top-0 left-0 right-0 z-50 px-4 py-2 bg-amber-500 text-white shadow-xl flex items-center justify-between gap-4">
        <p class="text-sm font-semibold">Your session has expired. Please reload or sign in again.</p>
        <div class="flex gap-2 items-center shrink-0">
            <button class="btn btn-sm variant-filled-white text-amber-700" onclick={() => window.location.reload()}>Reload</button>
            <button class="btn btn-sm" onclick={() => { flag_expired = false; ae_auth_error.set({ type: null, ts: null }); }}>✕</button>
        </div>
    </div>
{/if}

{#if browser && $ae_loc?.allow_access}
    {@render children?.()}

    {#if is_hydrating}
        <div class="fixed inset-0 z-99 flex flex-col items-center justify-center bg-surface-50/80 dark:bg-surface-900/80 backdrop-blur-sm transition-opacity duration-500">
            <div class="preset-filled-surface-100-900 p-8 rounded-2xl shadow-2xl flex flex-col items-center gap-4">
                <span class="fas fa-cog fa-spin text-5xl text-primary-500"></span>
                <div class="text-center font-bold text-xl">Hydrating Aether...</div>
            </div>
        </div>
    {/if}
{:else if browser && flag_denied}
    <div class="flex flex-col items-center justify-center h-screen gap-6 p-8">
        <h1 class="text-4xl font-black text-error-500">Access Denied</h1>
        <button class="btn variant-filled-primary" onclick={() => window.location.reload()}>Reload</button>
    </div>
{:else if browser}
    <div class="flex items-center justify-center h-screen"><span class="fas fa-spinner fa-spin text-4xl opacity-20"></span></div>
{/if}

{#if browser && (!$ae_loc?.iframe || $ae_loc?.trusted_access)}
    <E_app_sys_menu {data} bind:hide={$ae_loc.sys_menu.hide} bind:expand={$ae_sess.sys_menu.expand} />

    <!-- You must be in Edit Mode to initially see the Debug expand button. Once expanded, you can toggle the Edit Mode while still seeing the expanded Debug content. -->
    {#if $ae_loc.edit_mode || $ae_loc.debug_menu.expand}
        <E_app_debug_menu bind:hide={$ae_loc.debug_menu.hide} bind:expand={$ae_loc.debug_menu.expand} />
    {/if}
{/if}
