/**
 * RSL Carousel System
 *
 * Image carousel/slideshow with auto-rotation, pause controls, keyboard navigation,
 * and intersection observer for visibility-based auto-play.
 *
 * @fileoverview Accessible carousel with auto-rotation and visibility detection
 * @version 2.0.0
 * @license MIT
 *
 * Key Features:
 * - Auto-rotation with configurable interval
 * - Pause on hover, focus, or manual control
 * - Intersection Observer for visibility-based auto-play
 * - Keyboard navigation support
 * - Previous/Next arrow navigation
 * - Indicator dots with auto-scroll
 * - Visual pause/resume notifications
 * - Modal integration for full-screen image view
 * - ARIA labels for accessibility
 * - JSON Layout API compatible
 *
 * Usage:
 * HTML markup requires:
 * - .responsive-slot-layout container
 * - .carousel-slide elements
 * - .slider-indicators-scroll with .slider-indicator elements
 * - .carousel-prev-arrow and .carousel-next-arrow buttons
 * - .slider element with data-auto-rotate="true" data-interval="3"
 *
 * Public API:
 * - RSL.Carousel.init() - Initialize all carousels on the page
 * - RSL.Carousel.create(container) - Initialize a specific carousel
 * - container.carouselStartAutoRotate() - Start auto-rotation
 * - container.carouselPause() - Pause auto-rotation
 * - window.carouselPause() - Pause all carousels
 * - window.carouselResume() - Resume all carousels
 */

