<script lang="ts">
    import { env } from "$env/dynamic/public";
    import axios from "axios";
    import Modal from "./Modal.svelte";
    import { url } from "./util";
    import { isDir, isRessource, type Directory, type Ressource } from "./Types";
    import { onMount } from "svelte";

    interface Props {
        show: boolean;
        ok?: (res: Ressource) => void;
    }

    let { show = $bindable(false), ok = (res) => {} }: Props = $props();

    let file: File | null = null;
    let path: string = $state("/");

    let fetchingRessources = $state(false);
    let ressources: (Ressource | Directory)[] = $state([]);
    let selectedRessource: Ressource | undefined = $state();

    let error = $state("");

    let showNewDir = $state(false);
    let newDirName = $state("");
    let showDeleteDir = $state(false);
    let dirToDelete: Directory | undefined = $state();

    let showDeleteRessource = $state(false);
    let resToDelete: Ressource | undefined = $state();

    let showRenameFile = $state(false);
    let fileToRename: Ressource | undefined = $state();
    let newFileName = $state("");

    function handleFileChange(event: Event) {
        const target = event.target as HTMLInputElement | null;
        if (target?.files?.[0]) {
            file = target.files[0];
        }
    }

    function uploadData(event: SubmitEvent) {
        event.preventDefault();
        if (file === null) return;

        const formData = new FormData();
        formData.append("path", path);
        formData.append("file", file);

        axios
            .post(
                `${env.PUBLIC_JEOPARDY_SERVER_PROTOCOL}://${env.PUBLIC_JEOPARDY_SERVER}/upload`,
                formData,
                {
                    withCredentials: true,
                    headers: {
                        "Content-Type": "multipart/form-data"
                    },
                    onUploadProgress: (event) => {
                        console.log(event);
                    }
                }
            )
            .then((response) => {
                if (response.status === 200) {
                    fetchDirectory();
                } else {
                    alert("Failed with status: " + response.status);
                }
            })
            .catch((err) => {
                console.error(err);
                alert(err);
            });
    }

    async function deleteRessource(res: Ressource | Directory): Promise<boolean> {
        if (isRessource(res)) {
            return axios
                .delete(url("/cdn/" + res.user + "/" + res.filename), {
                    withCredentials: true
                })
                .then((response) => {
                    if (response.status === 200) {
                        fetchDirectory();
                        return true;
                    } else {
                        alert("Something went wrong: " + response.status);
                        return false;
                    }
                })
                .catch((err) => {
                    console.error(err);
                    return false;
                });
        } else if (isDir(res)) {
            showDeleteDir = true;
            dirToDelete = res;
            return true;
        }
        return false;
    }

    function deleteRessourceCancel() {
        resToDelete = undefined;
    }

    async function deleteDir() {
        if (dirToDelete === undefined) return false;
        return axios
            .delete(url("/directory"), {
                headers: {
                    "Content-Type": "application/json"
                },
                data: { path: path + (path === "/" ? "" : "/") + dirToDelete.name },
                withCredentials: true
            })
            .then((response) => {
                if (response.status === 200) {
                    fetchDirectory();
                    dirToDelete = undefined;
                    return true;
                } else {
                    alert("Failed to delete directory: " + response.status);
                }
                return false;
            })
            .catch((err) => {
                console.error(err);
                return false;
            });
    }

    function deleteDirCancel() {
        dirToDelete = undefined;
    }

    async function fetchDirectory() {
        fetchingRessources = true;
        return axios
            .post(
                url("/directory"),
                { path },
                {
                    withCredentials: true
                }
            )
            .then((response) => {
                if (response.status === 200) {
                    ressources = response.data;
                    ressources.sort((a, b) => {
                        if (isDir(a) && !isDir(b)) return -1;
                        if (!isDir(a) && isDir(b)) return 1;
                        return a.name.localeCompare(b.name);
                    });
                    if (path !== "/") {
                        ressources.unshift({
                            isDir: true,
                            name: ".."
                        });
                    }
                }
            })
            .catch((e) => {
                console.log(e);
            })
            .finally(() => {
                fetchingRessources = false;
            });
    }

    async function addDirectoryOk(): Promise<boolean> {
        error = "";
        if (newDirName.length <= 0) {
            error = "Gib einen Namen für den Ordner ein";
            return false;
        }

        return axios
            .put(url("/directory"), { name: newDirName, path }, { withCredentials: true })
            .then((response) => {
                if (response.status === 200) {
                    fetchDirectory();
                    return true;
                } else {
                    return false;
                }
            })
            .catch(() => {
                error = "Etwas ist schief gelaufen";
                return false;
            });
    }

    function addDirectoryCancel() {
        error = "";
        newDirName = "";
    }

    function ressourceClicked(res: Ressource | Directory) {
        if (isRessource(res)) {
            selectedRessource = res;
        } else if (isDir(res)) {
            if (res.name === "..") {
                let breadcumbs = path.split("/");
                breadcumbs.pop();
                path = breadcumbs.join("/");
                if (path.length <= 0) path = "/";
            } else {
                if (!path.endsWith("/")) {
                    path += "/";
                }
                path += res.name;
            }
            fetchDirectory();
        }
    }

    function renameRessource(res: Ressource) {
        fileToRename = res;
        newFileName = res.name;
        showRenameFile = true;
    }

    async function renameFile() {
        if (fileToRename === undefined) return false;
        return axios
            .put(
                url("/cdn/" + fileToRename.user + "/" + fileToRename.filename),
                {
                    name: newFileName
                },
                { withCredentials: true }
            )
            .then((response) => {
                if (response.status === 200) {
                    fetchDirectory();
                    fileToRename = undefined;
                    newFileName = "";
                    return true;
                } else {
                    alert("Failed to rename File: " + response.status);
                }
                return false;
            })
            .catch((err) => {
                console.error(err);
                return false;
            });
    }

    function renameFileCancel() {
        fileToRename = undefined;
        newFileName = "";
    }

    function closeRessourceManager() {
        selectedRessource = undefined;
    }

    $effect(() => {
        if (show) {
            fetchDirectory();
        }
    });
