/**
 * RSL Modal System
 *
 * Accessible, animated modal dialogs with focus trapping, keyboard navigation,
 * and dynamic content management. Supports multiple modals, programmatic control,
 * and integration with carousel and other RSL components.
 *
 * @fileoverview Full-featured modal dialog system with accessibility and animations
 * @version 2.0.0
 * @license MIT
 *
 * Key Features:
 * - WCAG 2.1 compliant focus trapping
 * - Keyboard navigation (Tab, Shift+Tab, Escape)
 * - Customizable entry/exit animations
 * - Dynamic content injection via data attributes or JavaScript
 * - Multiple modal support on single page
 * - Click-outside-to-close functionality
 * - Focus restoration to trigger element on close
 * - Programmatic and declarative API
 *
 * Usage:
 * <!-- Declarative (data attributes) -->
 * <button data-modal-target="#my-modal" data-animation-in="fadeIn"
 *         onclick="RSL.openFromTrigger(this)">Open Modal</button>
 * <div class="modal-container" id="my-modal">
 *   <div class="modal">...</div>
 * </div>
 *
 * <!-- Programmatic API -->
 * RSL.showModal({
 *   target: '#my-modal',
 *   title: '<h2>Title</h2>',
 *   body: ['<p>Content</p>'],
 *   footer: '<button class="close-modal">Close</button>',
 *   animationIn: 'slideInDown'
 * });
 *
 * Public API:
 * - RSL.openFromTrigger(buttonElement) - Open modal from data attributes
 * - RSL.showModal(options) - Open modal programmatically
 * - window.openModal() - Internal helper (exposed for integration)
 * - window.closeModal() - Internal helper (exposed for integration)
 * - window.updateModalContent() - Update modal content dynamically
 */

