<script lang="ts">
    /**
     * src/routes/events/ae_comp__event_files_upload.svelte
     * Specialized component for uploading files and automatically linking them to Event objects.
     */
    import { LoaderCircle, Upload, UploadCloud } from 'lucide-svelte';
    import Element_input_files_tbl from '$lib/elements/element_input_files_tbl.svelte';

    // Import storage, functions, and libraries
    import type { key_val } from '$lib/stores/ae_stores';
    import { api } from '$lib/api/api';
    import {
        ae_loc,
        ae_sess,
        ae_api,
        ae_trig,
        slct,
        slct_trigger
    } from '$lib/stores/ae_stores';
    import {
        events_loc,
        events_sess,
        events_slct,
        events_trig
    } from '$lib/stores/ae_events_stores';
    import { events_func } from '$lib/ae_events_functions';
    import { db_events } from '$lib/ae_events/db_events';

    interface Props {
        log_lvl?: number;
        // Expecting these for link_to_type: 'event', 'event_location', 'event_presentation', 'event_presenter', 'event_session'
        link_to_type: string;
        link_to_id: string;
        input_name?: string;
        multiple?: boolean;
        required?: boolean;
        accept?: string;
        class_li_default?: string;
        class_li?: string;
        input_class_li?: string[];
        table_class_li?: string[];
        upload_complete?: boolean;
        submit_status?: null | string;
        label?: import('svelte').Snippet;
    }

    let {
        log_lvl = $bindable(0),
        link_to_type,
        link_to_id,
        input_name = 'file_list',
        multiple = true,
        required = true,
        accept = 'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh',
        class_li_default = 'flex flex-col gap-1 items-center justify-center w-full max-w-2xl mx-auto my-1',
        class_li = '',
        input_class_li = ['file_drop_area'],
        table_class_li = ['table', 'table-sm', 'table-striped', '', 'text-sm'],
        upload_complete = $bindable(false),
        submit_status = $bindable(null),
        label
    }: Props = $props();

    // Local Variables
    let task_id: string = $state('');
    let input_file_list: any = $state(null);
    let ae_promises: key_val = $state({});
    let input_element_id = 'ae_comp__event_files_upload__input';

    // WHY: Keep task_id in sync with prop if it hasn't been set by an upload cycle yet
    $effect(() => {
        if (!ae_promises.upload__hosted_file_obj) {
            task_id = link_to_id;
        }
    });

    function prevent_default<T extends Event>(fn: (event: T) => void) {
        return function (event: T) {
            event.preventDefault();
            fn(event);
        };
    }

    async function handle_submit_form_files(event: SubmitEvent) {
        if (log_lvl) console.log('*** handle_submit_form() ***');

        $events_sess.files.disable_submit__event_file_obj = true;
        $events_sess.files.submit_status = 'saving';
        submit_status = 'saving';
        upload_complete = false;

        const target = event.currentTarget as HTMLFormElement;
        const file_input = target
            ? (target[input_element_id] as HTMLInputElement)
            : null;

        if (file_input && file_input.files && file_input.files.length > 0) {
            // Sequential upload to provide reliable progress and avoid server race conditions
            for (let i = 0; i < file_input.files.length; i++) {
                const tmp_file = file_input.files[i];
                task_id = $events_sess.files.processed_file_list[i].hash_sha256;

                await handle_input_upload_files({
                    input_upload_files: [tmp_file],
                    task_id: task_id
                });
            }

            // Cleanup after batch
            $events_sess.files.processed_file_list = [];
            target.reset();

            // Refresh Local Cache (Optimistic Revalidation)
            await db_events.file.clear();
            events_func.load_ae_obj_li__event_file({
                api_cfg: $ae_api,
                for_obj_type: link_to_type,
                for_obj_id: link_to_id,
                enabled: 'all',
                hidden: 'all',
                try_cache: true
            });
        }

        $events_sess.files.disable_submit__event_file_obj = false;
        $events_sess.files.submit_status = 'saved';
        submit_status = 'saved';
        upload_complete = true;
    }

    async function handle_input_upload_files({
        input_upload_files,
        task_id
    }: {
        input_upload_files: any[];
        task_id: string;
    }) {
        if (log_lvl)
            console.log(
                `*** handle_input_upload_files() *** task_id = ${task_id}`
            );

        const form_data = new FormData();
        form_data.append('account_id', $ae_loc.account_id);
        form_data.append('link_to_type', link_to_type);
        form_data.append('link_to_id', link_to_id);

        for (let i = 0; i < input_upload_files.length; i++) {
            form_data.append(`file_list`, input_upload_files[i]);
        }

        // STEP 1: Upload to Hosted Files
        ae_promises.upload__hosted_file_obj = api
            .post_object({
                api_cfg: $ae_api,
                endpoint: '/hosted_file/upload_files',
                form_data: form_data,
                task_id: task_id,
                log_lvl: log_lvl
            })
            .then(async function (result) {
                // WARNING: endpoint returns a list, we sequentially handle one at a time.
                const hosted_file_obj = result[0];
                const hosted_file_id = hosted_file_obj.hosted_file_id;

                const event_file_data: key_val = {
                    hosted_file_id: hosted_file_id,
                    for_type: link_to_type,
                    for_id: link_to_id,
                    filename: hosted_file_obj.filename,
                    extension: hosted_file_obj.extension,
                    enable: true
                };

                // STEP 2: Create Event File Link
                return await events_func.create_event_file_obj_from_hosted_file_async(
                    {
                        api_cfg: $ae_api,
                        hosted_file_id: hosted_file_id,
                        data: event_file_data,
                        log_lvl: log_lvl
                    }
                );
            })
            .catch(function (error: any) {
                console.error('Upload Process Failed:', error);
                return false;
            })
            .finally(function () {
                $slct_trigger = 'load__event_file_obj_li';
            });

        return ae_promises.upload__hosted_file_obj;
    }
