<script lang="ts">
import { browser } from '$app/environment';
import { onMount, untrack } from 'svelte';
import { liveQuery } from 'dexie';

import { api } from '$lib/ae_api/api';
import { ae_loc, ae_api, slct } from '$lib/stores/ae_stores';
import { db_core } from '$lib/ae_core/db_core';
import type { ae_DataStore } from '$lib/types/ae_types';
import { Database, Info, LoaderCircle, SquarePen } from '@lucide/svelte';
import AE_DataStore_Form from '$lib/elements/element_data_store_form.svelte';

interface Props {
    log_lvl?: number;
    expire_minutes?: number;
    mount_reload_sec?: number;
    ds_code: string;
    ds_name?: null | string;
    ds_type?: string;
    for_type?: null | string;
    for_id?: null | string;
    class_li?: string;
    display?: string;
    try_cache?: boolean;
    hide?: boolean;
    show_edit?: boolean;
    show_edit_btn?: boolean;
    show_view?: boolean;
    ds_loaded?: boolean;
    debug?: boolean;
    ds_loading_status?: string;
    val_sql?: null | any;
}

let {
    log_lvl = 0,
    expire_minutes = 15,
    mount_reload_sec = 0,
    ds_code,
    ds_name = null,
    ds_type = 'text',
    for_type = null,
    for_id = null,
    class_li = '',
    display = undefined as string | undefined,
    try_cache = true,
    hide = false,
    show_edit = $bindable(false),
    show_edit_btn = false,
    show_view = $bindable(true),
    ds_loaded = $bindable(false),
    debug = false,
    ds_loading_status = $bindable('starting'),
    val_sql = $bindable(null)
}: Props = $props();

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

// Dexie LiveQuery for data store
let lq__ds_obj = $derived(
    liveQuery(async () => {
        const current_code = ds_code;
        const account_id = $ae_loc.account_id;
        const current_for_type = for_type;
        const current_for_id = for_id;

        if (!current_code) return null;

        const results = await db_core.data_store
            .where('code')
            .equals(current_code)
            .toArray();

        if (!results || results.length === 0) return null;

        // Sort by specificity
        results.sort((a, b) => {
            const a_context = current_for_id && a.for_id === current_for_id && a.for_type === current_for_type ? 1 : 0;
            const b_context = current_for_id && b.for_id === current_for_id && b.for_type === current_for_type ? 1 : 0;
            if (a_context !== b_context) return b_context - a_context;

            const a_account = account_id && a.account_id === account_id ? 1 : 0;
            const b_account = account_id && b.account_id === account_id ? 1 : 0;
            if (a_account !== b_account) return b_account - a_account;

            const a_time = new Date(a.updated_on || a.created_on || 0).getTime();
            const b_time = new Date(b.updated_on || b.created_on || 0).getTime();
            return b_time - a_time;
        });

        return results[0];
    })
);

// Sync bound props when the live data changes
$effect(() => {
    const entry = $lq__ds_obj as ae_DataStore | null;
    untrack(() => {
        ds_loaded = !!entry;
        if (entry) {
            ds_loading_status = 'loaded';
            if (ds_type === 'sql') {
                val_sql = entry.text || entry.html || null;
            }
        }
    });
});

// Context Change Guard
$effect(() => {
    void for_id; void for_type; void ds_code;
    untrack(() => { ds_loading_status = 'starting'; });
});

$effect(() => {
    const account_id = $slct.account_id;
    const api_ready = !!$ae_api?.base_url;
    const entry = $lq__ds_obj as ae_DataStore | null | undefined;

    if (!browser || !account_id || !api_ready || ds_loading_status !== 'starting') return;

    const entry_is_stale_account = entry?.account_id !== null && entry?.account_id !== account_id;
    if (!entry || entry_is_stale_account) {
        trigger = 'load__ds__code';
    }
});

$effect(() => {
    if (trigger === 'load__ds__code') {
        untrack(() => {
            trigger = null;
            load_data_store();
        });
    }
});

onMount(() => {
    if (mount_reload_sec > 0) {
        setTimeout(() => { trigger = 'load__ds__code'; }, Math.floor(Math.random() * mount_reload_sec * 1000));
    }
});