(function() {
    'use strict';

    window.RSL = window.RSL || {};

    /**
     * Intersection Observer for visibility-based auto-play
     *
     * Automatically starts/stops carousel rotation when the carousel
     * enters or leaves the viewport. Improves performance by only
     * running carousels that are visible to the user.
     */
    var observer = new IntersectionObserver(
        function (entries) {
            entries.forEach(function (entry) {
                var container = entry.target;

                // Carousel is visible - start auto-rotation
                if (entry.isIntersecting) {
                    if (typeof container.carouselStartAutoRotate === "function") {
                        container.carouselStartAutoRotate();
                    }
                }
                // Carousel is not visible - pause auto-rotation
                else {
                    if (typeof container.carouselPause === "function") {
                        container.carouselPause();
                    }
                }
            });
        },
        { threshold: 0.1 } // Trigger when 10% of carousel is visible
    );

    window.RSL.Carousel = {
        /**
         * Track initialized carousel containers to prevent double-initialization
         */
        instances: new Set(),

        /**
         * Initialize all carousel containers on the page
         * Scans for .responsive-slot-layout elements that contain carousel slides
         * Used by JSON Layout API for auto-initialization
         */
        init: function() {
            var carouselContainers = document.querySelectorAll(".responsive-slot-layout");
            carouselContainers.forEach(function(container) {
                // Only initialize if it contains carousel slides
                var slides = container.querySelectorAll(".carousel-slide");
                if (slides.length > 0 && !RSL.Carousel.instances.has(container)) {
                    RSL.Carousel.create(container);
                }
            });
        },

        /**
         * Initialize a specific carousel container
         * @param {HTMLElement} container - The .responsive-slot-layout container element
         */
        create: function(container) {
            if (RSL.Carousel.instances.has(container)) {
                return; // Already initialized
            }

            RSL.Carousel._initializeCarousel(container);
            RSL.Carousel.instances.add(container);
        },

        /**
         * Initialize a single carousel
         * @private
         * @param {HTMLElement} container - The carousel container element
         */
        _initializeCarousel: function(container) {
            // ================================================================
            // DOM ELEMENTS
            // ================================================================

            var slides = Array.from(container.querySelectorAll(".carousel-slide"));
            var indicatorsContainer = container.querySelector(
                ".slider-indicators-scroll"
            );

            // Exit early if required elements are missing
            if (!slides.length || !indicatorsContainer) return;

            var indicators = Array.from(
                indicatorsContainer.querySelectorAll(".slider-indicator")
            );
            var prevBtn = container.querySelector(".carousel-prev-arrow");
            var nextBtn = container.querySelector(".carousel-next-arrow");
            var pauseContainer = container.querySelector(".pause-container");
            var sliderEl = container.querySelector(".slider");

            // ================================================================
            // STATE VARIABLES
            // ================================================================

            var slideCount = slides.length;
            var currentIndex = 0;

            /**
             * State flags for pause control
             *
             * isPaused: Temporary pause state (hover, focus)
             * pausedByUser: Explicit user pause via button/API
             *
             * Both flags must be false for auto-rotation to advance slides
             */
            var isPaused = false;      // temporary pause: hover, focus, etc.
            var pausedByUser = false;  // explicit pause via pause button / external JS

            /**
             * Auto-rotation configuration
             *
             * Read from data attributes on .slider element:
             * - data-auto-rotate="true" - Enable auto-rotation
             * - data-interval="3" - Rotation interval in seconds
             */
            var autoRotate =
                sliderEl && sliderEl.getAttribute("data-auto-rotate") === "true";
            var intervalSeconds = parseFloat(
                sliderEl && sliderEl.getAttribute("data-interval")
            );
            var autoRotateTimerId = null;

            // ================================================================
            // CORE SLIDE FUNCTIONS
            // ================================================================

            /**
             * Show a specific slide by index
             *
             * Hides all slides, shows the requested slide, updates active
             * indicator, and scrolls indicator container to keep active
             * indicator visible.
             *
             * @param {number} index - Slide index to display (0-based)
             */
            function showSlide(index) {
                // Validate index bounds
                if (index < 0 || index >= slideCount) return;

                // Hide all slides
                slides.forEach(function (slide) {
                    slide.style.display = "none";
                });

                // Show requested slide
                slides[index].style.display = "block";
                currentIndex = index;

                // Update active indicator
                indicators.forEach(function (indicator) {
                    indicator.classList.remove("active");
                });

                indicators[index].classList.add("active");
                updateIndicatorsScroll();
            }

            /**
             * Update indicator scroll position
             *
             * Automatically scrolls the indicator container to keep the
             * active indicator visible. Handles edge cases for first and
             * last indicators.
             */
            function updateIndicatorsScroll() {
                var activeIndicator = indicatorsContainer.querySelector(
                    ".slider-indicator.active"
                );
                if (!activeIndicator) return;

                // Calculate positions and dimensions
                var containerWidth = indicatorsContainer.offsetWidth;
                var activeIndicatorOffset = activeIndicator.offsetLeft;
                var activeIndicatorWidth = activeIndicator.offsetWidth;
                var containerScrollLeft = indicatorsContainer.scrollLeft;
                var containerVisibleWidth = containerScrollLeft + containerWidth;
                var indicatorVisibleLeft = activeIndicatorOffset - containerScrollLeft;
                var indicatorVisibleRight =
                    indicatorVisibleLeft + activeIndicatorWidth;

                // Check if active indicator is outside visible area
                if (
                    indicatorVisibleLeft < 0 ||
                    indicatorVisibleRight > containerVisibleWidth
                ) {
                    var scrollPosition;

                    // Indicator is to the left of visible area
                    if (indicatorVisibleLeft < 0) {
                        scrollPosition = activeIndicatorOffset - 2 * activeIndicatorWidth;
                    }
                    // Indicator is to the right of visible area
                    else {
                        scrollPosition =
                            activeIndicatorOffset -
                            containerWidth +
                            activeIndicatorWidth;
                    }

                    // Smooth scroll to calculated position
                    indicatorsContainer.scrollTo({
                        left: scrollPosition,
                        behavior: "smooth",
                    });
                }

                // Special handling for first indicator - scroll to start
                if (currentIndex === 0) {
                    indicatorsContainer.scrollTo({
                        left: 0,
                        behavior: "smooth",
                    });
                }
                // Special handling for last indicator - scroll to end
                else if (currentIndex === slideCount - 1) {
                    indicatorsContainer.scrollTo({
                        left: indicatorsContainer.scrollWidth,
                        behavior: "smooth",
                    });
                }
            }

            // ================================================================
            // VISUAL NOTIFICATION OVERLAYS
            // ================================================================

            /**
             * Create and display "Temporarily Paused" notification
             *
             * Shows a visual overlay indicating the carousel is temporarily
             * paused (hover, focus). Auto-removes after 5 seconds.
             * Removes any existing "Resuming" notification.
             */
            function createTemporarilyPauseDiv() {
                if (!pauseContainer) return;

                // Remove any existing resume notification
                var existingResumeDiv = pauseContainer.querySelector(
                    ".temporarily-resume"
                );
                if (existingResumeDiv) {
                    pauseContainer.removeChild(existingResumeDiv);
                }

                // Don't create duplicate pause notifications
                var existingPauseDiv = pauseContainer.querySelector(
                    ".temporarily-pause"
                );
                if (existingPauseDiv) return;

                // Create pause notification element
                var temporarilyPauseDiv = document.createElement("div");
                temporarilyPauseDiv.className = "temporarily-pause";
                temporarilyPauseDiv.textContent = "Temporarily Paused";
                pauseContainer.appendChild(temporarilyPauseDiv);

                // Auto-remove after 5 seconds
                setTimeout(function () {
                    if (temporarilyPauseDiv.parentNode === pauseContainer) {
                        pauseContainer.removeChild(temporarilyPauseDiv);
                    }
                }, 5000);
            }

            /**
             * Create and display "Resuming" notification
             *
             * Shows a visual overlay indicating the carousel is resuming
             * auto-rotation. Auto-removes after 5 seconds.
             * Removes any existing "Temporarily Paused" notification.
             */
            function createTemporarilyResumeDiv() {
                if (!pauseContainer) return;

                // Remove any existing pause notification
                var existingPauseDiv = pauseContainer.querySelector(
                    ".temporarily-pause"
                );
                if (existingPauseDiv) {
                    pauseContainer.removeChild(existingPauseDiv);
                }

                // Don't create duplicate resume notifications
                var existingResumeDiv = pauseContainer.querySelector(
                    ".temporarily-resume"
                );
                if (existingResumeDiv) return;

                // Create resume notification element
                var temporarilyResumeDiv = document.createElement("div");
                temporarilyResumeDiv.className = "temporarily-resume";
                temporarilyResumeDiv.textContent = "Resuming";
                pauseContainer.appendChild(temporarilyResumeDiv);

                // Auto-remove after 5 seconds
                setTimeout(function () {
                    if (temporarilyResumeDiv.parentNode === pauseContainer) {
                        pauseContainer.removeChild(temporarilyResumeDiv);
                    }
                }, 5000);
            }

            // ================================================================
            // AUTO-ROTATION CONTROL
            // ================================================================

            /**
             * Start auto-rotation timer
             *
             * Creates an interval that advances to the next slide at the
             * configured interval. Only advances if neither isPaused nor
             * pausedByUser flags are set.
             */
            function startAutoRotate() {
                // Only start if auto-rotate is enabled and interval is valid
                if (!autoRotate || isNaN(intervalSeconds)) return;

                // Prevent duplicate timers
                if (!autoRotateTimerId) {
                    autoRotateTimerId = setInterval(function () {
                        // Only advance if NOT paused for any reason
                        if (!isPaused && !pausedByUser) {
                            // Advance to next slide or wrap to first
                            if (currentIndex < slideCount - 1) {
                                showSlide(currentIndex + 1);
                            } else {
                                showSlide(0); // Loop back to first slide
                            }
                        }
                    }, intervalSeconds * 1000); // Convert seconds to milliseconds
                }
            }

            /**
             * Stop auto-rotation timer
             *
             * Clears the interval timer and resets the timer ID.
             */
            function stopAutoRotate() {
                if (autoRotateTimerId) {
                    clearInterval(autoRotateTimerId);
                    autoRotateTimerId = null;
                }
            }

            /**
             * Temporarily pause auto-rotation
             *
             * Sets the temporary pause flag. Used for hover, focus, etc.
             * Optionally shows pause notification overlay.
             *
             * @param {boolean} showMessage - Whether to show pause notification
             */
            function tempPause(showMessage) {
                isPaused = true;
                if (autoRotate && showMessage !== false) {
                    createTemporarilyPauseDiv();
                }
            }

            /**
             * Resume from temporary pause
             *
             * Clears the temporary pause flag. Only shows resume notification
             * if user hasn't manually paused the carousel.
             *
             * @param {boolean} showMessage - Whether to show resume notification
             */
            function tempResume(showMessage) {
                isPaused = false;
                // Only show "Resuming" if the user hasn't manually paused
                if (autoRotate && !pausedByUser && showMessage !== false) {
                    createTemporarilyResumeDiv();
                }
            }

            // ================================================================
            // PAUSE BUTTON CONTROL
            // ================================================================

            var pauseBtn = null;

            /**
             * Update pause button icon and label
             *
             * Changes button icon between pause/play based on current state
             * and updates ARIA label for accessibility.
             */
            function updatePauseButton() {
                if (!pauseBtn) return;
                var icon = pauseBtn.querySelector("i");
                if (!icon) return;

                if (pausedByUser) {
                    // Show play icon when paused
                    icon.className = "fa-solid fa-play";
                    pauseBtn.setAttribute(
                        "aria-label",
                        "Press Enter to resume this slideshow"
                    );
                } else {
                    // Show pause icon when playing
                    icon.className = "fa-solid fa-pause";
                    pauseBtn.setAttribute(
                        "aria-label",
                        "Press Enter to pause this slideshow"
                    );
                }
            }

            /**
             * Toggle user pause state
             *
             * Handles explicit user pause/resume via pause button or
             * global API. Manages state flags, timer, and notifications.
             */
            function toggleUserPause() {
                pausedByUser = !pausedByUser;

                if (pausedByUser) {
                    // User is explicitly pausing
                    if (sliderEl) sliderEl.classList.add("paused");
                    // Stop timer (pausedByUser flag also prevents advancement)
                    stopAutoRotate();
                    // Clear temp pause flag to prevent stuck state
                    isPaused = false;
                    createTemporarilyPauseDiv();
                } else {
                    // User is explicitly resuming
                    if (sliderEl) sliderEl.classList.remove("paused");
                    // Clear any leftover temporary pause
                    isPaused = false;
                    createTemporarilyResumeDiv();
                    startAutoRotate();
                }

                updatePauseButton();
            }

            /**
             * Create and add pause button to carousel controls
             *
             * Only created if auto-rotate is enabled. Button is inserted
             * before the previous arrow button.
             */
            if (autoRotate && prevBtn) {
                pauseBtn = document.createElement("div");
                pauseBtn.className = "pause-carousel slider-indicator";
                pauseBtn.innerHTML = '<i class="fa-solid fa-pause"></i>';
                pauseBtn.setAttribute("tabIndex", "0");
                pauseBtn.setAttribute(
                    "aria-label",
                    "Press Enter to pause/resume this slideshow"
                );
                prevBtn.parentElement.insertBefore(pauseBtn, prevBtn);

                // Click handler - toggle pause state
                pauseBtn.addEventListener("click", function (event) {
                    toggleUserPause();
                    event.preventDefault();
                });

                // Keyboard handler - Enter or Space toggles pause
                pauseBtn.addEventListener("keydown", function (event) {
                    if (event.key === "Enter" || event.key === " ") {
                        toggleUserPause();
                        event.preventDefault();
                    }
                });

                /**
                 * Focus/blur handlers for pause button
                 *
                 * Pauses carousel when button receives focus (keyboard navigation)
                 * but doesn't override manual user pause state.
                 */
                pauseBtn.addEventListener("focus", function () {
                    if (!pausedByUser) tempPause(false);
                });
                pauseBtn.addEventListener("blur", function () {
                    if (!pausedByUser) tempResume(false);
                });
            }

            // ================================================================
            // NAVIGATION ARROW CONTROLS
            // ================================================================

            /**
             * Previous button click handler
             *
             * Navigates to previous slide, wrapping to last slide if at first.
             * Temporarily pauses auto-rotation.
             */
            if (prevBtn) {
                prevBtn.addEventListener("click", function () {
                    if (currentIndex > 0) {
                        showSlide(currentIndex - 1);
                    } else {
                        showSlide(slideCount - 1); // Wrap to last slide
                    }
                    updateIndicatorsScroll();
                    tempPause(false); // Pause without notification
                });
            }

            /**
             * Next button click handler
             *
             * Navigates to next slide, wrapping to first slide if at last.
             * Temporarily pauses auto-rotation.
             */
            if (nextBtn) {
                nextBtn.addEventListener("click", function () {
                    if (currentIndex < slideCount - 1) {
                        showSlide(currentIndex + 1);
                    } else {
                        showSlide(0); // Wrap to first slide
                    }
                    updateIndicatorsScroll();
                    tempPause(false); // Pause without notification
                });
            }

            // ================================================================
            // INDICATOR KEYBOARD NAVIGATION
            // ================================================================

            /**
             * Set up keyboard navigation for indicator dots
             *
             * Each indicator:
             * - Is keyboard focusable (tabIndex="0")
             * - Shows corresponding slide on focus
             * - Pauses carousel while focused
             * - Supports Tab/Shift+Tab navigation between indicators
             */
            indicators.forEach(function (indicator, index) {
                // Make indicator keyboard focusable
                indicator.setAttribute("tabIndex", "0");

                /**
                 * Focus handler - pause and show slide
                 */
                indicator.addEventListener("focus", function () {
                    // Pause while focused
                    tempPause(false);
                    showSlide(index);
                });

                /**
                 * Blur handler - resume if not manually paused
                 */
                indicator.addEventListener("blur", function () {
                    if (!pausedByUser) {
                        tempResume(false);
                    }
                });

                /**
                 * Tab key handler - navigate between indicators
                 *
                 * Prevents default Tab behavior to keep focus within
                 * indicator strip. Shift+Tab moves backward, Tab moves forward.
                 */
                indicator.addEventListener("keydown", function (event) {
                    var activeIndex = index;
                    var nextIndex;
                    var prevIndex;

                    if (event.key === "Tab") {
                        if (event.shiftKey) {
                            // Shift+Tab - move to previous indicator
                            if (activeIndex === 0) return; // Allow tab out at first
                            event.preventDefault();
                            prevIndex = activeIndex - 1;
                            indicators[prevIndex].focus();
                        } else {
                            // Tab - move to next indicator
                            if (activeIndex === slideCount - 1) return; // Allow tab out at last
                            event.preventDefault();
                            nextIndex = activeIndex + 1;
                            indicators[nextIndex].focus();
                        }

                        // Show the new slide
                        showSlide(event.shiftKey ? prevIndex : nextIndex);
                    }
                });
            });

            // ================================================================
            // HOVER PAUSE/RESUME
            // ================================================================

            /**
             * Mouse enter handler - temporarily pause on hover
             *
             * Only pauses if user hasn't manually paused. This allows users
             * to read content without carousel advancing.
             */
            container.addEventListener("mouseenter", function () {
                // If the user has manually paused, hovering shouldn't change state
                if (!pausedByUser) {
                    tempPause(true); // Show pause notification
                }
            });

            /**
             * Mouse leave handler - resume after hover
             *
             * Only resumes if user hasn't manually paused. Respects
             * explicit user pause state.
             */
            container.addEventListener("mouseleave", function () {
                // Only resume on hover-out if the user has NOT manually paused
                if (!pausedByUser) {
                    tempResume(true); // Show resume notification
                }
            });

            // ================================================================
            // PUBLIC API
            // ================================================================

            /**
             * Public method: Start auto-rotation
             *
             * Called by Intersection Observer when carousel becomes visible.
             * Clears any stale temporary pause state.
             */
            container.carouselStartAutoRotate = function () {
                // Coming back into view: clear any stale temp pause and start
                isPaused = false;
                startAutoRotate();
            };

            /**
             * Public method: Pause carousel
             *
             * Called by Intersection Observer when carousel leaves viewport.
             * Stops timer but doesn't modify user pause flag.
             */
            container.carouselPause = function () {
                // Visibility pause: just stop timer; don't touch user flag
                stopAutoRotate();
            };

            /**
             * Global pause helper
             *
             * Pauses carousel if not already paused by user.
             * Note: Last carousel initialized wins for global functions.
             */
            window.carouselPause = function () {
                if (!pausedByUser) toggleUserPause();
            };

            /**
             * Global resume helper
             *
             * Resumes carousel if paused by user.
             * Note: Last carousel initialized wins for global functions.
             */
            window.carouselResume = function () {
                if (pausedByUser) toggleUserPause();
            };

            // ================================================================
            // INITIALIZATION
            // ================================================================

            // Show first slide
            showSlide(currentIndex);

            // Start auto-rotation if enabled
            startAutoRotate();

            // Add container to Intersection Observer for visibility detection
            observer.observe(container);
        }
    };

    /**
     * Auto-initialize on page load (for backward compatibility)
     */
    document.addEventListener('DOMContentLoaded', function() {
        RSL.Carousel.init();
    });

})();