</script>

<Modal
    bind:showModal={show}
    okFn={async () => {
        if (selectedRessource) ok({ ...selectedRessource });
        return true;
    }}
    oncloseFn={closeRessourceManager}
    okButtonText={selectedRessource !== undefined ? selectedRessource.name : "Ok"}
    width="90%"
    height="90%"
>
    {#snippet header()}
        <h2 class="text-3xl">Ressourcenmanager - {path}</h2>
    {/snippet}
    <div class="h-full">
        {#if fetchingRessources}
            Loading...
        {:else if ressources.length > 0}
            <div class="flex flex-col gap-2">
                {#each ressources as ressource}
                    <!-- svelte-ignore a11y_click_events_have_key_events -->
                    <!-- svelte-ignore a11y_no_static_element_interactions -->
                    <div
                        class="flex grow cursor-pointer items-center justify-between rounded-sm border-1 border-solid p-1 hover:bg-gray-200"
                        onclick={() => ressourceClicked(ressource)}
                        class:bg-green-200={isRessource(ressource) &&
                            ressource._id === selectedRessource?._id}
                    >
                        <div>
                            {#if isDir(ressource)}
                                <i class="fa-solid fa-folder"></i>
                                {ressource.name}
                            {:else}
                                {#if ressource.mimetype.includes("image")}
                                    <i class="fa-solid fa-image"></i>
                                {:else if ressource.mimetype.includes("audio")}
                                    <i class="fa-solid fa-music"></i>
                                {:else}
                                    <i class="fa-solid fa-file"></i>
                                {/if}
                                {ressource.name}
                            {/if}
                        </div>
                        {#if !(isDir(ressource) && ressource.name === "..")}
                            <div class="flex gap-4">
                                {#if isRessource(ressource)}
                                    <!-- svelte-ignore a11y_consider_explicit_label -->
                                    <button
                                        type="button"
                                        class="btn border-black"
                                        onclick={(event) => {
                                            event.stopPropagation();
                                            renameRessource(ressource);
                                        }}><i class="fa-solid fa-pencil"></i></button
                                    >
                                {/if}
                                <!-- svelte-ignore a11y_consider_explicit_label -->
                                <button
                                    type="button"
                                    class="btn border-red-600 text-red-600"
                                    onclick={(event) => {
                                        event.stopPropagation();
                                        if (isRessource(ressource)) {
                                            showDeleteRessource = true;
                                            resToDelete = ressource;
                                        } else if (isDir(ressource)) {
                                            dirToDelete = ressource;
                                            showDeleteDir = true;
                                        }
                                    }}><i class="fa-solid fa-trash"></i></button
                                >
                            </div>
                        {/if}
                    </div>
                {/each}
            </div>
        {:else}
            <div class="flex h-full w-full grow-2 flex-col items-center justify-center">
                <div class="text-[128px] text-gray-300"><i class="fa-solid fa-database"></i></div>
                <div class="text-[24px] text-gray-500 select-none">
                    Noch keine Ressourcen vorhanden
                </div>
            </div>
        {/if}
    </div>
    {#snippet actionButtons()}
        <form
            action={`${env.PUBLIC_JEOPARDY_SERVER_PROTOCOL}://${env.PUBLIC_JEOPARDY_SERVER}/upload`}
            enctype="multipart/form-data"
            method="post"
            onsubmit={uploadData}
        >
            <input class="btn" type="file" name="file" onchange={handleFileChange} />
            <input type="submit" value="Hochladen" class="btn" />
        </form>
        <button class="btn" type="button" onclick={() => (showNewDir = true)}>Neuer Ordner</button>
    {/snippet}
</Modal>

<Modal bind:showModal={showNewDir} okFn={addDirectoryOk} cancelFn={addDirectoryCancel}>
    {#snippet header()}
        <h2 class="text-3xl">Neuer Ordner</h2>
    {/snippet}
    <div>
        <label for="directory" class="">Name</label>
        <div>
            <input
                type="text"
                name="directory"
                id="directory"
                class="borders mt-2 mb-2 w-full"
                bind:value={newDirName}
            />
        </div>
        {#if error.length > 0}
            <div class="text-red-700">{error}</div>
        {/if}
    </div>
</Modal>

<Modal
    bind:showModal={showDeleteRessource}
    okFn={async () => {
        if (resToDelete === undefined) return false;
        return deleteRessource(resToDelete);
    }}
    cancelFn={deleteRessourceCancel}
>
    {#snippet header()}
        <h2 class="text-3xl">Ressource löschen</h2>
    {/snippet}

    <div>
        Soll die Ressource {resToDelete?.name} wirklich gelöscht werden?
    </div>
    {#if error.length > 0}
        <div class="text-red-700">{error}</div>
    {/if}
</Modal>

<Modal bind:showModal={showDeleteDir} okFn={deleteDir} cancelFn={deleteDirCancel}>
    {#snippet header()}
        <h2 class="text-3xl">Ordner löschen</h2>
    {/snippet}

    <div>
        Soll der Ordner {dirToDelete?.name} wirklich gelöscht werden? Alle darin enthaltenen Daten gehen
        verloren.
    </div>
    {#if error.length > 0}
        <div class="text-red-700">{error}</div>
    {/if}
</Modal>

<Modal bind:showModal={showRenameFile} okFn={renameFile} cancelFn={renameFileCancel}>
    {#snippet header()}
        <h2 class="text-3xl">Datei umbenennen</h2>
    {/snippet}
    <div>
        <label for="directory" class="">Name</label>
        <div>
            <input
                type="text"
                name="directory"
                id="directory"
                class="borders mt-2 mb-2 w-full"
                bind:value={newFileName}
            />
        </div>
        {#if error.length > 0}
            <div class="text-red-700">{error}</div>
        {/if}
    </div>
</Modal>

<style>
    .borders {
        border: 1px solid black;
        border-radius: 5px;
        display: flex;
        padding: 2px;
    }
</style>
