<script lang="ts">
// import { browser } from '$app/environment';
import { untrack } from 'svelte';
import type { Snippet } from 'svelte';
import {
    Check,
    CircleAlert,
    LoaderCircle,
    Save,
    SquarePen,
    Trash2,
    X
} from '@lucide/svelte';
import type { key_val } from '$lib/stores/ae_stores';
import { ae_api, ae_loc } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import AE_Comp_Editor_TipTap from '$lib/elements/element_editor_tiptap.svelte';

interface Props {
    // Core Identifiers
    id?: string;
    object_type: string;
    object_id: string;
    field_name: string;

    // Value Handling
    current_value: any;
    field_type?:
        | 'text'
        | 'textarea'
        | 'select'
        | 'tiptap'
        | 'checkbox'
        | 'date'
        | 'datetime'
        | 'number';
    allow_null?: boolean;

    // Select Options
    select_options?: key_val; // { value: label }

    // UI Configuration
    edit_label?: string;
    display_block?: boolean;
    display_absolute_edit?: boolean;
    placeholder?: string;
    class_li?: string;
    textarea_rows?: number;

    // Behavior
    object_reload?: boolean; // SWR pattern
    log_lvl?: number;

    // Callbacks
    on_success?: (data: any) => void;
    on_error?: (error: any) => void;

    // Snippets
    children?: Snippet;
}

let {
    id,
    object_type,
    object_id,
    field_name,
    current_value = $bindable(),
    field_type = 'text',
    allow_null = false,
    select_options = {},
    edit_label = 'Edit Field',
    display_block = false,
    display_absolute_edit = false,
    placeholder = 'Enter value...',
    class_li = '',
    textarea_rows = 4,
    object_reload = true,
    log_lvl = 0,
    on_success,
    on_error,
    children
}: Props = $props();

// Internal State
let is_editing = $state(false);
let patch_status = $state<'idle' | 'processing' | 'success' | 'error'>('idle');
let error_message = $state('');
let draft_value = $state(current_value);

// WHY: Optimistic display. After a successful PATCH, liveQuery may not fire
// immediately (or at all if on_success doesn't trigger a Dexie refresh). We show
// draft_value as the display until current_value catches up from liveQuery.
let has_optimistic = $state(false);
let display_value = $derived(has_optimistic ? draft_value : current_value);

// Sync draft with display_value when not editing.
// Suppress reset if optimistic is active — we already have the right value.
$effect(() => {
    if (!is_editing) {
        untrack(() => {
            if (!has_optimistic) {
                draft_value = current_value;
            }
        });
    }
});

// Clear optimistic once liveQuery catches up (current_value matches what we saved)
$effect(() => {
    if (has_optimistic && current_value === draft_value) {
        has_optimistic = false;
    }
});

async function handle_patch() {
    if (log_lvl)
        console.log(
            `AE Field Editor V3: Patching ${object_type}.${field_name}...`
        );

    patch_status = 'processing';
    error_message = '';

    try {
        const result = await api.update_ae_obj({
            api_cfg: $ae_api,
            obj_type: object_type,
            obj_id: object_id,
            fields: {
                [field_name]: draft_value
            },
            log_lvl
        });

        if (result) {
            patch_status = 'success';
            has_optimistic = true; // show draft_value immediately; cleared when liveQuery catches up
            if (on_success) on_success(result);

            // Close edit mode after a brief success indicator
            setTimeout(() => {
                if (patch_status === 'success') {
                    patch_status = 'idle';
                    is_editing = false;
                }
            }, 1000);
        } else {
            throw new Error('No data returned from update.');
        }
    } catch (error: any) {
        console.error('AE Field Editor V3: Patch failed.', error);
        patch_status = 'error';
        error_message = error?.message || 'Update failed.';
        if (on_error) on_error(error);
    }
}

function cancel_edit() {
    has_optimistic = false;
    draft_value = current_value;
    is_editing = false;
    patch_status = 'idle';
    error_message = '';
}

function toggle_edit() {
    if (is_editing) cancel_edit();
    else {
        has_optimistic = false; // clear optimistic so draft syncs from current prop
        draft_value = current_value;
        is_editing = true;
    }
}
</script>

