<script lang="ts">
    interface Props {
        log_lvl?: number;
        api_cfg?: key_val;
        // export let api_crud_super_key: null|string = api_cfg.api_crud_super_key;

        trigger_patch?: any;
        patch_status?: string; // '', processing, complete, error
        patch_complete?: boolean | null | string; // null = not started, true = complete/success, false = error
        patch_result?: boolean | null | key_val; // Result of the patch operation

        object_type: string;
        object_id: string;
        object_reload?: boolean;

        field_name: string;
        field_type?: string; // button, text, textarea, template (older method), select (in progress method)

        previous_field_value?: any;
        current_field_value?: any;
        new_field_value?: any;

        allow_null?: boolean;
        select_option_kv?: key_val;
        val_empty_is_null?: boolean; // This was added to help with a select option list. If the value is empty (''), it will be set to null.

        edit_label?: string;
        display_block?: boolean; // If true, the element will be displayed as a block element.
        // display_inline?: boolean;
        display_absolute_edit?: boolean; // If true, the edit form will be displayed in the top right corner of the element.
        // display_block_edit?: boolean;
        textarea_cols?: number;
        textarea_rows?: number;

        // export let input_field_template: null|object = null;

        hide_element?: boolean; // This hides the entire custom element.
        hide_edit_btn?: boolean; // This only hides the edit button.
        // hide_edit_form?: boolean;
        show_edit_form?: boolean; // This is used if the parent needs to make the edit form visible.

        outline_element?: boolean;

        btn_label?: any; // '<span class="fas fa-check mx-1"></span> Save'; // PATCH
        // export let remove_breaks = false;
        class_li?: string;
        children?: import('svelte').Snippet;
    }

    let {
        log_lvl = 0,
        api_cfg = { api_crud_super_key: null },

        trigger_patch = null,
        patch_status = '',
        patch_complete = $bindable(null), // null = not started, true = complete/success, false = error
        patch_result = null,

        object_type,
        object_id,
        object_reload = false,

        field_name,
        field_type = 'text',

        previous_field_value = $bindable(null),
        current_field_value = null,
        new_field_value = current_field_value,

        allow_null = false,
        select_option_kv = $bindable({}),
        val_empty_is_null = false, // If the value is empty (''), it will be set to null.

        edit_label = 'Edit',
        display_block = false,
        // display_inline = false,
        display_absolute_edit = false,
        // display_block_edit = false,
        textarea_cols = 80,
        textarea_rows = 5,

        hide_element = $bindable(false),
        hide_edit_btn = false,
        // hide_edit_form = $bindable(true),
        show_edit_form = $bindable(),

        outline_element = $bindable(false),

        btn_label = null,
        class_li = '',
        children
    }: Props = $props();

    // *** Import Svelte core
    import { browser } from '$app/environment';

    // *** Import Aether core variables and functions
    import type { key_val } from '$lib/stores/ae_stores';
    // import { api } from '$lib/api';
    import { core_func } from '$lib/ae_core/ae_core_functions';
    // import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';

    // *** Import Aether core components
    import AE_Comp_Editor_TipTap from '$lib/elements/AE_Comp_Editor_TipTap.svelte';

    // *** Import Aether module variables and functions
    // *** Import Aether module components

    // export let show_field_name = true;
    // export let show_original_value = true;
    // export let trim_string = false;

    // *** Set initial variables
    let ae_promises: key_val = $state({}); // Promise<any>;
    // let patch_result: null|Promise<any>|key_val|string = $state();

    $effect(() => {
        if (browser) {
            if (log_lvl) {
                console.log(
                    `Element AE CRUD: Object Type: ${object_type}; Object ID: ${object_id}; Field Name: ${field_name}; New Field Value: ${new_field_value} (Current: ${current_field_value})`
                );
                // ; Super Key: ${api_crud_super_key}
            }
        }

        // if (select_option_kv) {
        //     console.log(select_option_kv);
        // }

        if (trigger_patch === true) {
            if (log_lvl) {
                console.log('AE CRUD: Patch triggered by trigger_patch = true');
            }
            trigger_patch = null;
            handle_obj_field_patch(new_field_value);

            // if (new_field_value !== current_field_value) {
            //     if (log_lvl > 1) {
            //         console.log(`AE CRUD: field_value changed from ${current_field_value} to ${new_field_value}`);
            //     }
            // }
        }
    });

    // Updated 2024-03-22
    async function handle_obj_field_patch(new_field_value: any) {
        if (log_lvl) {
            console.log(
                `AE CRUD: Patching Object Type: ${object_type}; Object ID: ${object_id}; Field Name: ${field_name}; New Field Value: ${new_field_value}; Current Field Value: ${current_field_value}`
            );
            // ; Super Key: ${api_crud_super_key}
        }

        patch_status = 'Processing...';
        patch_complete = null;
        patch_result = null;

        // This was added to help with a select option list. If the value is empty (''), it will be set to null.
        if (val_empty_is_null && new_field_value == '') {
            new_field_value = null;
        }

        // NOTE: Is this needed? The field_name, field_value, and fields parameters for update_ae_obj_id_crud() already take care of the data portion. They are added to data_list object as part of the JSON request.
        // NOTE: Currently this only handles one field and value at a time. This may need to be changed in the future to use the "fields" parameter as well.
        // let patch_data = {}

        // if (remove_breaks) {
        //     patch_data['field_value'] = field_value.replace(/(\r\n|\n|\r)/gm, "");
        // } else {
        //     patch_data['field_value'] = field_value;
        // }

        // patch_data[field_name] = field_value;
        // console.log(patch_data);

        // let params = {};

        ae_promises.api_update__ae_obj = core_func
            .update_ae_obj_id_crud_v2({
                api_cfg: api_cfg,
                object_type: object_type,
                object_id: object_id,
                object_reload: object_reload,
                field_name: field_name,
                new_field_value: new_field_value,
                log_lvl: log_lvl
            })
            .then(function (results) {
                // console.log('Field PATCH Promise', results);

                if (results) {
                    // console.log(`Patched - Field Name: ${field_name} with New Field Value: ${new_field_value}; Original Field Value: ${current_field_value}`);
                    patch_status = 'PATCH complete';
                    current_field_value = new_field_value;
                } else {
                    console.log(
                        `Not Patched - Field Name: ${field_name} with New Field Value: ${new_field_value}; Original Field Value: ${current_field_value}`
                    );
                    patch_status = 'PATCH failed';
                    return false;
                }
                return true;
            })
            .catch(function (error: any) {
                patch_status = 'Error during PATCH';
                console.log('Something went wrong patching the record.');
                console.log(error);
                return false;
            })
            .finally(function () {
                // console.log('Field PATCH Promise finally');
                if (patch_status != 'PATCH complete') {
                    patch_status = 'Error during PATCH';
                    patch_complete = false;
                    patch_result = false;
                } else {
                    // patch_complete = true;
                    patch_complete = object_id; // Return the object ID that was patched
                    patch_result = {
                        type: object_type,
                        id: object_id,
                        field_name: field_name,
                        field_value: new_field_value,
                        original_value: current_field_value
                    };
                }
            });

        return ae_promises.api_update__ae_obj;
    }
