/**
 * TutorHelper student booking form.
 */
document.addEventListener('DOMContentLoaded', function () {
	const containers = document.querySelectorAll(
		'[data-tutorhelper-student-booking]'
	);

	containers.forEach(function (container) {
		const form = container.querySelector(
			'[data-booking-form]'
		);

		if (!form) {
			return;
		}

        function getCurrentMonth() {
            const today = new Date();

            return [
                today.getFullYear(),
                String(today.getMonth() + 1).padStart(2, '0')
            ].join('-');
        }


        let selectedBookingTypeId = '';
        let visibleMonth = getCurrentMonth();
        let selectedDate = '';
        let selectedSlotStart = '';
        let selectedSlotEnd = '';
        let selectedLocationType = '';
        let timeRequestSequence = 0;

        

		const mode =
			container.dataset.bookingMode || 'student';

		const services = Array.from(
			container.querySelectorAll(
				'[data-booking-service]'
			)
		);

		const bookingTypeInput =
			container.querySelector(
				'[data-booking-type-id]'
			);

		const bookingStartInput =
			container.querySelector(
				'[data-booking-start]'
			);

		const bookingEndInput =
			container.querySelector(
				'[data-booking-end]'
			);

		const locationTypeInput =
			container.querySelector(
				'[data-booking-location-type]'
			);

		const summaryService =
			container.querySelector(
				'[data-summary-service]'
			);

		const summaryDate =
			container.querySelector(
				'[data-summary-date]'
			);

		const summaryTime =
			container.querySelector(
				'[data-summary-time]'
			);

		const summaryLocation =
			container.querySelector(
				'[data-summary-location]'
			);

		const calendar =
			container.querySelector(
				'[data-booking-calendar]'
			);

		const times =
			container.querySelector(
				'[data-booking-times]'
			);

		const submitButton =
			container.querySelector(
				'[data-booking-submit]'
			);

        const cancellationPolicy =
            container.querySelector(
                '[data-booking-cancellation-policy]'
            );

        const policyAgreement =
            container.querySelector(
                'input[name="policy_agreed"]'
            );

        const bookingMessage =
            container.querySelector(
                '[data-booking-message]'
            );

        if (calendar) {
            renderCalendar(
                visibleMonth,
                []
            );
        }

        

        function shiftMonth(month, offset) {
            const parts = month.split('-');
            const date = new Date(
                Number(parts[0]),
                Number(parts[1]) - 1 + offset,
                1
            );

            return [
                date.getFullYear(),
                String(date.getMonth() + 1).padStart(2, '0')
            ].join('-');
        }

        function escapeHtml(value) {
            const element =
                document.createElement('div');

            element.textContent =
                value === null || value === undefined
                    ? ''
                    : String(value);

            return element.innerHTML;
        }

        function getLocationLabel(locationType) {
            const labels = {
                online: 'Online',
                phone: 'Phone',
                in_person: 'In person',
                custom: 'Custom location',
                other: 'Other'
            };

            if (!locationType) {
                return tutorhelperStudentBooking
                    .strings.notSelected;
            }

            return labels[locationType]
                || locationType
                    .replace(/_/g, ' ')
                    .replace(
                        /\b\w/g,
                        function (character) {
                            return character.toUpperCase();
                        }
                    );
        }

        function getCancellationPolicyText(
            cancellationsAllowed,
            noticeHours
        ) {
            if (!cancellationsAllowed) {
                return 'Once your lesson has been confirmed, it cannot be cancelled through the online booking system. Please contact your tutor directly if your circumstances change.';
            }

            const hours =
                Number.parseInt(
                    noticeHours,
                    10
                );

            if (
                Number.isNaN(hours)
                || hours <= 0
            ) {
                return 'You may cancel this lesson before its scheduled start time.';
            }

            if (1 === hours) {
                return 'You may cancel this lesson up to 1 hour before its scheduled start time.';
            }

            if (
                0 === hours % 24
            ) {
                const days =
                    hours / 24;

                if (1 === days) {
                    return 'You may cancel this lesson up to 1 day before its scheduled start time.';
                }

                return 'You may cancel this lesson up to '
                    + days
                    + ' days before its scheduled start time.';
            }

            return 'You may cancel this lesson up to '
                + hours
                + ' hours before its scheduled start time.';
        }


        function clearBookingMessage() {
            if (!bookingMessage) {
                return;
            }

            bookingMessage.hidden = true;
            bookingMessage.textContent = '';

            bookingMessage.classList.remove(
                'is-success',
                'is-error'
            );
        }

        function showBookingMessage(
            message,
            type
        ) {
            if (!bookingMessage) {
                return;
            }

            bookingMessage.textContent =
                message;

            bookingMessage.hidden = false;

            bookingMessage.classList.toggle(
                'is-success',
                'success' === type
            );

            bookingMessage.classList.toggle(
                'is-error',
                'error' === type
            );

            bookingMessage.scrollIntoView({
                behavior: 'smooth',
                block: 'nearest'
            });
        }

        function updateSubmitState() {
            if (!submitButton) {
                return;
            }

            const hasCompleteSelection =
                Boolean(
                    selectedBookingTypeId
                    && selectedDate
                    && selectedSlotStart
                    && selectedSlotEnd
                    && selectedLocationType
                );

            const hasPolicyAgreement =
                Boolean(
                    policyAgreement
                    && policyAgreement.checked
                );

            submitButton.disabled =
                'preview' === mode
                || ! hasCompleteSelection
                || ! hasPolicyAgreement;
        }


        async function loadAvailableDates(month) {
            if (
                ! selectedBookingTypeId
                || ! calendar
            ) {
                return;
            }

            visibleMonth = month;

            renderCalendar(
                visibleMonth,
                [],
                false
            );

            calendar.setAttribute(
                'aria-busy',
                'true'
            );

            const body =
                new URLSearchParams({
                    action:
                        tutorhelperStudentBooking
                            .actions.dates,

                    nonce:
                        tutorhelperStudentBooking
                            .nonce,

                    booking_type_id:
                        selectedBookingTypeId,

                    month:
                        visibleMonth
                });

            try {
                const response = await fetch(
                    tutorhelperStudentBooking.ajaxUrl,
                    {
                        method: 'POST',
                        credentials: 'same-origin',
                        headers: {
                            'Content-Type':
                                'application/x-www-form-urlencoded; charset=UTF-8'
                        },
                        body: body.toString()
                    }
                );

                const payload =
                    await response.json();

                if (
                    ! payload.success
                    || ! payload.data
                ) {
                    throw new Error(
                        payload.data
                        && payload.data.message
                            ? payload.data.message
                            : ''
                    );
                }

                renderCalendar(
                    visibleMonth,
                    payload.data.available_dates || [],
                    true
                );

                calendar.removeAttribute(
                    'aria-busy'
                );
            } catch (error) {
                calendar.removeAttribute(
                    'aria-busy'
                );

                calendar.innerHTML =
                    '<p class="tutorhelper-student-booking__placeholder">'
                    + escapeHtml(
                        error.message
                        || tutorhelperStudentBooking
                            .strings.dateError
                    )
                    + '</p>';
            }
        }

        async function loadAvailableTimes(
            bookingTypeId,
            date
        ) {
            timeRequestSequence += 1;

            const requestSequence =
                timeRequestSequence;

            if (
                ! bookingTypeId
                || ! date
                || ! times
            ) {
                return;
            }

            selectedSlotStart = '';
            selectedSlotEnd = '';
            selectedLocationType = '';

            if (bookingStartInput) {
                bookingStartInput.value = '';
            }

            if (bookingEndInput) {
                bookingEndInput.value = '';
            }

            if (summaryTime) {
                summaryTime.textContent =
                    tutorhelperStudentBooking
                        .strings.notSelected;
            }

            if (submitButton) {
                submitButton.disabled = true;
            }

            times.setAttribute(
                'aria-busy',
                'true'
            );

            times.innerHTML =
                '<p class="tutorhelper-student-booking__placeholder">'
                + escapeHtml(
                    tutorhelperStudentBooking
                        .strings.loadingTimes
                )
                + '</p>';

            const body =
                new URLSearchParams({
                    action:
                        tutorhelperStudentBooking
                            .actions.times,

                    nonce:
                        tutorhelperStudentBooking
                            .nonce,

                    booking_type_id:
                        bookingTypeId,

                    date:
                        date
                });

            try {
                const response = await fetch(
                    tutorhelperStudentBooking.ajaxUrl,
                    {
                        method: 'POST',
                        credentials: 'same-origin',
                        headers: {
                            'Content-Type':
                                'application/x-www-form-urlencoded; charset=UTF-8'
                        },
                        body: body.toString()
                    }
                );

                const payload =
                    await response.json();

                if (
                    ! payload.success
                    || ! payload.data
                ) {
                    throw new Error(
                        payload.data
                        && payload.data.message
                            ? payload.data.message
                            : ''
                    );
                }

                if (
                    requestSequence
                    !== timeRequestSequence
                    || date !== selectedDate
                    || bookingTypeId
                        !== selectedBookingTypeId
                ) {
                    return;
                }


                renderTimeSlots(
                    payload.data.slots || []
                );
            } catch (error) {
                if (
                    requestSequence
                    !== timeRequestSequence
                ) {
                    return;
                }

                times.innerHTML =
                    '<p class="tutorhelper-student-booking__placeholder">'
                    + escapeHtml(
                        error.message
                        || tutorhelperStudentBooking
                            .strings.timeError
                    )
                    + '</p>';
            } finally {
                times.removeAttribute(
                    'aria-busy'
                );
            }
        }

        function renderTimeSlots(slots) {
            if (!times) {
                return;
            }

            if (
                ! Array.isArray(slots)
                || 0 === slots.length
            ) {
                times.innerHTML =
                    '<p class="tutorhelper-student-booking__placeholder">'
                    + escapeHtml(
                        tutorhelperStudentBooking
                            .strings.noTimes
                    )
                    + '</p>';

                return;
            }

            let html =
                '<div class="tutorhelper-student-booking__time-list">';

            slots.forEach(function (slot) {
                const start =
                    slot.start || '';

                const end =
                    slot.end || '';

                const label =
                    slot.label || '';

                const locationType =
                    slot.location_type || '';

                const isSelected =
                    selectedSlotStart === start;

                html +=
                    '<button'
                    + ' type="button"'
                    + ' class="tutorhelper-student-booking__time'
                    + (
                        isSelected
                            ? ' is-selected'
                            : ''
                    )
                    + '"'
                    + ' data-booking-slot'
                    + ' data-booking-start="'
                    + escapeHtml(start)
                    + '"'
                    + ' data-booking-end="'
                    + escapeHtml(end)
                    + '"'
                    + ' data-booking-location-type="'
                    + escapeHtml(locationType)
                    + '"'
                    + ' aria-pressed="'
                    + (
                        isSelected
                            ? 'true'
                            : 'false'
                    )
                    + '">'
                    + escapeHtml(label)
                    + '</button>';
            });

            html += '</div>';

            times.innerHTML = html;

            times
                .querySelectorAll(
                    '[data-booking-slot]'
                )
                .forEach(function (button) {
                    button.addEventListener(
                        'click',
                        function () {
                            selectTimeSlot(
                                button,
                                slots
                            );
                        }
                    );
                });
        }

        function selectTimeSlot(
            button,
            slots
        ) {
            selectedSlotStart =
                button.dataset.bookingStart
                || '';

            selectedSlotEnd =
                button.dataset.bookingEnd
                || '';

            selectedLocationType =
                button.dataset
                    .bookingLocationType
                || '';

            if (bookingStartInput) {
                bookingStartInput.value =
                    selectedSlotStart;
            }

            if (bookingEndInput) {
                bookingEndInput.value =
                    selectedSlotEnd;
            }

            if (locationTypeInput) {
                locationTypeInput.value =
                    selectedLocationType;
            }

            if (summaryTime) {
                summaryTime.textContent =
                    button.textContent.trim();
            }

            if (summaryLocation) {
                summaryLocation.textContent =
                    getLocationLabel(
                        selectedLocationType
                    );
            }

            renderTimeSlots(slots);

            container.dispatchEvent(
                new CustomEvent(
                    'tutorhelper:booking-time-selected',
                    {
                        detail: {
                            bookingTypeId:
                                selectedBookingTypeId,

                            date:
                                selectedDate,

                            start:
                                selectedSlotStart,

                            end:
                                selectedSlotEnd,

                            locationType:
                                selectedLocationType
                        }
                    }
                )
            );

            updateSubmitState();
        }



        function renderCalendar(
            month,
            availableDates,
            showEmptyMessage = false
        ) {
            const parts = month.split('-');

            const year = Number(parts[0]);
            const monthIndex = Number(parts[1]) - 1;

            const firstDay =
                new Date(year, monthIndex, 1);

            const finalDay =
                new Date(year, monthIndex + 1, 0);

            const formatter =
                new Intl.DateTimeFormat(
                    undefined,
                    {
                        month: 'long',
                        year: 'numeric'
                    }
                );

            const available =
                new Set(availableDates);

            let html =
                '<div class="tutorhelper-student-booking__calendar-header">'
                + '<button type="button" data-calendar-previous aria-label="Previous month">‹</button>'
                + '<strong>'
                + escapeHtml(
                    formatter.format(firstDay)
                )
                + '</strong>'
                + '<button type="button" data-calendar-next aria-label="Next month">›</button>'
                + '</div>';

            html +=
                '<div class="tutorhelper-student-booking__calendar-weekdays">';

            ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
                .forEach(function (label) {
                    html +=
                        '<span>'
                        + escapeHtml(label)
                        + '</span>';
                });

            html += '</div>';

            html +=
                '<div class="tutorhelper-student-booking__calendar-days">';

            const leadingDays =
                (firstDay.getDay() + 6) % 7;

            const todayDate =
                new Date();

            const today =
                [
                    todayDate.getFullYear(),
                    String(
                        todayDate.getMonth() + 1
                    ).padStart(2, '0'),
                    String(
                        todayDate.getDate()
                    ).padStart(2, '0')
                ].join('-');


            for (
                let blank = 0;
                blank < leadingDays;
                blank += 1
            ) {
                html +=
                    '<span class="tutorhelper-student-booking__calendar-blank"></span>';
            }

            for (
                let day = 1;
                day <= finalDay.getDate();
                day += 1
            ) {
                const date =
                    [
                        year,
                        String(monthIndex + 1).padStart(2, '0'),
                        String(day).padStart(2, '0')
                    ].join('-');

                const isAvailable =
                    available.has(date);

                const isSelected =
                    selectedDate === date;

                const isToday =
	                today === date;

                html +=
                    '<button'
                    + ' type="button"'
                    + ' class="tutorhelper-student-booking__calendar-day'
                    + (
                        isAvailable
                            ? ' is-available'
                            : ''
                    )
                    + (
                        isToday
                            ? ' is-today'
                            : ''
                    )
                    + (
                        isSelected
                            ? ' is-selected'
                            : ''
                    )
                    + '"'
                    + ' data-booking-date="'
                    + escapeHtml(date)
                    + '"'
                    + (
                        isAvailable
                            ? ''
                            : ' disabled'
                    )
                    + ' aria-pressed="'
                    + (
                        isSelected
                            ? 'true'
                            : 'false'
                    )
                    + '">'
                    + day
                    + '</button>';
            }

            html += '</div>';

            if (
                showEmptyMessage
                && 0 === available.size
            ) {
                html +=
                    '<p class="tutorhelper-student-booking__calendar-empty">'
                    + escapeHtml(
                        tutorhelperStudentBooking
                            .strings.noDates
                    )
                    + '</p>';
            }

            calendar.innerHTML = html;

            const previousButton =
                calendar.querySelector(
                    '[data-calendar-previous]'
                );

            const nextButton =
                calendar.querySelector(
                    '[data-calendar-next]'
                );

            if (previousButton) {
                previousButton.addEventListener(
                    'click',
                    function () {
                        const previousMonth =
                            shiftMonth(
                                visibleMonth,
                                -1
                            );

                        if (selectedBookingTypeId) {
                            loadAvailableDates(
                                previousMonth
                            );
                        } else {
                            visibleMonth =
                                previousMonth;

                            renderCalendar(
                                visibleMonth,
                                []
                            );
                        }
                    }
                );
            }

            if (nextButton) {
                nextButton.addEventListener(
                    'click',
                    function () {
                        const nextMonth =
                            shiftMonth(
                                visibleMonth,
                                1
                            );

                        if (selectedBookingTypeId) {
                            loadAvailableDates(
                                nextMonth
                            );
                        } else {
                            visibleMonth =
                                nextMonth;

                            renderCalendar(
                                visibleMonth,
                                [],
                                false
                            );
                        }
                    }
                );
            }

            calendar
                .querySelectorAll(
                    '[data-booking-date]:not(:disabled)'
                )
                .forEach(function (button) {
                    button.addEventListener(
                        'click',
                        function () {
                            selectedDate =
                                button.dataset
                                    .bookingDate
                                || '';

                            if (summaryDate) {
                                summaryDate.textContent =
                                    new Intl.DateTimeFormat(
                                        undefined,
                                        {
                                            weekday: 'long',
                                            day: 'numeric',
                                            month: 'long',
                                            year: 'numeric'
                                        }
                                    ).format(
                                        new Date(
                                            selectedDate
                                                + 'T12:00:00'
                                        )
                                    );
                            }

                            renderCalendar(
                                visibleMonth,
                                Array.from(
                                    available
                                ),
                                true
                            );

                            loadAvailableTimes(
                                selectedBookingTypeId,
                                selectedDate
                            );

                            container.dispatchEvent(
                                new CustomEvent(
                                    'tutorhelper:booking-date-selected',
                                    {
                                        detail: {
                                            bookingTypeId:
                                                selectedBookingTypeId,

                                            date:
                                                selectedDate
                                        }
                                    }
                                )
                            );
                        }
                    );
                });
        }

		/**
		 * Reset date and time selections when the service changes.
		 */
		function resetDateAndTime() {
            selectedDate = '';
            selectedSlotStart = '';
            selectedSlotEnd = '';
            selectedLocationType = '';
            timeRequestSequence += 1;


			if (bookingStartInput) {
				bookingStartInput.value = '';
			}

			if (bookingEndInput) {
				bookingEndInput.value = '';
			}

            if (locationTypeInput) {
                locationTypeInput.value = '';
            }

            if (policyAgreement) {
                policyAgreement.checked = false;
            }

			if (summaryDate) {
				summaryDate.textContent =
					'Not selected';
			}

			if (summaryTime) {
				summaryTime.textContent =
					'Not selected';
			}

			if (calendar) {
                renderCalendar(
                    visibleMonth,
                    [],
                    false
                );
            }

			if (times) {
				times.innerHTML =
					'<p class="tutorhelper-student-booking__placeholder">'
					+ 'Select a date to view available times.'
					+ '</p>';
			}

			updateSubmitState();
		}

        function resetBookingInterface() {
            selectedBookingTypeId = '';

            services.forEach(function (service) {
                service.classList.remove(
                    'is-selected'
                );

                service.setAttribute(
                    'aria-pressed',
                    'false'
                );
            });

            if (bookingTypeInput) {
                bookingTypeInput.value = '';
            }

            if (summaryService) {
                summaryService.textContent =
                    tutorhelperStudentBooking
                        .strings.notSelected;
            }

            if (summaryLocation) {
                summaryLocation.textContent =
                    tutorhelperStudentBooking
                        .strings.notSelected;
            }

            if (cancellationPolicy) {
                cancellationPolicy.textContent =
                    'The cancellation policy for your selected service will appear here.';
            }

            resetDateAndTime();

            if (calendar) {
                renderCalendar(
                    visibleMonth,
                    [],
                    false
                );
            }

            updateSubmitState();
        }

		services.forEach(function (service) {
			service.addEventListener(
				'click',
				function () {
					services.forEach(
						function (otherService) {
							const selected =
								otherService === service;

							otherService.classList.toggle(
								'is-selected',
								selected
							);

							otherService.setAttribute(
								'aria-pressed',
								selected
									? 'true'
									: 'false'
							);
						}
					);

					const bookingTypeId =
						service.dataset.bookingTypeId
						|| '';

                    selectedBookingTypeId =
                        bookingTypeId;

                    selectedDate = '';

					const title =
						service.dataset.bookingTitle
						|| '';

					const locationType =
						service.dataset
							.bookingLocationType
						|| '';

					const locationLabel =
						service.dataset
							.bookingLocationLabel
						|| 'Not selected';

                    const cancellationsAllowed =
                        '1' === (
                            service.dataset
                                .bookingCancellationsAllowed
                            || '0'
                        );

                    const cancellationNoticeHours =
                        service.dataset
                            .bookingCancellationNoticeHours
                        || '0';

					resetDateAndTime();

                    if (bookingTypeInput) {
                        bookingTypeInput.value =
                            bookingTypeId;
                    }

                    if (locationTypeInput) {
                        locationTypeInput.value =
                            locationType;
                    }

                    if (summaryService) {
                        summaryService.textContent =
                            title
                            || tutorhelperStudentBooking
                                .strings.notSelected;
                    }

                    if (summaryLocation) {
                        summaryLocation.textContent =
                            locationLabel;
                    }

                    if (cancellationPolicy) {
                        cancellationPolicy.textContent =
                            getCancellationPolicyText(
                                cancellationsAllowed,
                                cancellationNoticeHours
                            );
                    }

                    loadAvailableDates(
                        visibleMonth
                    );

					container.dispatchEvent(
						new CustomEvent(
							'tutorhelper:booking-service-selected',
							{
								detail: {
									bookingTypeId:
										bookingTypeId,

									title:
										title,

									duration:
										service.dataset
											.bookingDuration
										|| '',

									price:
										service.dataset
											.bookingPrice
										|| '',

									locationType:
										locationType
								}
							}
						)
					);
				}
			);
		});


        if (policyAgreement) {
            policyAgreement.addEventListener(
                'change',
                updateSubmitState
            );
        }

        form.addEventListener(
            'submit',
            async function (event) {
                event.preventDefault();

                if ('preview' === mode) {
                    return;
                }

                if (
                    ! selectedBookingTypeId
                    || ! selectedDate
                    || ! selectedSlotStart
                    || ! selectedSlotEnd
                    || ! selectedLocationType
                    || ! policyAgreement
                    || ! policyAgreement.checked
                ) {
                    showBookingMessage(
                        tutorhelperStudentBooking
                            .strings.submitError,
                        'error'
                    );

                    return;
                }

                if (submitButton) {
                    submitButton.disabled = true;
                    submitButton.setAttribute(
                        'aria-busy',
                        'true'
                    );

                    submitButton.dataset
                        .originalLabel =
                            submitButton
                                .textContent;

                    submitButton.textContent =
                        tutorhelperStudentBooking
                            .strings.submitting;
                }

                clearBookingMessage();

                const body =
                    new URLSearchParams({
                        action:
                            tutorhelperStudentBooking
                                .actions.submit,

                        nonce:
                            tutorhelperStudentBooking
                                .nonce,

                        booking_type_id:
                            selectedBookingTypeId,

                        booking_start:
                            selectedSlotStart,

                        booking_end:
                            selectedSlotEnd,

                        timezone:
                            tutorhelperStudentBooking
                                .timezone,

                        location_type:
                            selectedLocationType
                    });

                try {
                    const response =
                        await fetch(
                            tutorhelperStudentBooking
                                .ajaxUrl,
                            {
                                method: 'POST',
                                credentials:
                                    'same-origin',
                                headers: {
                                    'Content-Type':
                                        'application/x-www-form-urlencoded; charset=UTF-8'
                                },
                                body:
                                    body.toString()
                            }
                        );

                    const payload =
                        await response.json();

                    if (
                        ! payload.success
                        || ! payload.data
                    ) {
                        throw new Error(
                            payload.data
                                && payload.data.message
                                    ? payload.data.message
                                    : ''
                        );
                    }

                    showBookingMessage(
                        payload.data.message
                            || tutorhelperStudentBooking
                                .strings.submitSuccess,
                        'success'
                    );

                    form.reset();

                    resetBookingInterface();
                } catch (error) {
                    showBookingMessage(
                        error.message
                            || tutorhelperStudentBooking
                                .strings.submitError,
                        'error'
                    );

                    if (submitButton) {
                        submitButton.disabled = false;
                    }
                } finally {
                    if (submitButton) {
                        submitButton.removeAttribute(
                            'aria-busy'
                        );

                        if (
                            submitButton.dataset
                                .originalLabel
                        ) {
                            submitButton.textContent =
                                submitButton.dataset
                                    .originalLabel;
                        }
                    }
                }
            }
        );

		if (
			mode === 'preview'
			&& submitButton
		) {
			submitButton.disabled = true;
		}

		form.addEventListener(
			'submit',
			function (event) {
				event.preventDefault();

				if (mode !== 'student') {
					return;
				}
			}
		);
	});
});