(function() {
    'use strict';

    // Initialize RSL namespace
    window.RSL = window.RSL || {};

    /**
     * RSL Modal Component
     * Public API for modal management and instance tracking
     */
    window.RSL.Modal = window.RSL.Modal || {
        instances: new Map(),

        /**
         * Initialize all modal instances on the page
         * Scans for .modal-container elements and sets up event handlers
         * Safe to call multiple times - prevents double-initialization
         */
        init: function() {
            const containers = document.querySelectorAll('.modal-container');
            containers.forEach(function(container) {
                if (!RSL.Modal.instances.has(container)) {
                    RSL.Modal.create(container);
                }
            });
        },

        /**
         * Create a modal instance for a container element
         * @param {HTMLElement} container - The .modal-container element
         * @returns {Object} Modal instance
         */
        create: function(container) {
            // Check if already initialized
            if (RSL.Modal.instances.has(container)) {
                return RSL.Modal.instances.get(container);
            }

            const modal = container.querySelector('.modal');
            const closeButtons = container.querySelectorAll('.close-modal');
            const openFrom = container.getAttribute('data-open-from');

            const instance = {
                container: container,
                modal: modal,
                closeButtons: closeButtons,
                openFrom: openFrom
            };

            // Always attach close button event listeners
            attachCloseModalEventListeners(container, modal, closeButtons, null);

            // Set up open button event listeners if data-open-from is present
            if (openFrom) {
                const openButtons = Array.from(document.querySelectorAll(openFrom));
                const focusableElementsString = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';

                openButtons.forEach(function(openButton) {
                    openButton.addEventListener('click', function() {
                        openModal(container, modal, openButton, focusableElementsString, this.getAttribute('data-animation-in'));
                    });
                });
            }

            // Store instance
            RSL.Modal.instances.set(container, instance);
            return instance;
        }
    };

    /**
     * All modal containers with data-open-from attribute
     * These are automatically activated on page load
     * @deprecated Use RSL.Modal.init() instead
     */
    const modalContainers = Array.from(document.querySelectorAll('.modal-container[data-open-from]'));

    /**
     * Close a modal with animation
     *
     * Plays exit animation, removes show state, clears event listeners,
     * and restores focus to the element that opened the modal.
     *
     * @param {HTMLElement} modalContainer - The .modal-container element
     * @param {HTMLElement} modal - The .modal element inside container
     * @param {string} animationOut - CSS animation name for exit (e.g., 'fadeOut')
     * @param {HTMLElement} openButton - Element to restore focus to after closing
     *
     * @example
     * closeModal(container, modal, 'slideOutUp', triggerButton);
     */
    function closeModal(modalContainer, modal, animationOut, openButton) {
        modal.style.animation = animationOut + ' 0.5s forwards';

        setTimeout(function() {
            modalContainer.classList.remove('show-modal');
            modal.style.animation = '';
        }, 500);

        modalContainer.removeEventListener('keydown', handleKeyDown);

        // Check if a focused indicator exists (carousel integration)
        const focusedElement = document.querySelector('.slider-indicator.focused');

        if (focusedElement) {
            focusedElement.focus();
            focusedElement.classList.remove('focused');
        } else if (openButton) {
            openButton.focus();
        }
    }

    /**
     * Handle keyboard navigation within modal (Tab, Shift+Tab)
     *
     * Implements focus trapping by cycling focus between first and last
     * focusable elements. Prevents Tab from leaving the modal.
     *
     * @param {HTMLElement} modalContainer - The .modal-container element
     * @param {string} focusableElementsString - CSS selector for focusable elements
     * @param {KeyboardEvent} e - The keyboard event
     */
    function handleKeyDown(modalContainer, focusableElementsString, e) {
        const focusableElements = Array.from(modalContainer.querySelectorAll(focusableElementsString));
        const firstFocusable = focusableElements[0];
        const lastFocusable = focusableElements[focusableElements.length - 1];

        if (e.key === 'Tab') {
            if (e.shiftKey && document.activeElement === firstFocusable) {
                lastFocusable.focus();
                e.preventDefault();
            } else if (!e.shiftKey && document.activeElement === lastFocusable) {
                firstFocusable.focus();
                e.preventDefault();
            }
        }
    }

    /**
     * Open a modal with animation and focus management
     *
     * Shows modal, sets ARIA attributes, traps focus, and plays entry animation.
     * Automatically focuses first focusable element for accessibility.
     *
     * @param {HTMLElement} modalContainer - The .modal-container element
     * @param {HTMLElement} modal - The .modal element inside container
     * @param {HTMLElement} openButton - Element that triggered the modal (for focus restoration)
     * @param {string} focusableElementsString - CSS selector for focusable elements
     * @param {string} animationIn - CSS animation name for entry (e.g., 'fadeIn')
     *
     * @example
     * openModal(container, modal, button, 'button, [href], input', 'bounceIn');
     */
    function openModal(modalContainer, modal, openButton, focusableElementsString, animationIn) {
        modalContainer.classList.add('show-modal');

        const modalContent = modal.textContent.trim();
        modalContainer.setAttribute(
            'aria-label',
            'Dialog open. ' + modalContent + '. Use Tab key to navigate through the modal, it will close if you trigger the event'
        );

        const firstFocusable = modalContainer.querySelector(focusableElementsString);
        if (firstFocusable) {
            firstFocusable.focus();
        }

        modal.style.animation = animationIn + ' 0.5s forwards';
        modalContainer.addEventListener('keydown', function(e) {
            handleKeyDown(modalContainer, focusableElementsString, e);
        });
    }

    /**
     * Attach close event listeners to modal close buttons and backdrop
     *
     * Binds click handlers to all .close-modal buttons within a modal and
     * enables click-outside-to-close by listening to container clicks.
     *
     * @param {HTMLElement} modalContainer - The .modal-container element
     * @param {HTMLElement} modal - The .modal element inside container
     * @param {NodeList} closeButtons - All .close-modal buttons in the modal
     * @param {HTMLElement} openButton - Element to restore focus to
     */
    function attachCloseModalEventListeners(modalContainer, modal, closeButtons, openButton) {
        closeButtons.forEach(function(closeButton) {
            closeButton.addEventListener('click', function() {
                closeModal(modalContainer, modal, this.getAttribute('data-animation-out'), openButton);
            });
        });

        modalContainer.addEventListener('click', function(event) {
            if (event.target === modalContainer) {
                closeModal(modalContainer, modal, closeButtons[0].getAttribute('data-animation-out'), openButton);
            }
        });
    }

    /**
     * Update modal content without attaching event listeners
     *
     * Dynamically injects HTML into modal header, body, and footer.
     * Body content can be a single string or array of strings (each becomes a .slot-item).
     * Does NOT attach event listeners - call attachCloseModalEventListeners() after if needed.
     *
     * @param {HTMLElement} modalContainer - The .modal-container element
     * @param {string} [headerHTML=''] - HTML for modal title area
     * @param {string[]|string} [bodyHTML=[]] - Array of HTML strings or single HTML string for body
     * @param {string} [footerHTML=''] - HTML for modal footer (buttons, etc.)
     *
     * @example
     * updateModalContent(
     *   container,
     *   '<h2>Title</h2>',
     *   ['<p>Paragraph 1</p>', '<p>Paragraph 2</p>'],
     *   '<button class="close-modal">Close</button>'
     * );
     */
    function updateModalContent(modalContainer, headerHTML, bodyHTML, footerHTML) {
        headerHTML = headerHTML || '';
        bodyHTML = bodyHTML || [];
        footerHTML = footerHTML || '';

        if (!modalContainer) return;

        const modalHeader = modalContainer.querySelector('.modal-header');
        const titleEl = modalHeader ? modalHeader.querySelector('#modalTitle') : null;
        const modalBody = modalContainer.querySelector('.modal-body');
        const modalFooter = modalContainer.querySelector('.modal-footer');

        if (titleEl && headerHTML !== '') {
            titleEl.innerHTML = headerHTML;
        }

        if (modalBody && (Array.isArray(bodyHTML) ? bodyHTML.length > 0 : typeof bodyHTML === 'string')) {
            const items = Array.isArray(bodyHTML) ? bodyHTML : [bodyHTML];
            modalBody.innerHTML = '';
            items.forEach(function(content) {
                const slotItem = document.createElement('div');
                slotItem.classList.add('slot-item');
                slotItem.innerHTML = content;
                modalBody.appendChild(slotItem);
            });
        }

        if (modalFooter && footerHTML !== '') {
            modalFooter.innerHTML = footerHTML;
        }
    }

    /**
     * Activate all modals with data-open-from attributes
     * @deprecated Use RSL.Modal.init() instead
     *
     * Finds all buttons matching the data-open-from selector and attaches
     * click handlers to open their associated modals.
     */
    function activateModals() {
        modalContainers.forEach(function(modalContainer) {
            const openButtons = Array.from(document.querySelectorAll(modalContainer.getAttribute('data-open-from')));
            const modal = modalContainer.querySelector('.modal');
            const closeButtons = modalContainer.querySelectorAll('.close-modal');
            const focusableElementsString = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';

            openButtons.forEach(function(openButton) {
                openButton.addEventListener('click', function() {
                    openModal(modalContainer, modal, openButton, focusableElementsString, this.getAttribute('data-animation-in'));
                });
            });

            attachCloseModalEventListeners(modalContainer, modal, closeButtons, openButtons[0]);
        });
    }

    // Auto-initialize on page load
    document.addEventListener('DOMContentLoaded', function() {
        RSL.Modal.init();
    });

    /**
     * Open modal from trigger button using data attributes
     *
     * Reads all modal configuration from data attributes on the button element:
     * - data-modal-target: CSS selector for modal container
     * - data-modal-title: HTML for title
     * - data-modal-body: JSON array of body HTML strings
     * - data-modal-body-selector: CSS selector to pull body content from DOM
     * - data-modal-footer: HTML for footer
     * - data-animation-in: Entry animation name
     *
     * @param {HTMLElement} btnEl - Button element with data attributes
     *
     * @example
     * <button data-modal-target="#my-modal"
     *         data-modal-title="<h2>Title</h2>"
     *         data-modal-body='["<p>Content</p>"]'
     *         data-animation-in="fadeIn"
     *         onclick="RSL.Modal.openFromTrigger(this)">
     *   Open Modal
     * </button>
     */
    RSL.Modal.openFromTrigger = function(btnEl) {
        const targetSel = btnEl.getAttribute('data-modal-target');
        const container = document.querySelector(targetSel);
        if (!container) return;

        // Ensure the modal is initialized before opening
        if (!RSL.Modal.instances.has(container)) {
            RSL.Modal.create(container);
        }

        const modal = container.querySelector('.modal');
        const focusables = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';

        const title = btnEl.getAttribute('data-modal-title') || '';
        const footer = btnEl.getAttribute('data-modal-footer') || '';
        const animIn = btnEl.getAttribute('data-animation-in') || 'fadeIn';

        let body = [];
        const json = btnEl.getAttribute('data-modal-body');
        const sel = btnEl.getAttribute('data-modal-body-selector');

        if (sel) {
            body = Array.from(document.querySelectorAll(sel)).map(function(el) {
                return el.innerHTML;
            });
        } else if (json) {
            try {
                body = JSON.parse(json);
            } catch (e) {
                body = [json];
            }
        }

        updateModalContent(container, title, body, footer);

        // Note: Close button listeners are already attached in create()
        // No need to attach them again here

        openModal(container, modal, btnEl, focusables, animIn);
    };

    /**
     * Programmatically open a modal with options object
     *
     * Provides full control over modal content and behavior via JavaScript.
     * Useful for dynamic modals, AJAX content, or complex integrations.
     *
     * @param {Object} opts - Configuration options
     * @param {string|HTMLElement} opts.target - Modal container selector or element
     * @param {string} [opts.title=''] - HTML for title area
     * @param {string[]|string} [opts.body=[]] - Array of HTML strings or single HTML string
     * @param {string} [opts.footer=''] - HTML for footer
     * @param {string} [opts.animationIn='fadeIn'] - Entry animation name
     * @param {HTMLElement|null} [opts.trigger=null] - Element to restore focus to
     * @param {string} [opts.bodySelector] - CSS selector to pull body content from DOM
     *
     * @example
     * RSL.Modal.showModal({
     *   target: '#confirmation-modal',
     *   title: '<h2>Confirm Action</h2>',
     *   body: ['<p>Are you sure?</p>'],
     *   footer: '<button class="btn close-modal" data-animation-out="fadeOut">Yes</button>',
     *   animationIn: 'bounceIn',
     *   trigger: document.querySelector('.delete-button')
     * });
     */
    RSL.Modal.showModal = function(opts) {
        opts = opts || {};
        const target = opts.target;
        const title = opts.title || '';
        let body = opts.body || [];
        const footer = opts.footer || '';
        const animationIn = opts.animationIn || 'fadeIn';
        const trigger = opts.trigger || null;
        const bodySelector = opts.bodySelector;

        const container = typeof target === 'string' ? document.querySelector(target) : target;
        if (!container) return;

        // Ensure the modal is initialized before opening
        if (!RSL.Modal.instances.has(container)) {
            RSL.Modal.create(container);
        }

        const modal = container.querySelector('.modal');
        const focusables = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';

        if (bodySelector) {
            body = Array.from(document.querySelectorAll(bodySelector)).map(function(el) {
                return el.innerHTML;
            });
        } else if (!Array.isArray(body)) {
            body = [body];
        }

        updateModalContent(container, title, body, footer);

        // Note: Close button listeners are already attached in create()
        // No need to attach them again here

        openModal(container, modal, trigger || container, focusables, animationIn);
    };

    // Backward compatibility aliases
    RSL.openFromTrigger = RSL.Modal.openFromTrigger;
    RSL.showModal = RSL.Modal.showModal;

    // Expose helpers for integration with other components (carousel, etc.)
    window.openModal = openModal;
    window.closeModal = closeModal;
    window.updateModalContent = updateModalContent;

})();