</script>

<form
    onsubmit={prevent_default(handle_submit_form_files)}
    class="{class_li_default} {class_li}"
>
    {#await ae_promises.upload__hosted_file_obj}
        <div class="text-lg flex flex-row gap-1 items-center justify-center">
            <LoaderCircle class="animate-spin m-1" />
            <span class="">
                Uploading
                {#if $ae_sess.api_upload_kv[task_id]}
                    {$ae_sess.api_upload_kv[task_id].percent_completed}%
                {/if}
            </span>
        </div>
    {/await}

    <div
        class="
            border-2 hover:border-2 border-dashed border-primary-500
            p-1 w-full rounded-lg
            preset-filled-primary-50-950 hover:border-primary-800
            cursor-pointer transition-colors
            "
    >
        <label
            for={input_element_id}
            class="
            svelte_input_file_label
            text-center
            cursor-pointer
            "
            class:hidden={$events_sess.files.disable_submit__event_file_obj}
        >
            {#if label}{@render label()}{:else}
                <div class="flex items-center justify-center gap-2 mb-2 pt-2">
                    <Upload class="text-primary-500" />
                    <strong class="preset-tonal-primary px-3 py-1 rounded-full"
                        >Select Files</strong
                    >
                </div>
                <div
                    class="text-sm text-gray-600 dark:text-gray-400 italic pb-2"
                >
                    <strong>Presentation materials only</strong><br />
                    (PPTX, Keynote, PDF, MP4, etc)
                </div>
            {/if}
        </label>

        <input
            id={input_element_id}
            type="file"
            bind:files={input_file_list}
            {multiple}
            {required}
            {accept}
            name={input_name}
            class:hidden={$events_sess.files.disable_submit__event_file_obj}
            class="
            svelte_input_file_element file-dropzone-input
            block w-full text-lg text-center
            rounded-lg
            cursor-pointer
            p-1
            preset-tonal-primary preset-outlined-primary-200-800 hover:preset-filled-success-200-800
            transition-all
            {input_class_li.join(' ')}
            "
        />
    </div>

    <Element_input_files_tbl
        bind:input_file_list
        bind:file_list_status={$events_sess.files.status__file_list}
        bind:processed_file_list={$events_sess.files.processed_file_list}
        {table_class_li}
    />

    <button
        type="submit"
        class="
            btn btn-lg
            text-lg
            preset-tonal-primary border border-primary-500 hover:preset-tonal-success hover:border-success-500
            flex items-center justify-center
            w-54
            transition-all
            "
        disabled={$events_sess.files.disable_submit__event_file_obj ||
            $events_sess.files.status__file_list != 'ready'}
    >
        {#await ae_promises.upload__hosted_file_obj}
            <LoaderCircle class="animate-spin m-1" />
            <span class="">
                {#if $ae_sess.api_upload_kv[task_id]}
                    {$ae_sess.api_upload_kv[task_id].percent_completed}%
                {:else}
                    ...
                {/if}
            </span>
        {:then}
            <UploadCloud class="m-1" size={20} />
            <span class="text-sm"> Upload </span>
            <span class="grow font-bold ml-2">
                {#if $events_sess.files.processed_file_list?.length > 0}
                    {$events_sess.files.processed_file_list.length}
                    {$events_sess.files.processed_file_list.length === 1
                        ? 'file'
                        : 'files'}
                {:else}
                    <span class="text-xs"> 0 </span>
                {/if}
            </span>
        {/await}
    </button>
</form>
