<script>
    import { SchemaField } from "pocketbase";
    import ApiClient from "@/utils/ApiClient";
    import CommonHelper from "@/utils/CommonHelper";
    import tooltip from "@/actions/tooltip";
    import Field from "@/components/base/Field.svelte";
    import Draggable from "@/components/base/Draggable.svelte";
    import UploadedFilePreview from "@/components/base/UploadedFilePreview.svelte";
    import RecordFileThumb from "@/components/records/RecordFileThumb.svelte";
    import { onMount } from "svelte";

    export let record;
    export let value = "";
    export let uploadedFiles = []; // Array<File> array
    export let deletedFileNames = []; // Array<string> array
    export let field = new SchemaField();

    let fileInput;
    let filesListElem;
    let isDragOver = false;
    let fileToken = "";

    // normalize uploadedFiles type
    $: if (!Array.isArray(uploadedFiles)) {
        uploadedFiles = CommonHelper.toArray(uploadedFiles);
    }

    // normalize deleted files
    $: if (!Array.isArray(deletedFileNames)) {
        deletedFileNames = CommonHelper.toArray(deletedFileNames);
    }

    $: isMultiple = field.options?.maxSelect > 1;

    $: if (CommonHelper.isEmpty(value)) {
        value = isMultiple ? [] : "";
    }

    $: valueAsArray = CommonHelper.toArray(value);

    $: maxReached =
        (valueAsArray.length || uploadedFiles.length) &&
        field.options?.maxSelect <= valueAsArray.length + uploadedFiles.length - deletedFileNames.length;

    $: if (uploadedFiles !== -1 || deletedFileNames !== -1) {
        triggerListChange();
    }

    function restoreExistingFile(name) {
        CommonHelper.removeByValue(deletedFileNames, name);
        deletedFileNames = deletedFileNames;
    }

    function removeExistingFile(name) {
        CommonHelper.pushUnique(deletedFileNames, name);
        deletedFileNames = deletedFileNames;
    }

    function removeNewFile(index) {
        if (!CommonHelper.isEmpty(uploadedFiles[index])) {
            uploadedFiles.splice(index, 1);
        }
        uploadedFiles = uploadedFiles;
    }

    // emulate native change event
    function triggerListChange() {
        filesListElem?.dispatchEvent(
            new CustomEvent("change", {
                detail: { value, uploadedFiles, deletedFileNames },
                bubbles: true,
            })
        );
    }

    function dropHandler(e) {
        e.preventDefault();

        isDragOver = false;

        const files = e.dataTransfer?.files || [];

        if (maxReached || !files.length) {
            return;
        }

        for (const file of files) {
            const currentTotal = valueAsArray.length + uploadedFiles.length - deletedFileNames.length;

            if (field.options?.maxSelect <= currentTotal) {
                break;
            }

            uploadedFiles.push(file);
        }

        uploadedFiles = uploadedFiles;
    }

    onMount(async () => {
        fileToken = await ApiClient.getAdminFileToken(record.collectionId);
    });
</script>

<div
    class="block"
    on:dragover|preventDefault={() => {
        isDragOver = true;
    }}
    on:dragleave={() => {
        isDragOver = false;
    }}
    on:drop={dropHandler}
>
    <Field
        class="
            form-field form-field-list form-field-file
            {field.required ? 'required' : ''}
            {isDragOver ? 'dragover' : ''}
        "
        name={field.name}
        let:uniqueId
    >
        <label for={uniqueId}>
            <i class={CommonHelper.getFieldTypeIcon(field.type)} />
            <span class="txt">{field.name}</span>
        </label>

        <div bind:this={filesListElem} class="list">
            {#each valueAsArray as filename, i (filename + record.id)}
                {@const isDeleted = deletedFileNames.includes(filename)}
                <Draggable
                    bind:list={value}
                    group={field.name + "_uploaded"}
                    index={i}
                    disabled={!isMultiple}
                    let:dragging
                    let:dragover
                >
                    <div class="list-item" class:dragging class:dragover>
                        <div class:fade={isDeleted}>
                            <RecordFileThumb {record} {filename} />
                        </div>

                        <div class="content">
                            <a
                                draggable={false}
                                href={ApiClient.files.getUrl(record, filename, { token: fileToken })}
                                class="txt-ellipsis {isDeleted
                                    ? 'txt-strikethrough txt-hint'
                                    : 'link-primary'}"
                                title="Download"
                                target="_blank"
                                rel="noopener noreferrer"
                            >
                                {filename}
                            </a>
                        </div>

                        <div class="actions">
                            {#if isDeleted}
                                <button
                                    type="button"
                                    class="btn btn-sm btn-danger btn-transparent"
                                    on:click={() => restoreExistingFile(filename)}
                                >
                                    <span class="txt">Restore</span>
                                </button>
                            {:else}
                                <button
                                    type="button"
                                    class="btn btn-transparent btn-hint btn-sm btn-circle btn-remove"
                                    use:tooltip={"Remove file"}
                                    on:click={() => removeExistingFile(filename)}
                                >
                                    <i class="ri-close-line" />
                                </button>
                            {/if}
                        </div>
                    </div>
                </Draggable>
            {/each}

            {#each uploadedFiles as file, i (file.name + i)}
                <Draggable
                    bind:list={uploadedFiles}
                    group={field.name + "_new"}
                    index={i}
                    disabled={!isMultiple}
                    let:dragging
                    let:dragover
                >
                    <div class="list-item" class:dragging class:dragover>
                        <figure class="thumb">
                            <UploadedFilePreview {file} />
                        </figure>
                        <div class="filename m-r-auto" title={file.name}>
                            <small class="label label-success m-r-5">New</small>
                            <span class="txt">{file.name}</span>
                        </div>
                        <button
                            type="button"
                            class="btn btn-transparent btn-hint btn-sm btn-circle btn-remove"
                            use:tooltip={"Remove file"}
                            on:click={() => removeNewFile(i)}
                        >
                            <i class="ri-close-line" />
                        </button>
                    </div>
                </Draggable>
            {/each}

            <div class="list-item list-item-btn">
                <input
                    bind:this={fileInput}
                    type="file"
                    class="hidden"
                    accept={field.options?.mimeTypes?.join(",") || null}
                    multiple={isMultiple}
                    on:change={() => {
                        for (let file of fileInput.files) {
                            uploadedFiles.push(file);
                        }
                        uploadedFiles = uploadedFiles;
                        fileInput.value = null; // reset
                    }}
                />
                <button
                    type="button"
                    class="btn btn-transparent btn-sm btn-block"
                    disabled={maxReached}
                    on:click={() => fileInput?.click()}
                >
                    <i class="ri-upload-cloud-line" />
                    <span class="txt">Upload new file</span>
                </button>
            </div>
        </div>
    </Field>
</div>