// ========================================================================
// MODAL INTEGRATION FOR FULL-SCREEN IMAGE VIEW
// ========================================================================

/**
 * Global indicator click/keyboard handlers for modal integration
 *
 * When an indicator is clicked or activated with Enter key, opens a modal
 * with the full-size image and caption. Requires modal.js to be loaded.
 */
const indicators = Array.from(document.querySelectorAll(".slider-indicator"));

indicators.forEach((indicator) => {
    /**
     * Click handler - prevent event propagation
     *
     * Prevents clicks on indicators from bubbling up to parent elements
     */
    indicator.addEventListener("click", function (e) {
        e.stopPropagation(); // Prevent event propagation to parent elements
    });

    /**
     * Enter key handler - open modal with image
     *
     * Reads data attributes from indicator to populate modal with
     * full-size image and caption information.
     */
    indicator.addEventListener("keydown", function (e) {
        if (e.key === "Enter") {
            this.classList.add("focused");
            e.preventDefault(); // Prevent default Enter key behavior

            // Read data attributes for modal content
            const openModalAnimation = this.getAttribute("data-animation-in");
            const captionHeader = this.getAttribute("data-caption-header");
            const captionText = this.getAttribute("data-caption-text");
            const imageInSlide = this.getAttribute("data-slide-img");

            // Get modal container (requires modal.js)
            const modalContainer = document.getElementById("carousel-modal");
            const modal = modalContainer.querySelector(".modal");
            const openButton = this;
            const focusableElementsString =
                'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';

            // Prepare modal content
            const headerHTML = "";
            const bodyHTML = [imageInSlide, captionHeader, captionText];
            const footerHTML =
                "<button class='btn btn-success'>Okay</button><button class='btn btn-danger close-modal' aria-label='Close Modal' data-animation-out='rotateOut'>Cancel</button>";

            // Update modal content (requires modal.js function)
            updateModalContent(modalContainer, headerHTML, bodyHTML, footerHTML);

            // Show modal with animation
            modal.style.animation = `${openModalAnimation} 0.5s forwards`;
            modal.style.display = "block";

            // Open modal with focus trap (requires modal.js function)
            openModal(
                modalContainer,
                modal,
                openButton,
                focusableElementsString,
                openModalAnimation
            );

            // Pause slideshow while modal is open (external function)
            pauseSlideshow(".slider");
        }
    });
});