<div
    class="ae_field_editor group relative {class_li}"
    class:block={display_block}
    class:inline-block={!display_block}>
    <!-- VIEW MODE -->
    <div class="view_wrapper flex items-center gap-2" class:hidden={is_editing}>
        <div class="content_render grow">
            {#if children}
                {@render children()}
            {:else if field_type === 'checkbox'}
                <span
                    class="badge {display_value
                        ? 'variant-filled-success'
                        : 'variant-soft-surface'}">
                    {display_value ? 'True' : 'False'}
                </span>
            {:else if field_type === 'tiptap'}
                <div class="prose dark:prose-invert max-w-none">
                    {@html display_value ||
                        '<span class="opacity-50 italic">Empty</span>'}
                </div>
            {:else}
                <span class:opacity-50={!display_value}>
                    {display_value || 'Not set'}
                </span>
            {/if}
        </div>

        <!-- Edit Trigger (Visible on Hover or Edit Mode) -->
        <!-- WHY: Always render to avoid layout shift when edit_mode toggles.
             Use invisible (visibility:hidden, preserves space) when edit_mode is off. -->
        <button
            type="button"
            class="btn-icon btn-icon-sm variant-soft-warning opacity-20 transition-opacity hover:opacity-100"
            class:invisible={!$ae_loc.edit_mode}
            class:pointer-events-none={!$ae_loc.edit_mode}
            onclick={toggle_edit}
            title="Edit {field_name}">
            <SquarePen size="14" />
        </button>
    </div>

    <!-- EDIT MODE -->
    {#if is_editing}
        <div
            class="edit_wrapper border-warning-500/50 bg-surface-50-950 z-50 rounded-lg border-2 border-dashed p-3 shadow-xl"
            class:absolute={display_absolute_edit}
            class:top-0={display_absolute_edit}
            class:left-0={display_absolute_edit}
            class:w-full={display_absolute_edit}>
            <header class="mb-2 flex items-center justify-between">
                <span
                    class="text-xs font-bold tracking-wider uppercase opacity-60"
                    >{edit_label || field_name}</span>
                <div class="flex gap-1">
                    <button
                        type="button"
                        class="btn-icon btn-icon-sm variant-soft-surface"
                        onclick={cancel_edit}
                        disabled={patch_status === 'processing'}>
                        <X size="14" />
                    </button>
                </div>
            </header>

            <div class="input_container mb-3">
                {#if field_type === 'textarea'}
                    <textarea
                        bind:value={draft_value}
                        rows={textarea_rows}
                        class="textarea"
                        {placeholder}></textarea>
                {:else if field_type === 'select'}
                    <select bind:value={draft_value} class="select">
                        {#if allow_null}
                            <option value={null}>-- None --</option>
                        {/if}
                        {#each Object.entries(select_options) as [val, label] (val)}
                            <option value={val}>{label}</option>
                        {/each}
                    </select>
                {:else if field_type === 'checkbox'}
                    <label class="flex items-center space-x-2">
                        <input
                            type="checkbox"
                            bind:checked={draft_value}
                            class="checkbox" />
                        <span>{draft_value ? 'True' : 'False'}</span>
                    </label>
                {:else if field_type === 'tiptap'}
                    <AE_Comp_Editor_TipTap
                        bind:content={draft_value}
                        {placeholder} />
                {:else if field_type === 'date'}
                    <input type="date" bind:value={draft_value} class="input" />
                {:else if field_type === 'datetime'}
                    <input
                        type="datetime-local"
                        bind:value={draft_value}
                        class="input" />
                {:else if field_type === 'number'}
                    <input
                        type="number"
                        bind:value={draft_value}
                        class="input"
                        {placeholder}
                        onkeydown={(e) =>
                            e.key === 'Enter' && handle_patch()} />
                {:else}
                    <input
                        type="text"
                        bind:value={draft_value}
                        class="input"
                        {placeholder}
                        onkeydown={(e) =>
                            e.key === 'Enter' && handle_patch()} />
                {/if}
            </div>

            <footer class="flex items-center justify-between">
                <div class="status_indicator text-xs">
                    {#if patch_status === 'processing'}
                        <span class="text-primary-500 flex items-center gap-1">
                            <LoaderCircle size="12" class="animate-spin" /> Saving...
                        </span>
                    {:else if patch_status === 'success'}
                        <span class="text-success-500 flex items-center gap-1">
                            <Check size="12" /> Saved
                        </span>
                    {:else if patch_status === 'error'}
                        <span
                            class="text-error-500 flex items-center gap-1"
                            title={error_message}>
                            <CircleAlert size="12" /> Error
                        </span>
                    {/if}
                </div>

                <div class="actions flex gap-2">
                    {#if allow_null && draft_value !== null}
                        <button
                            type="button"
                            class="btn btn-sm variant-soft-error"
                            onclick={() => (draft_value = null)}>
                            Set Null
                        </button>
                    {/if}
                    <button
                        type="button"
                        class="btn btn-sm variant-filled-primary"
                        onclick={handle_patch}
                        disabled={patch_status === 'processing' ||
                            draft_value === display_value}>
                        {#if patch_status === 'processing'}
                            <LoaderCircle size="14" class="mr-1 animate-spin" />
                        {:else}
                            <Save size="14" class="mr-1" />
                        {/if}
                        Save
                    </button>
                </div>
            </footer>
        </div>
    {/if}
</div>

<style>
/* Add any specialized transitions if needed */
.ae_field_editor :global(.btn-icon-sm) {
    width: 24px;
    height: 24px;
}
</style>
