<script lang="ts">
import { untrack } from 'svelte';
/**
 * ae_comp__journal_entry_obj_id_view.svelte
 * Reference Implementation for Journal Entry View/Edit
 * Corrected for V3 API Strictness & Robust Decryption
 * Uses strictly snake_case.
 */

// *** Import Svelte core
// import { goto } from '$app/navigation';

// *** Import secondary libraries
import { marked } from 'marked';

// *** Import Aether components and helpers
import type { key_val } from '$lib/stores/ae_stores';
import { ae_util } from '$lib/ae_utils/ae_utils';
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
import {
    journals_loc,
    journals_sess
} from '$lib/ae_journals/ae_journals_stores';
import { journals_func } from '$lib/ae_journals/ae_journals_functions';
import { decrypt_journal_entry } from '$lib/ae_journals/ae_journals_decryption';

import AE_Comp_Journal_Entry_Editor from './ae_comp__journal_entry_editor.svelte';
import AE_Comp_Journal_Entry_Header from './ae_comp__journal_entry_header.svelte';
import AE_Comp_Journal_Entry_Metadata from './ae_comp__journal_entry_metadata.svelte';
import AE_Comp_Journal_Entry_AiTools from './ae_comp__journal_entry_ai_tools.svelte';
import AE_Comp_Journal_Entry_ObjFileLi from './ae_comp__journal_entry_obj_file_li.svelte';
import AE_Comp_Modal_Journal_Entry_Append from './ae_comp__modal_journal_entry_append.svelte';
import AE_Comp_Modal_Journal_Entry_Config from './ae_comp__modal_journal_entry_config.svelte';
import type { ae_JournalEntryDraft } from '$lib/types/ae_types';

// Icons
import { CircleAlert, CircleX, LoaderCircle } from '@lucide/svelte';
// *** Props
interface Props {
    log_lvl?: number;
    lq__journal_obj: any;
    lq__journal_obj_li: any;
    lq__journal_entry_obj: any;
    on_show_export?: () => void;
}

let {
    log_lvl = 0,
    lq__journal_obj,
    lq__journal_obj_li,
    lq__journal_entry_obj,
    on_show_export
}: Props = $props();

// *** State
let editor_view: any = $state();
let orig_entry_obj: ae_JournalEntryDraft | null = $state(null);
let tmp_entry_obj: ae_JournalEntryDraft = $state({});
let save_status: 'saved' | 'unsaved' | 'saving' = $state('saved');
let decryption_error: string | null = $state(null);
let auto_save_timer: ReturnType<typeof setTimeout>;
let is_processing = $state(false);
let show_config_modal = $state(false);

// *** Helpers
function deep_copy(obj: any) {
    if (!obj) return null;
    try {
        const copy: ae_JournalEntryDraft = {};
        for (const key in obj) {
            const val = obj[key];
            if (val instanceof Date) {
                copy[key] = new Date(val.getTime());
            } else if (Array.isArray(val)) {
                copy[key] = [...val];
            } else if (typeof val === 'object' && val !== null) {
                copy[key] = { ...val };
            } else {
                copy[key] = val;
            }
        }
        return copy;
    } catch (e) {
        console.error('deep_copy failed:', e);
        return { ...obj };
    }
}

// *** Derived
let has_unsaved_changes = $derived.by(() => {
    if (!tmp_entry_obj || !orig_entry_obj || is_processing) return false;

    const normalize = (val: any) =>
        val === null || val === undefined ? '' : String(val).trim();

    const content_changed =
        normalize(tmp_entry_obj.content) !== normalize(orig_entry_obj.content);
    const name_changed =
        normalize(tmp_entry_obj.name) !== normalize(orig_entry_obj.name);
    const private_changed =
        (tmp_entry_obj.private ?? false) !== (orig_entry_obj.private ?? false);

    if (content_changed || name_changed || private_changed) return true;

    const other_fields = [
        'tags',
        'category_code',
        'public',
        'personal',
        'professional',
        'archive_on',
        'sort'
    ];
    for (const field of other_fields) {
        if (
            normalize(tmp_entry_obj[field]) !== normalize(orig_entry_obj[field])
        )
            return true;
    }

    return false;
});

// *** Effects

// 1. Initial Load & Background Sync
$effect(() => {
    const entry = $lq__journal_entry_obj; // Track only entry

    untrack(() => {
        const journal = $lq__journal_obj;
        if (!entry || !(entry.updated_on || entry.created_on)) return;

        const session_kv = $journals_sess?.journal_kv[journal?.id];
        const is_decrypted = session_kv?.journal_passcode_decrypted === true;

        // Only sync if saved and not currently processing/editing
        if (save_status === 'saved' && !has_unsaved_changes && !is_processing) {
            // Prevent overwrite of recovered text if we are in a decrypted session
            if (is_decrypted && tmp_entry_obj.content && !entry.content) {
                return;
            }

            const base = deep_copy(entry);
            if (base) {
                base.content = base.content ?? null;
                base.history = base.history ?? null;
                orig_entry_obj = { ...base };
                tmp_entry_obj = { ...base };
            }
        }
    });
});