async function load_data_store() {
    if (ds_loading_status === 'loading') return;
    ds_loading_status = 'loading';
    const api_cfg = untrack(() => $ae_api);

    try {
        let ds_results = await api.get_data_store({ api_cfg, code: ds_code, for_type, for_id, log_lvl });
        const is_error = ds_results?.meta?.success === false;
        const status_code = ds_results?.meta?.status_code || (ds_results === false ? 500 : 200);

        if (!ds_results || is_error || [404, 403, 401].includes(status_code)) {
            ds_results = await api.get_data_store({ api_cfg, code: ds_code, no_account_id: true, log_lvl });
        }

        const ds_id = ds_results?.data_store_id || ds_results?.id;
        if (ds_results && ds_id) {
            const text_val = ds_results.text || '';
            const json_val = ds_results.json || (ds_results.json_str ? JSON.parse(ds_results.json_str) : null);

            const ds_to_save: ae_DataStore = {
                ...ds_results,
                id: ds_id,
                data_store_id: ds_results.data_store_id || ds_id,
                account_id: ds_results.account_id || null,
                updated_on: ds_results.updated_on || new Date().toISOString(),
                text: text_val,
                html: text_val,
                json: json_val
            };
            await db_core.data_store.put(ds_to_save);
        } else {
            ds_loading_status = 'not found';
        }
    } catch (err) {
        console.error(`ae_e_data_store [${ds_code}]: Fetch failed.`, err);
        ds_loading_status = 'error';
    }
}

</script>

<div
    class="ae__elem__data_store relative {class_li}"
    class:hidden={hide}
    style={display ? `display: ${display}` : undefined}>
    {#if $lq__ds_obj}
        {#if debug || $ae_loc.debug === 'debug'}
            <div class="preset-tonal-surface mb-2 rounded-lg p-2 text-[10px]">
                <div class="flex items-center gap-1 font-bold uppercase opacity-50 mb-1">
                    <Database size="12" /> Debug Info
                </div>
                <pre class="overflow-x-auto">ID: {$lq__ds_obj.id} | Code: {$lq__ds_obj.code} | Type: {$lq__ds_obj.type} | Account: {$lq__ds_obj.account_id || 'Global'}</pre>
            </div>
        {/if}

        <AE_DataStore_Form
            bind:open={show_edit}
            editing_obj={$lq__ds_obj as ae_DataStore}
            show_account_field={false}
            show_for_fields={false}
            readonly_code={!$ae_loc.manager_access}
            on_saved={() => { trigger = 'load__ds__code'; }}
            on_deleted={() => { ds_loading_status = 'not found'; }} />

        {#if show_view}
            {#if $lq__ds_obj.type === 'html' && $lq__ds_obj.html}
                {@html $lq__ds_obj.html}
            {:else if $lq__ds_obj.type === 'text' && $lq__ds_obj.text}
                <div class="whitespace-pre-wrap">{$lq__ds_obj.text}</div>
            {:else if $lq__ds_obj.type === 'sql' && $lq__ds_obj.text}
                {#if debug}<div class="preset-tonal-surface rounded p-2 font-mono text-xs opacity-50"><span class="font-bold">SQL:</span> {$lq__ds_obj.text}</div>{/if}
            {/if}
        {/if}

        {#if $ae_loc.edit_mode && ($ae_loc.manager_access || (show_edit_btn && $ae_loc.administrator_access))}
            <button
                type="button"
                class="btn-icon btn-icon-sm preset-tonal-warning absolute top-0 right-0 z-10 opacity-20 transition-opacity hover:opacity-100"
                ondblclick={() => { show_edit = true; }}
                title="Edit Data Store: {ds_code}">
                <SquarePen size="14" />
            </button>
        {/if}
    {:else if ds_loading_status === 'not found'}
        {#if $ae_loc.administrator_access || ($ae_loc.trusted_access && $ae_loc.edit_mode)}
            <div class="preset-tonal-surface flex items-center gap-2 rounded border-2 border-dashed p-3 text-xs opacity-60">
                <Info size="14" class="text-warning-500" />
                <span class="font-bold">Data Store not found:</span> 
                <code class="font-mono text-primary-500">{ds_code}</code>
            </div>
        {/if}
    {/if}

    {#if ds_loading_status === 'loading'}
        <div class="absolute bottom-0 left-0 p-1 opacity-50">
            <LoaderCircle size="14" class="animate-spin text-primary-500" />
        </div>
    {/if}
</div>

<style>
.ae__elem__data_store :global(.btn-icon-sm) { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; padding: 0; }
</style>
