<script lang="ts">
    import {TimeEntryDto} from "$shared/lib/models/TimeEntryDto";
    import {Temporal} from "@js-temporal/polyfill";
    import {createEventDispatcher, onMount, onDestroy} from "svelte";
    import DateTimePart from "./sections/date-time.svelte";
    import LabelsPart from "./sections/labels.svelte";
    import CategoryPart from "./sections/category.svelte";
    import Button from "$shared/components/button.svelte";
    import {Textarea} from "$shared/components/form";
    import Alert from "$shared/components/alert.svelte";
    import {is_guid} from "$shared/lib/helpers";
    import {create_entry_async, edit_entry_async} from "$app/lib/stores/entries";

    const dispatch = createEventDispatcher();

    let formError = "";
    let formIsLoading = false;
    let description = "";
    let descriptionError = "";
    let dateTimePart;
    let labelsPart;
    let categoryPart;
    let entryId;

    onMount(() => {
        formIsLoading = true;

        Promise.all([categoryPart.load_categories(), labelsPart.load_labels()]).then(() => {
            formIsLoading = false;
        });

        window.addEventListener("keydown", handle_window_keydown);
    });

    onDestroy(() => {
        window.removeEventListener("keydown", handle_window_keydown);
    });

    function handle_window_keydown(event) {
        if (event.ctrlKey && event.code === "Enter") {
            submit_form();
        }
    }

    function validate_form() {
        return dateTimePart.is_valid() && categoryPart.is_valid() && description_is_valid();
    }

    function description_is_valid() {
        if (!description) {
            descriptionError = "Description is required";
        } else {
            descriptionError = "";
        }

        return description;
    }

    function get_payload() {
        const response = {} as TimeEntryDto;
        const values = get_values();
        if (!is_guid(values.id)) {
            delete values.id;
        } else {
            response.id = values.id;
        }

        const currentTimeZone = Temporal.Now.zonedDateTimeISO().offset;
        response.start = values.date + "T" + values.fromTimeValue + currentTimeZone.toString();
        response.stop = values.date + "T" + values.toTimeValue + currentTimeZone.toString();

        response.category = {
            id: values.category.id,
        };

        const selectedLabels = values.labels;
        if (selectedLabels?.length > 0 ?? false) {
            response.labels = selectedLabels;
        }

        const descriptionContent = description?.trim();
        if (descriptionContent?.length > 0 ?? false) {
            response.description = descriptionContent;
        }

        return response;
    }

    async function submit_form() {
        formError = "";
        if (validate_form()) {
            const payload = get_payload() as TimeEntryDto;
            formIsLoading = true;
            if (is_guid(payload.id)) {
                const response = await edit_entry_async(payload);
                if (response.ok) {
                    functions.reset();
                    dispatch("updated", response.data);
                } else {
                    formError = "An error occured while updating the entry, try again soon";
                    formIsLoading = false;
                }
            } else {
                const response = await create_entry_async(payload);
                if (response.ok) {
                    functions.reset();
                    dispatch("created");
                } else {
                    formError = "An error occured while creating the entry, try again soon";
                    formIsLoading = false;
                }
            }
        }
    }

    function get_values() {
        return {
            id: entryId,
            toTimeValue: dateTimePart.get_to_time_value(),
            fromTimeValue: dateTimePart.get_from_time_value(),
            date: dateTimePart.get_date(),
            category: categoryPart.get_selected(),
            labels: labelsPart.get_selected(),
            description: description,
        };
    }

    export const functions = {
        set_values(values) {
            entryId = values.id;
            dateTimePart.set_values(values);
            labelsPart.select_labels(values?.labels.map((c) => c.id) ?? []);
            categoryPart.select_category(values?.category?.id);
            description = values.description;
        },
        set_time(value: {to: Temporal.PlainTime, from: Temporal.PlainTime}) {
            dateTimePart.set_times(value);
        },
        set_description(value: string) {
            if (description) description = description + "\n\n" + value;
            else description = value;
        },
        reset() {
            formIsLoading = false;
            entryId = "";
            labelsPart.reset();
            categoryPart.reset();
            dateTimePart.reset(true);
            description = "";
            formError = "";
        },
    };
</script>

<form on:submit|preventDefault={submit_form}
      on:reset={() => functions.reset()}>
    <div class="margin-y-sm">
        <Alert visible={formError !== ""}
               message={formError}
               type="error"/>
    </div>

    <div class="margin-bottom-sm">
        <DateTimePart bind:functions={dateTimePart}/>
    </div>

    <div class="margin-bottom-sm">
        <CategoryPart bind:functions={categoryPart}/>
    </div>

    <div class="margin-bottom-sm">
        <LabelsPart bind:functions={labelsPart}/>
    </div>

    <div class="margin-bottom-sm">
        <Textarea class="width-100%"
                  id="description"
                  label="Description"
                  errorText="{descriptionError}"
                  bind:value={description}></Textarea>
    </div>

    <div class="flex flex-row justify-end gap-x-xs">
        {#if entryId}
            <Button text="Reset"
                    on:click={() => functions.reset()}
                    variant="subtle"
            />
        {/if}
        <Button loading={formIsLoading}
                type="submit"
                variant="primary"
                text={entryId ? "Save" : "Create"}
        />
    </div>
</form>
