<!--

    Queue - A Queueing system that can be used to handle labs in higher education
    Copyright (C) 2016-2024  Delft University of Technology

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

-->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{lab/create/regular}">
    <head>
        <title>Create Slotted Lab</title>
        <script src="/webjars/fullcalendar/index.global.js"></script>
        <script src="/js/time_slots.js"></script>
    </head>

    <!--@thymesVar id="ec" type="nl.tudelft.labracore.api.dto.EditionCollectionDetailsDTO"-->
    <!--@thymesVar id="edition" type="nl.tudelft.labracore.api.dto.EditionDetailsDTO"-->

    <!--@thymesVar id="modules" type="java.util.List<nl.tudelft.labracore.api.dto.ModuleDetailsDTO>"-->
    <!--@thymesVar id="assignments" type="java.util.List<nl.tudelft.labracore.api.dto.AssignmentDetailsDTO>"-->
    <!--@thymesVar id="rooms" type="java.util.List<nl.tudelft.labracore.api.dto.RoomSummaryDTO>"-->

    <!--@thymesVar id="dto" type="nl.tudelft.queue.dto.create.labs.SlottedLabCreateDTO"-->
    <!--@thymesVar id="lType" type="nl.tudelft.queue.model.enums.QueueSessionType"-->

    <body>
        <th:block th:object="${dto}">
            <th:block layout:fragment="advanced-config">
                <th:block th:replace="~{lab/create/components/advanced-slotted :: advanced}"></th:block>
            </th:block>

            <section layout:fragment="slot-config">
                <h3 class="font-500 mb-3">Time slots</h3>

                <div class="flex mb-5 | md:vertical md:align-stretch">
                    <div class="flex vertical">
                        <div>
                            <h4 class="font-400 mb-3">Configure time slots in bulk</h4>
                            <div class="flex vertical">
                                <div class="grid col-2 align-center gap-3" style="--col-1: 6rem">
                                    <label for="day">Day</label>
                                    <input
                                        id="day"
                                        class="textfield"
                                        type="text"
                                        autocomplete="false"
                                        readonly
                                        placeholder="Click here to select a day..."
                                        th:value="${dto.slot.opensAt}" />
                                    <div style="grid-column: span 2" class="grid col-2 gap-3">
                                        <div class="flex vertical gap-0">
                                            <label for="from" class="font-200">From</label>
                                            <input
                                                id="from"
                                                class="textfield"
                                                type="time"
                                                th:value="${#temporals.format(dto.slot.opensAt, 'HH:MM')}" />
                                        </div>
                                        <div class="flex vertical gap-0">
                                            <label for="to" class="font-200">To</label>
                                            <input
                                                id="to"
                                                class="textfield"
                                                type="time"
                                                th:value="${#temporals.format(dto.slot.closesAt, 'HH:MM')}" />
                                        </div>
                                    </div>
                                    <label for="duration">Duration</label>
                                    <input id="duration" class="textfield" type="number" min="1" placeholder="Enter duration in minutes..." />
                                    <label for="capacity">Capacity</label>
                                    <input id="capacity" class="textfield" type="number" min="0" placeholder="Enter capacity..." />
                                </div>
                                <div class="flex gap-3 vertical">
                                    <button id="add-slots" type="button" class="button">Add slots</button>
                                    <div class="grid gap-3 col-2">
                                        <button id="update-slots" type="button" class="button" data-style="outlined">Update slots in range</button>
                                        <button id="remove-slots" type="button" class="button" data-style="outlined" data-type="error">
                                            Remove slots in range
                                        </button>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="underlined"></div>
                        <div>
                            <h4 class="font-400 mb-3">Configure selected time slot</h4>
                            <div class="flex vertical">
                                <div id="edit-info" class="banner" data-type="info">
                                    <span class="fa-solid fa-info-circle banner__icon"></span>
                                    <p>Click a time slot to edit</p>
                                </div>
                                <div id="edit-timeslot" class="flex vertical hidden">
                                    <h4 class="flex vertical gap-0">
                                        <span id="edit-timeslot-time" class="font-400"></span>
                                        <span id="edit-timeslot-day" class="font-300"></span>
                                    </h4>
                                    <div class="grid col-2 align-center gap-3" style="--col-1: 6rem">
                                        <label for="edit-timeslot-capacity">Capacity</label>
                                        <input id="edit-timeslot-capacity" class="textfield" min="0" type="number" />
                                    </div>
                                    <button id="remove-timeslot" type="button" class="button" data-style="outlined" data-type="error">
                                        Remove slot
                                    </button>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div id="timeslot-overview" class="grow"></div>
                </div>

                <dialog id="day-select-dialog" class="dialog">
                    <div class="flex vertical p-7" style="min-width: min(100vw, 40rem)">
                        <div id="day-select"></div>
                    </div>
                </dialog>

                <!-- Slot form elements -->
                <div id="slots" hidden></div>

                <p id="time-slot-warning" class="fw-500 colour-error" hidden>There are no time slots. Add some time slots above.</p>

                <script th:inline="javascript">
                    document.addEventListener("DOMContentLoaded", function () {
                        let timeSlots = new TimeSlotCollection();
                        let day = undefined;

                        // Clear day field, which sometimes is remembered by the browser
                        if (document.getElementById("day").value) {
                            let el = document.getElementById("day");
                            el.value = moment(el.value).format("ddd D MMM YYYY");
                        } else {
                            document.getElementById("day").value = "";
                        }

                        /**
                         * Updates the hidden input fields for slots
                         */
                        function updateFormFields() {
                            const div = document.getElementById("slots");
                            div.innerHTML = "";
                            div.appendChild(timeSlots.inputs);
                            if (!timeSlots.isEmpty()) {
                                document.getElementById("time-slot-warning").setAttribute("hidden", "");
                            }
                        }

                        // Add slots from DTO (if copying)
                        const slotDTOs = /*[[${dto.timeSlots}]]*/ [];
                        slotDTOs.forEach(dto => {
                            let slot = TimeSlot.fromDTO(dto);
                            slot.showCapacity = true;
                            timeSlots.addSlot(slot);
                        });
                        updateFormFields();

                        // Calendar for selecting the day
                        const daySelectDialog = document.getElementById("day-select-dialog");
                        let daySelect = new FullCalendar.Calendar(document.getElementById("day-select"), {
                            initialView: "dayGridMonth",
                            locale: "gb",
                            firstDay: 1,
                            selectable: true,
                            selectAllow: info =>
                                moment(info.start).startOf("day") >= moment().startOf("day") && moment(info.end).diff(info.start, "days") === 1,
                            select: info => {
                                document.getElementById("day").value = moment(info.start).format("ddd D MMM YYYY");
                                day = moment(info.start);
                                daySelectDialog.close();
                            },
                        });
                        document.getElementById("day").addEventListener("click", function () {
                            daySelectDialog.showModal();
                            daySelect.render();
                        });

                        // Calendar for timeslot overview
                        let timeSlotOverview = new Calendar(
                            new FullCalendar.Calendar(document.getElementById("timeslot-overview"), {
                                initialView: "timeGridWeek",
                                locale: "gb",
                                firstDay: 1,
                                allDaySlot: false,
                                editable: true,
                                slotDuration: "00:10",
                                scrollTime: "09:00",
                            }),
                            timeSlots,
                            {
                                // On select display event editing on the side
                                onSelect: ts => {
                                    const from = ts.start.format("H:mm");
                                    const to = ts.end.format("H:mm");

                                    document.getElementById("edit-timeslot-day").innerText = ts.start.format("dddd D MMMM");
                                    document.getElementById("edit-timeslot-time").innerText = `${from} - ${to}`;
                                    document.getElementById("edit-timeslot-capacity").value = ts.capacity;

                                    document.getElementById("edit-timeslot").classList.remove("hidden");
                                    document.getElementById("edit-info").classList.add("hidden");
                                },
                                // Allow editing
                                onEdit: () => {},
                            }
                        );
                        timeSlotOverview.show();
                        // Make sure to update form fields when the calendar updates
                        timeSlotOverview.update = function () {
                            this.calendar.refetchEvents();
                            updateFormFields();
                        };

                        /**
                         * Focus inputs that are invalid. Return true iff all inputs are valid.
                         */
                        function verifyInputs(inputs) {
                            if (inputs.includes("day") && !day) {
                                document.getElementById("day").focus();
                                return false;
                            }

                            const from = document.getElementById("from");
                            if (inputs.includes("from") && !from.value) {
                                from.focus();
                                return false;
                            }

                            const to = document.getElementById("to");
                            if (inputs.includes("to") && !to.value) {
                                to.focus();
                                return false;
                            }

                            const duration = document.getElementById("duration");
                            if (inputs.includes("duration") && !duration.value) {
                                duration.focus();
                                return false;
                            }

                            const capacity = document.getElementById("capacity");
                            if (inputs.includes("capacity") && !capacity.value) {
                                capacity.focus();
                                return false;
                            }

                            return true;
                        }

                        // Add slots withing the provided timeframe
                        document.getElementById("add-slots").addEventListener("click", function () {
                            if (!verifyInputs(["day", "to", "from", "capacity", "duration"])) return;

                            const duration = document.getElementById("duration").value;
                            const capacity = document.getElementById("capacity").value;
                            const from = document.getElementById("from").value;
                            const to = document.getElementById("to").value;

                            let time = day.clone();
                            time.set({ hour: from.split(":")[0], minute: from.split(":")[1] });
                            const end = day.clone();
                            end.set({ hour: to.split(":")[0], minute: to.split(":")[1] });

                            timeSlots.waitForBulkUpdate();
                            while (time.clone().add(parseInt(duration), "minutes") <= end) {
                                timeSlots.addSlot(
                                    new TimeSlot(undefined, time.clone(), time.clone().add(parseInt(duration), "minutes"), parseInt(capacity), [], {
                                        showCapacity: true,
                                    })
                                );
                                time.add(parseInt(duration), "minutes");
                            }
                            timeSlots.bulkUpdate();

                            timeSlotOverview.scrollToTime(timeSlots.timeRange.start);
                        });

                        // Update slots on button click
                        document.getElementById("update-slots").addEventListener("click", function () {
                            if (!verifyInputs(["day", "to", "from", "capacity", "duration"])) return;

                            const capacity = document.getElementById("capacity").value;
                            const duration = document.getElementById("duration").value;

                            const from = document.getElementById("from").value;
                            const to = document.getElementById("to").value;

                            let start = day.clone();
                            start.set({ hour: from.split(":")[0], minute: from.split(":")[1] });
                            const end = day.clone();
                            end.set({ hour: to.split(":")[0], minute: to.split(":")[1] });

                            timeSlots.waitForBulkUpdate();
                            timeSlots.getSlotsBetween(start, end).forEach(ts => {
                                ts.capacity = parseInt(capacity);
                                ts.end = ts.start.clone().add(parseInt(duration), "minutes");
                            });
                            timeSlots.bulkUpdate();
                        });

                        // Remove slots on button click
                        document.getElementById("remove-slots").addEventListener("click", function () {
                            if (!verifyInputs(["day", "to", "from"])) return;

                            const from = document.getElementById("from").value;
                            const to = document.getElementById("to").value;

                            let start = day.clone();
                            start.set({ hour: from.split(":")[0], minute: from.split(":")[1] });
                            const end = day.clone();
                            end.set({ hour: to.split(":")[0], minute: to.split(":")[1] });

                            timeSlots.waitForBulkUpdate();
                            timeSlots.getSlotsBetween(start, end).forEach(ts => {
                                if (ts === timeSlots.selected) {
                                    document.getElementById("edit-timeslot").classList.add("hidden");
                                    document.getElementById("edit-info").classList.remove("hidden");
                                }
                                timeSlots.removeSlot(ts);
                            });
                            timeSlots.bulkUpdate();
                        });

                        // Edit capacity on capacity change
                        const editCapacity = document.getElementById("edit-timeslot-capacity");
                        editCapacity.addEventListener("change", function () {
                            timeSlots.selected.capacity = parseInt(editCapacity.value);
                        });

                        // Remove timeslot on button click
                        document.getElementById("remove-timeslot").addEventListener("click", function () {
                            timeSlots.removeSlot(timeSlots.selected);

                            document.getElementById("edit-timeslot").classList.add("hidden");
                            document.getElementById("edit-info").classList.remove("hidden");
                        });

                        // Show error if trying to create lab without timeslots
                        document.getElementById("form").addEventListener("submit", function (event) {
                            if (timeSlots.isEmpty()) {
                                document.getElementById("time-slot-warning").removeAttribute("hidden");
                                event.preventDefault();
                            }
                        });
                    });
                </script>

                <div class="grid col-2 align-center gap-3" style="--col-1: minmax(0, 29rem)">
                    <label for="slot-open-input">Slot selection opens at:</label>
                    <div>
                        <input
                            th:classappend="${#fields.hasErrors('slottedLabConfig.selectionOpensAt')} ? 'is-invalid'"
                            type="datetime-local"
                            id="slot-open-input"
                            th:field="*{slottedLabConfig.selectionOpensAt}"
                            class="textfield"
                            required />
                        <div
                            class="colour-error"
                            th:if="${#fields.hasErrors('slottedLabConfig.selectionOpensAt')}"
                            th:errors="*{slottedLabConfig.selectionOpensAt}">
                            Slot opensAt error
                        </div>
                    </div>

                    <div style="grid-column: span 2">
                        <input id="slot-disable-late-enrollment-input" type="checkbox" th:field="*{slottedLabConfig.disableLateEnrollment}" />
                        <label for="slot-disable-late-enrollment-input">Disallow enrollment in ongoing slots</label>
                    </div>

                    <th:block
                        th:with="consecutiveFilling = ${dto.slottedLabConfig.consideredFullPercentage != 0 or dto.slottedLabConfig.previousEmptyAllowedThreshold != 0}">
                        <div style="grid-column: span 2">
                            <input
                                id="consecutive-filling-checkbox"
                                type="checkbox"
                                class="form-check-input"
                                autocomplete="off"
                                th:checked="${consecutiveFilling}"
                                onchange="updateConsecutiveFillingVisibility()" />
                            <label for="consecutive-filling-checkbox">Consecutive Filling</label>
                        </div>

                        <label id="slot-full-percentage-label" for="slot-full-percentage" th:hidden="not ${consecutiveFilling}">
                            The percentage of a slot that has to be filled prior to opening subsequent slots:
                        </label>
                        <div id="slot-full-percentage-div" th:hidden="not ${consecutiveFilling}">
                            <input
                                id="slot-full-percentage"
                                type="number"
                                th:field="*{slottedLabConfig.consideredFullPercentage}"
                                class="textfield"
                                min="1"
                                max="100"
                                placeholder="50"
                                th:disabled="not ${consecutiveFilling}" />
                        </div>

                        <label id="empty-allowed-threshold-label" for="empty-allowed-threshold" th:hidden="not ${consecutiveFilling}">
                            The number of previous slots that are permitted to be below the percentage threshold:
                        </label>
                        <div id="empty-allowed-threshold-div" th:hidden="not ${consecutiveFilling}">
                            <input
                                id="empty-allowed-threshold"
                                type="number"
                                th:field="*{slottedLabConfig.previousEmptyAllowedThreshold}"
                                class="textfield"
                                min="0"
                                placeholder="0"
                                th:disabled="not ${consecutiveFilling}" />
                        </div>
                    </th:block>
                </div>

                <div class="mt-5 underlined"></div>

                <script th:inline="javascript">
                    function updateConsecutiveFillingVisibility() {
                        const checkbox = document.getElementById("consecutive-filling-checkbox");
                        const formElements = ["slot-full-percentage", "empty-allowed-threshold"].map(id => document.getElementById(id));
                        const toHide = [
                            "slot-full-percentage-label",
                            "empty-allowed-threshold-label",
                            "slot-full-percentage-div",
                            "empty-allowed-threshold-div",
                        ].map(id => document.getElementById(id));

                        if (checkbox.checked) {
                            formElements.forEach(elem => {
                                elem.setAttribute("required", "");
                                elem.removeAttribute("disabled");
                            });
                            toHide.forEach(elem => {
                                elem.removeAttribute("hidden");
                            });
                        } else {
                            formElements.forEach(elem => {
                                elem.removeAttribute("required");
                                elem.setAttribute("disabled", "");
                            });
                            toHide.forEach(elem => {
                                elem.setAttribute("hidden", "");
                            });
                        }
                    }
                </script>
            </section>
        </th:block>
    </body>
</html>