</script>

<!-- relative -->
<div
    class="{class_li} ae_crud
        font-normal
        transition-all duration-300 ease-in-out
        relative
        "
    class:hidden={hide_element}
    class:block={display_block}
    class:inline-block={!display_block}
    class:outline_element
>
    {@render children?.()}

    <span
        class="field_viewing_wrapper
            "
    >
        <!-- {@render children?.()} -->

        <button
            type="button"
            class:hidden={show_edit_form || hide_edit_btn}
            class="
                btn btn-icon
                text-xs
                m-0 px-0.5
                preset-tonal-warning hover:preset-tonal-error
                preset-outlined-warning-100-900 hover:preset-outlined-warning-600-400
                opacity-50 hover:opacity-100
                transition-all
                "
            ondblclick={() => {
                // hide_edit_btn = true;
                // hide_edit_form = false;
                show_edit_form = true;
            }}
            title="Double click to edit property"
        >
            <span class="fas fa-edit m-0 p-0"></span>
            <span class="hidden">Edit</span>
        </button>
    </span>

    <!-- class:display_block={display_block} -->
    <div
        class:hidden={!show_edit_form}
        class:absolute={display_absolute_edit}
        class:top-0={display_absolute_edit}
        class:right-0={display_absolute_edit}
        class:drop-shadow-2xl={display_absolute_edit}
        class="field_editing_wrapper_v2
            border-2 border-dashed hover:border-solid
            border-pink-400 dark:border-pink-600
            rounded-md
            min-w-fit w-full max-w-fit
            z-20
            p-1 m-0
            bg-pink-50/90 dark:bg-pink-900/90
            hover:bg-pink-50 hover:dark:bg-pink-900

            flex flex-col md:flex-row flex-wrap gap-1
            items-center justify-center
            space-y-2
            transition-all duration-300 ease-in-out
            "
    >
        <span class="grow flex flex-row items-center justify-between">
            <span class="hidden md:inline font-semibold text-lg">
                {edit_label}
            </span>

            <button
                type="button"
                class="btn btn-md ae_btn_surface_outlined m-1"
                onclick={() => {
                    // hide_edit_btn = false;
                    // hide_edit_form = true;
                    show_edit_form = false;
                }}
                title="Close field editing. This does not save any changes."
            >
                <span class="fas fa-window-close"></span>
                <span class="hidden sm:inline">Close</span>
            </button>
        </span>

        <span>
            New value: {new_field_value}
        </span>

        <span
            class="field_value
                grow
                min-w-fit w-full max-w-fit
                flex flex-row flex-wrap items-center justify-center gap-1
                "
        >
            {#if field_type == 'template'}
                <!-- <Element_input_v2 {...input_field_template} bind:value={field_value} /> -->
            {:else if field_type == 'button'}
                <!-- <input type="button" bind:value={field_value}> -->
                {new_field_value}
            {:else if field_type == 'select'}
                <select
                    bind:value={new_field_value}
                    class="
                    select
                    p-1
                    min-w-fit w-full
                    border border-gray-300 dark:border-gray-600
                    "
                >
                    {#if select_option_kv && Object.keys(select_option_kv).length == 0}
                        <option value="">-- not set --</option>
                    {:else if select_option_kv && Object.keys(select_option_kv).length > 0}
                        {#each Object.keys(select_option_kv) as option (option)}
                            <option value={option}>{select_option_kv[option]} {option}</option>
                        {/each}
                    {:else}
                        <option value="">-- no list --</option>
                    {/if}
                </select>
            {:else if field_type == 'text'}
                <input
                    bind:value={new_field_value}
                    class="input ae_btn_surface min-w-64 w-96 max-w-full"
                />
            {:else if field_type == 'textarea'}
                <textarea
                    bind:value={new_field_value}
                    cols={textarea_cols}
                    rows={textarea_rows}
                    class="textarea"
                ></textarea>
            {:else if field_type == 'tiptap'}
                <div class="w-full min-w-96 text-left">
                    <AE_Comp_Editor_TipTap 
                        bind:content={new_field_value} 
                        placeholder="Start typing..."
                    />
                </div>
            {:else}
                <input bind:value={new_field_value} class="input w-fit" />
            {/if}
            {#if allow_null}
                <button
                    class="btn btn-sm ae_btn_warning m-1"
                    onclick={() => {
                        new_field_value = null;
                    }}
                    title="Set value to NULL"
                >
                    Ø NULL
                </button>
            {/if}
        </span>

        <button
            class="
                ae_btn_warning_outlined
                btn btn-lg
                m-1
                "
            disabled={new_field_value === current_field_value}
            onclick={async () => {
                handle_obj_field_patch(new_field_value);
            }}
            title="Save new field value"
        >
            {#if new_field_value === current_field_value}
                {#if btn_label}
                    {@html btn_label}
                {:else}
                    <span class="fas fa-check mx-1"></span>
                    <span>Save</span>
                {/if}
                <!-- <span>{patch_result}</span> -->
            {:else if btn_label}
                {@html btn_label}
            {:else}
                <span class="fas fa-save mx-1"></span>
                <span>Save</span>
            {/if}
        </button>

        <div class="field_patch_result" class:hidden={!patch_status}>
            {#await ae_promises.api_update__ae_obj}
                <span class="fas fa-spinner fa-spin mx-1"></span>
                <span>Processing...</span>
            {:then}
                {#if patch_status}
                    <span class="fas fa-check mx-1"></span>
                    <span>{patch_status}</span>
                {:else}
                    <!-- <div>Nothing to show yet...</div> -->
                {/if}
            {/await}
        </div>
    </div>
</div>

<style>
    .ae_crud.outline_element .field_viewing_wrapper {
        outline: dotted thin hsla(0, 50%, 50%, 0);
        transition: outline 3s 1s;
    }
    .ae_crud.outline_element .field_viewing_wrapper:hover {
        outline: dashed thin hsla(0, 50%, 50%, 0.9);
        transition: outline 1s 0.5s;
    }

    .ae_crud .field_viewing_wrapper {
        margin: 0;
        padding: 0;

        /* color: hsla(0,0%,50%,.8); */
        opacity: 0.25;

        /* NOTE: transition when hover ends */
        transition-property: opacity, background-color, border-color, color, height, width;
        transition-delay: 1s; /* no delay */
        transition-duration: 0.55s;
        transition-timing-function: linear;
    }

    .ae_crud .field_viewing_wrapper:hover {
        /* outline: solid thin hsla(0,50%,50%,.9); */
        /* color: hsla(0,50%,50%,.9); */

        opacity: 1;

        /* NOTE: transition when hover starts */
        transition-property: opacity, background-color, border-color, color, height, width;
        transition-delay: 0.25s; /* no delay */
        transition-duration: 0.5s;
        transition-timing-function: linear;
    }

    .ae_crud .field_editing_wrapper {
        /* outline: dashed thin pink; */

        /* position: relative; */

        /* contain: layout; */
        /* contain: size; */
        /* contain: none; */
        contain: content;

        box-shadow: 0.5em 0.5em 0.75em 0.75em hsla(0, 0%, 0%, 0.5);

        /* color: hsla(0,0%,50%,.8); */
        /* background-color: hsla(0,0%,50%,.5); */
        /* border: dashed thin transparent; */

        /* background-color: yellow; */
        background-color: hsla(60, 50%, 80%, 0.95);
        border: solid thin hsla(0, 50%, 50%, 0.5);
        border-radius: 0.5em;

        height: auto;
        /* height: 100%; */
        max-height: 100%;

        min-width: fit-content;
        width: auto;
        max-width: 100%;

        /* font-size: 1em; */
        /* line-height: 1em; */

        /* NOTE: transition when hover ends */
        transition-property: background-color, border-color, color, height, width;
        transition-delay: 0.75s; /* short delay */
        transition-duration: 0.5s;
        transition-timing-function: linear;

        z-index: 1;

        padding: 0.5em;
    }

    .ae_crud.show_crud.display_inline .field_editing_wrapper:hover {
        background-color: hsla(60, 60%, 90%, 0.8);
        z-index: 55;
    }

    .ae_crud.show_crud.display_inline .field_editing_wrapper {
        /* display: block; */
        display: inline-block;
        /* display: inline; */

        box-shadow: initial;
        background-color: hsla(60, 50%, 80%, 0.4);

        padding: 0.25em;

        position: initial;

        z-index: 0;

        display: flex;
        flex-direction: row;
        justify-content: center;
        align-items: center;
        gap: 0.5em;

        width: 30%;
    }

    .ae_crud.show_crud.display_inline .field_editing_wrapper.display_block_edit {
        /* display: block; */

        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        gap: 0.5em;

        flex-grow: 1;

        height: auto;
        width: 100%;
    }

    .ae_crud textarea {
        height: auto;
    }
    /* END: Svelte CRUD (update) component  */
</style>