// 2. Auto-Save Debounce
$effect(() => {
    // Track content and name directly so this effect re-runs on every keystroke,
    // resetting the debounce timer each time (fires 2 s after the LAST change).
    // Tracking has_unsaved_changes ensures the effect also wakes up when changes
    // are cleared (e.g. after a save) so the status indicator resets correctly.
    // All side-effects (save_status writes, $journals_loc reads) stay in untrack
    // to avoid creating reactive loops.
    void tmp_entry_obj.content;
    void tmp_entry_obj.name;
    const changed = has_unsaved_changes;

    clearTimeout(auto_save_timer);

    if (!changed) {
        untrack(() => {
            if (save_status === 'unsaved') save_status = 'saved';
        });
        return;
    }

    untrack(() => {
        if (save_status !== 'saving') save_status = 'unsaved';
    });

    if (!untrack(() => $journals_loc.entry.auto_save)) return;

    auto_save_timer = setTimeout(() => {
        untrack(() => {
            if (has_unsaved_changes && !is_processing && save_status !== 'saving') {
                update_journal_entry();
            }
        });
    }, 2000);
});

// 3. Auto-Decryption Workflow
$effect(() => {
    const journal = $lq__journal_obj;
    const entry = $lq__journal_entry_obj;
    if (!journal?.id || !entry) return;

    // Track session state selectively
    const session = $journals_sess?.journal_kv[journal.id];
    const is_verified = session?.journal_passcode_verified;
    const decrypted_status = session?.journal_passcode_decrypted;
    const has_encrypted_content = !!entry.content_encrypted;

    if (
        has_encrypted_content &&
        is_verified &&
        decrypted_status !== true &&
        decrypted_status !== 'processing'
    ) {
        untrack(() => run_decryption_workflow());
    }
});

// *** Actions

async function run_decryption_workflow() {
    const journal = $lq__journal_obj;
    if (!journal?.id || is_processing) return;

    let journal_key =
        $journals_sess.journal_kv[journal.id]?.typed_journal_passcode;

    is_processing = true;
    decryption_error = null;

    journals_sess.update((s) => {
        if (!s.journal_kv[journal.id]) s.journal_kv[journal.id] = {};
        s.journal_kv[journal.id].journal_passcode_decrypted = 'processing';
        return s;
    });

    const result = await decrypt_journal_entry(
        $lq__journal_entry_obj,
        journal,
        journal_key
    );

    if (!result.success) {
        decryption_error = result.error || 'Decryption failed.';
        journals_sess.update((s) => {
            s.journal_kv[journal.id].journal_passcode_verified = false;
            s.journal_kv[journal.id].journal_passcode_decrypted = false;
            return s;
        });
        is_processing = false;
        return;
    }

    // SUCCESS
    const content =
        typeof result.content === 'string'
            ? result.content
            : await (result.content ?? '');
    tmp_entry_obj.content = content;
    tmp_entry_obj.content_md_html = await handle_marked(content);
    tmp_entry_obj.content_encrypted = null;
    tmp_entry_obj.history_encrypted = null;

    if (orig_entry_obj) {
        orig_entry_obj.content = content;
        orig_entry_obj.content_encrypted = null;
        orig_entry_obj.history_encrypted = null;
    }

    if (result.history) {
        tmp_entry_obj.history = result.history;
        if (orig_entry_obj) orig_entry_obj.history = result.history;
    }

    journals_sess.update((s) => {
        s.journal_kv[journal.id].journal_passcode_decrypted = true;
        return s;
    });
    is_processing = false;
}

