<script lang="ts">
    import {state, token, type UploadFile} from '../store';
    import {Button, ButtonGroup, Modal, Progressbar} from 'flowbite-svelte';
    import {filesize} from 'filesize';

    interface MyFile extends UploadFile {
        waiting: boolean,
        done: boolean,
        current: number,
        total: number,
        progress: number
    }

    let aborting = false;
    let done = false;
    let show_modal = false;
    let files: MyFile[] = [];
    let current = 0, total = 0;
    let progress: number;
    $: progress = total == 0 ? 0 : (current / total * 100);
    let not_done_files: MyFile[], done_files: MyFile[];
    $: not_done_files = files.filter(f => !f.done);
    $: done_files = files.filter(f => f.done);

    function close() {
        show_modal = false;
        state.update(v => v);
    }

    async function realUpload(file: MyFile) {
        if (file.done)
            return;
        file.waiting = false;
        let load_progress = 0;
        await new Promise((resolve) => {
            const xhr = new XMLHttpRequest();
            xhr.onloadend = resolve;
            xhr.onerror = resolve;
            xhr.upload.onprogress = ev => {
                current += ev.loaded - load_progress;
                load_progress = ev.loaded;
                file.current = ev.loaded;
                file.progress = file.current / file.total * 100;
                files = files;
                if (file.current == file.total)
                    resolve(null);
            };
            xhr.open('POST', '/upload', true);
            xhr.setRequestHeader('X-Node', file.id.toString());
            xhr.setRequestHeader('X-Token', $token ?? '');
            xhr.send(file.file);
        });
        current += file.total - load_progress;
        file.done = true;
        files = files;
    }

    export const upload = async (fs: UploadFile[]) => {
        aborting = false;
        done = false;
        current = 0;
        total = 0;
        show_modal = true;

        fs.forEach(f => (total += f.file.size));
        files = fs.map(f => {
            return {
                ...f,
                waiting: f.file.size != 0,
                done: f.file.size == 0,
                current: 0,
                total: f.file.size,
                progress: 0
            };
        });

        const in_flight = new Set();
        for (const file of files) {
            if (in_flight.size >= 15) {
                await Promise.race(in_flight);
            }
            if (aborting)
                break;
            const p = realUpload(file);
            in_flight.add(p);
            const _ = (async () => { await p; in_flight.delete(p); })();
        }

        await Promise.all(in_flight);

        done = true;
        if (!aborting && !files.some(v => v.overwrite))
            close();
    };
</script>

<Modal bind:open={show_modal} dismissable={false} size="xl" title="Uploading">
    <div>
        <div class="mb-1 flex justify-between">
            <span>{filesize(current, {base: 2, standard: 'jedec'})} / {filesize(total, {base: 2, standard: 'jedec'})}</span>
            <span>{progress.toFixed(2)}%</span>
        </div>
        <Progressbar class="mt-0" size="h-4" bind:progress={progress} />
    </div>

    <table class="w-full">
        <thead>
            <tr>
                <th>File</th>
                <th>Status</th>
            </tr>
        </thead>
        <tbody>
            {#each not_done_files as file (file.id)}
                <tr>
                    <td>{file.full_name}</td>
                    <td>
                        {#if file.waiting}
                            Waiting
                        {:else}
                            <div class="flex flex-nowrap flex-row">
                                <span class="mr-4">{filesize(file.current, {base: 2, standard: 'jedec'})} / {filesize(file.total, {base: 2, standard: 'jedec'})}</span>
                                <Progressbar class="flex-1" size="h-4" bind:progress={file.progress} labelInside />
                            </div>
                        {/if}
                    </td>
                </tr>
            {/each}
            {#each done_files as file (file.id)}
                <tr>
                    <td>{file.full_name}</td>
                    <td>Done {#if file.overwrite}(Overwrote old file){/if}</td>
                </tr>
            {/each}
        </tbody>
    </table>

    <span slot="footer">
        {#if done}
            <Button class="w-full" on:click={close}>Close</Button>
        {:else if !aborting}
            <Button class="w-full" color="red" on:click={() => (aborting = true)}>Abort</Button>
        {/if}
    </span>
</Modal>