async function update_journal_entry(fields_kv: key_val | undefined = undefined) {
    if (!$ae_loc.trusted_access || save_status === 'saving' || is_processing)
        return;

    is_processing = true;
    save_status = 'saving';

    // Use fields_kv if provided (partial update), otherwise use full tmp_entry_obj
    const data_kv: key_val = fields_kv || {
        name: tmp_entry_obj.name,
        content: tmp_entry_obj.content,
        history: tmp_entry_obj.history,
        tags: tmp_entry_obj.tags,
        category_code: tmp_entry_obj.category_code,
        summary: tmp_entry_obj.summary,
        priority: tmp_entry_obj.priority,
        private: tmp_entry_obj.private,
        public: tmp_entry_obj.public,
        personal: tmp_entry_obj.personal,
        professional: tmp_entry_obj.professional,
        alert: tmp_entry_obj.alert,
        alert_msg: tmp_entry_obj.alert_msg,
        hide: tmp_entry_obj.hide,
        enable: tmp_entry_obj.enable,
        sort: tmp_entry_obj.sort,
        group: tmp_entry_obj.group,
        data_json: tmp_entry_obj.data_json,
        archive_on: tmp_entry_obj.archive_on,
        linked_li_json: tmp_entry_obj.linked_li_json
            ? JSON.stringify(tmp_entry_obj.linked_li_json)
            : null
    };

    const decrypt_key = $lq__journal_obj.combined_passcode;

    // Handle encryption logic for content only on full updates
    if (!fields_kv) {
        if (tmp_entry_obj.private) {
            if (tmp_entry_obj.content) {
                const content_to_encrypt =
                    typeof tmp_entry_obj.content === 'string'
                        ? tmp_entry_obj.content
                        : '';
                data_kv.content_encrypted = await ae_util.encrypt_wrapper(
                    content_to_encrypt,
                    decrypt_key
                );
                data_kv.content = null;
            }
        } else {
            data_kv.content_encrypted = null;
            data_kv.history_encrypted = null;
        }
    }

    try {
        const journal_entry_id = $lq__journal_entry_obj?.journal_entry_id;
        if (!journal_entry_id) {
            console.error('Journal entry ID missing for update.');
            return;
        }

        await journals_func.update_ae_obj__journal_entry({
            api_cfg: $ae_api,
            journal_entry_id,
            data_kv: data_kv,
            log_lvl: 1
        });

        // Sync ORIG after save to clear unsaved changes flag
        if (!fields_kv) {
            orig_entry_obj = deep_copy(tmp_entry_obj);
        }
        save_status = 'saved';
    } catch (error) {
        console.error('Update failed:', error);
        save_status = 'unsaved';
    } finally {
        is_processing = false;
    }
}

async function handle_content_decryption() {
    const journal = $lq__journal_obj;
    const entry = $lq__journal_entry_obj;
    if (!journal?.id || !entry || is_processing) return;

    if (entry.content_encrypted && !tmp_entry_obj.content) {
        await run_decryption_workflow();
    } else {
        is_processing = true;
        tmp_entry_obj.content = null;
        tmp_entry_obj.history = null;
        if (orig_entry_obj) {
            orig_entry_obj.content = null;
            orig_entry_obj.history = null;
        }
        journals_sess.update((s) => {
            s.journal_kv[journal.id].journal_passcode_decrypted = false;
            return s;
        });
        is_processing = false;
    }
}

function handle_marked(text: string) {
    if (!text) return '';
    let start_index = 0;
    while (start_index < text.length) {
        const code_point = text.codePointAt(start_index);
        if (
            code_point === 0x200b ||
            code_point === 0x200c ||
            code_point === 0x200d ||
            code_point === 0x200e ||
            code_point === 0x200f ||
            code_point === 0xfeff
        ) {
            start_index += code_point > 0xffff ? 2 : 1;
            continue;
        }

        break;
    }

    return marked.parse(text.slice(start_index));
}

async function handle_force_reset() {
    if (
        !confirm(
            'WARNING: This will permanently DELETE the encrypted content and history for this entry and reset it to plain text. This cannot be undone. Proceed?'
        )
    ) {
        return;
    }

    is_processing = true;
    tmp_entry_obj.private = false;
    tmp_entry_obj.content = '';
    tmp_entry_obj.content_encrypted = null;
    tmp_entry_obj.history = '';
    tmp_entry_obj.history_encrypted = null;

    // Sync orig to match the "cleared" state
    if (orig_entry_obj) {
        orig_entry_obj.private = false;
        orig_entry_obj.content = '';
        orig_entry_obj.content_encrypted = null;
        orig_entry_obj.history = '';
        orig_entry_obj.history_encrypted = null;
    }

    await update_journal_entry();
    is_processing = false;
}

let show_append_modal = $state(false);
let modal_mode: 'append' | 'prepend' | 'auto' = $state('auto');

function handle_show_ai_tools() {
    show_config_modal = false;

    if (typeof window === 'undefined') return;

    const entry_id = $lq__journal_entry_obj?.journal_entry_id ?? 'default';
    const ai_tools_anchor_id = `journal_entry_ai_tools_${entry_id}`;

    queueMicrotask(() => {
        const ai_tools_el = document.getElementById(ai_tools_anchor_id);
        ai_tools_el?.scrollIntoView({ behavior: 'smooth', block: 'center' });
    });
}
</script>

<div class="group/entry-view relative w-full min-w-0">
    <!-- Subtle glow — same technique as the rest of the Journals module -->
    <div
        class="from-primary-500/50 to-secondary-500/50 pointer-events-none absolute -inset-1
               rounded-2xl bg-linear-to-r opacity-5 blur
               transition duration-700
               group-hover/entry-view:opacity-15 dark:opacity-10 dark:group-hover/entry-view:opacity-20">
    </div>
    <section
        class="ae_view border-surface-200-800 bg-surface-50-900 relative flex w-full min-w-0 flex-col
           gap-4 rounded-xl
           border p-2 shadow-xl"
        bind:clientHeight={$ae_loc.iframe_height_modal_body}>
        {#if $lq__journal_entry_obj && $lq__journal_obj}
            <AE_Comp_Journal_Entry_Header
                entry={$lq__journal_entry_obj}
                journal={$lq__journal_obj}
                journals_li={$lq__journal_obj_li}
                bind:tmp_entry_obj
                has_changed={has_unsaved_changes}
                on_save={() => update_journal_entry()}
                on_decrypt={handle_content_decryption}
                on_show_config={() => (show_config_modal = true)}
                {save_status}
                {log_lvl} />

            <div class="w-full min-w-0 space-y-4">
                {#if decryption_error}
                    <div
                        class="bg-error-100 border-error-300 flex w-full animate-bounce items-center justify-between rounded-lg border p-4 shadow-xl">
                        <div
                            class="text-error-700 flex items-center gap-4 font-bold">
                            <CircleAlert size="2.5em" />
                            <span class="text-xl">{decryption_error}</span>
                        </div>
                        <button
                            type="button"
                            class="btn btn-sm preset-tonal-error hover:preset-filled-error-500 font-bold"
                            onclick={() => (decryption_error = null)}>
                            <CircleX size="1.2em" class="mr-2" /> Dismiss
                        </button>
                    </div>
                {/if}

                <!-- ring-2 inset indicates "edit mode" in both light and dark without a background swap -->
                <section
                    class="border-surface-200-800 bg-surface-100-900 relative min-w-0 grow overflow-hidden
                       rounded-xl border p-2 shadow-md
                       {$journals_loc.entry.edit_kv[
                        $lq__journal_entry_obj?.journal_entry_id
                    ] == 'current'
                        ? 'ring-primary-500/40 ring-2 ring-inset'
                        : ''}">
                    {#if $ae_loc.edit_mode && $journals_loc.entry.edit_kv[$lq__journal_entry_obj?.journal_entry_id] === 'current'}
                        <div
                            id={`journal_entry_ai_tools_${$lq__journal_entry_obj?.journal_entry_id ?? 'default'}`}>
                            <AE_Comp_Journal_Entry_AiTools
                                content={typeof tmp_entry_obj.content === 'string'
                                    ? tmp_entry_obj.content
                                    : ''}
                                bind:summary={tmp_entry_obj.summary}
                                on_save={() => update_journal_entry()}
                                {log_lvl} />
                        </div>
                    {/if}

                    <AE_Comp_Journal_Entry_Editor
                        entry={$lq__journal_entry_obj}
                        journal={$lq__journal_obj}
                        bind:tmp_entry_obj
                        bind:editor_view
                        has_changed={has_unsaved_changes}
                        updated_idb={false}
                        on_save={() => update_journal_entry()}
                        on_force_reset={handle_force_reset} />
                </section>

                <AE_Comp_Journal_Entry_ObjFileLi
                    {log_lvl}
                    link_to_type="journal_entry"
                    link_to_id={$lq__journal_entry_obj.journal_entry_id}
                    {lq__journal_entry_obj} />

                <div
                    class="border-surface-200-800 bg-surface-100-900 rounded-xl border p-3 shadow-sm">
                    <AE_Comp_Journal_Entry_Metadata
                        entry={$lq__journal_entry_obj} />
                </div>
            </div>

            <AE_Comp_Modal_Journal_Entry_Append
                bind:open={show_append_modal}
                journal_entry={$lq__journal_entry_obj}
                journal_config={$lq__journal_obj?.cfg_json}
                mode={modal_mode}
                on_close={() => (show_append_modal = false)}
                on_update={() => {
                    show_append_modal = false;
                }}
                {log_lvl} />

            <AE_Comp_Modal_Journal_Entry_Config
                bind:show={show_config_modal}
                journal={$lq__journal_obj}
                bind:tmp_entry_obj
                on_save={() => update_journal_entry()}
                on_force_reset={handle_force_reset}
                {on_show_export}
                on_show_ai={handle_show_ai_tools}
                on_append={() => {
                    modal_mode = 'append';
                    show_append_modal = true;
                }}
                on_prepend={() => {
                    modal_mode = 'prepend';
                    show_append_modal = true;
                }}
                {log_lvl} />
        {:else}
            <div
                class="flex flex-col items-center gap-4 p-20 text-center opacity-50">
                <LoaderCircle class="animate-spin" size="4em" />
                <span class="text-2xl font-bold">Loading Journal Entry...</span>
            </div>
        {/if}
    </section>
</div>
