/**
 * RSL Tabs System
 *
 * Accessible tabbed interface component with keyboard navigation, ARIA support,
 * and optional skip links for enhanced accessibility. Supports multiple tab
 * groups on a single page with independent state management.
 *
 * @fileoverview WCAG 2.1 compliant tabs component with keyboard navigation
 * @version 2.4.0
 * @license MIT
 *
 * Key Features:
 * - WCAG 2.1 Level AA compliant
 * - Arrow key navigation between tabs (Left/Right)
 * - Tab key exits tab list to content panel
 * - Home/End keys jump to first/last tab
 * - Enter/Space to activate tabs (manual activation mode)
 * - Automatic ARIA attribute management
 * - Optional skip links for screen reader users
 * - Multiple tab groups per page
 * - Integration with ADAcompliantNavigator utility
 * - JSON Layout API compatible
 * - FilterBus integration for visibility filtering
 * - Date range filtering support
 *
 * Usage:
 * <div class="tabs-display">
 *   <div class="slot-layout tabs">
 *     <a class="tab-link" data-tab="tab1">Tab 1</a>
 *     <a class="tab-link" data-tab="tab2">Tab 2</a>
 *   </div>
 *   <div class="tab-content" data-tab="tab1">Content 1</div>
 *   <div class="tab-content" data-tab="tab2">Content 2</div>
 * </div>
 *
 * FilterBus Integration:
 * <div class="tabs-display"
 *      data-filter-subscribe="category"
 *      data-filter-value="Sales">
 *   <!-- Tab group shows when category filter is "Sales" or "All" -->
 * </div>
 *
 * Date Range Filtering:
 * <div class="tabs-display"
 *      data-date="2025-12-15">
 *   <!-- Tab group shows when date picker range includes Dec 15, 2025 -->
 * </div>
 *
 * Public API:
 * - RSL.Tabs.init() - Initialize all tab groups on the page
 * - RSL.Tabs.create(container) - Initialize a specific tabs-display container
 *
 * Requires:
 * - ADAcompliantNavigator function for skip links (optional)
 */

(function() {
    'use strict';

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

    /**
     * Track FilterBus subscriptions for cleanup
     * @type {Map<HTMLElement, string>}
     */
    var filterSubscriptions = new Map();

    /**
     * Track date filter subscriptions separately
     * @type {Map<HTMLElement, string>}
     */
    var dateFilterSubscriptions = new Map();

    /**
     * Parse a date string into a Date object
     * Supports ISO (YYYY-MM-DD), US (MM/DD/YYYY), and European (DD.MM.YYYY) formats
     * @param {string|Date} dateStr - Date string or Date object
     * @returns {Date|null} Parsed date or null if invalid
     */
    function parseDate(dateStr) {
        if (!dateStr) return null;
        if (dateStr instanceof Date) return dateStr;

        var str = String(dateStr).trim();

        // ISO format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS
        if (/^\d{4}-\d{2}-\d{2}/.test(str)) {
            var d = new Date(str);
            if (!isNaN(d.getTime())) return d;
        }

        // US format: MM/DD/YYYY
        if (/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(str)) {
            var parts = str.split('/');
            var d = new Date(parseInt(parts[2]), parseInt(parts[0]) - 1, parseInt(parts[1]));
            if (!isNaN(d.getTime())) return d;
        }

        // European format: DD.MM.YYYY
        if (/^\d{1,2}\.\d{1,2}\.\d{4}$/.test(str)) {
            var parts = str.split('.');
            var d = new Date(parseInt(parts[2]), parseInt(parts[1]) - 1, parseInt(parts[0]));
            if (!isNaN(d.getTime())) return d;
        }

        // Fallback to native parsing
        var fallback = new Date(str);
        return isNaN(fallback.getTime()) ? null : fallback;
    }

    /**
     * Setup date filter subscription for a tabs container
     * @param {HTMLElement} container - The .tabs-display container
     */
    function setupDateFilterSubscription(container) {
        // Check if FilterBus is available
        if (!window.RSL || !window.RSL.FilterBus) {
            return;
        }

        // Check if this container has a date attribute
        var dateAttr = container.getAttribute('data-date');
        if (!dateAttr) {
            return;
        }

        // Don't double-subscribe
        if (dateFilterSubscriptions.has(container)) {
            return;
        }

        // Generate unique subscriber ID
        var subscriberId = 'tabs-date-' + (container.id || Math.random().toString(36).substr(2, 9));

        // Subscribe to all FilterBus state changes to catch date picker updates
        window.RSL.FilterBus.subscribe(
            subscriberId,
            function(state, meta) {
                handleDateFilterChange(container, state, meta);
            }
        );

        // Store subscription ID for cleanup
        dateFilterSubscriptions.set(container, subscriberId);

        // Apply any existing FilterBus state on init
        var currentState = window.RSL.FilterBus.getState();
        if (Object.keys(currentState).length > 0) {
            handleDateFilterChange(container, currentState, { source: 'init' });
        }
    }

    /**
     * Handle date filter changes for tabs visibility
     * @param {HTMLElement} container - The .tabs-display container
     * @param {Object} state - Current filter state
     * @param {Object} meta - Change metadata
     */
    function handleDateFilterChange(container, state, meta) {
        if (!state) return;

        var tabDateStr = container.getAttribute('data-date');
        if (!tabDateStr) return;

        var tabDate = parseDate(tabDateStr);
        if (!tabDate) return;

        // Look for date filter in state (from date picker)
        var dateFilter = null;
        Object.keys(state).forEach(function(key) {
            var value = state[key];
            if (value && typeof value === 'object' && (value.mode === 'range' || value.mode === 'single')) {
                dateFilter = value;
            }
        });

        // If no date filter active, show the tab
        if (!dateFilter || !dateFilter.startDate) {
            container.classList.remove('tabs-display-date-hidden');
            return;
        }

        // Parse filter dates
        var filterStart = parseDate(dateFilter.startDate);
        var filterEnd = parseDate(dateFilter.endDate || dateFilter.startDate);

        if (!filterStart || !filterEnd) {
            container.classList.remove('tabs-display-date-hidden');
            return;
        }

        // Set end date to end of day for inclusive comparison
        filterEnd.setHours(23, 59, 59, 999);

        // Check if tab date is within range
        var shouldShow = tabDate >= filterStart && tabDate <= filterEnd;

        if (shouldShow) {
            container.classList.remove('tabs-display-date-hidden');
        } else {
            container.classList.add('tabs-display-date-hidden');
        }

        // Dispatch event
        container.dispatchEvent(new CustomEvent('rsl-tabs:date-filter-update', {
            bubbles: true,
            detail: { state: state, meta: meta, visible: shouldShow, tabDate: tabDate }
        }));
    }

    /**
     * Setup FilterBus subscription for a tabs container
     * @param {HTMLElement} container - The .tabs-display container
     */
    function setupFilterBusSubscription(container) {
        // Check if FilterBus is available
        if (!window.RSL || !window.RSL.FilterBus) {
            return;
        }

        // Check if this container has a subscription key
        var filterSubscribe = container.getAttribute('data-filter-subscribe');
        if (!filterSubscribe) {
            return;
        }

        // Don't double-subscribe
        if (filterSubscriptions.has(container)) {
            return;
        }

        // Generate unique subscriber ID
        var subscriberId = 'tabs-' + (container.id || Math.random().toString(36).substr(2, 9));

        // Subscribe to FilterBus
        window.RSL.FilterBus.subscribe(
            subscriberId,
            function(state, meta) {
                handleFilterBusChange(container, state, meta);
            },
            { keys: [filterSubscribe] }
        );

        // Store subscription ID for cleanup
        filterSubscriptions.set(container, subscriberId);

        // Apply any existing FilterBus state on init
        var currentState = window.RSL.FilterBus.getState();
        if (Object.keys(currentState).length > 0) {
            handleFilterBusChange(container, currentState, { source: 'init' });
        }
    }

    /**
     * Handle FilterBus state changes for tabs visibility
     * @param {HTMLElement} container - The .tabs-display container
     * @param {Object} state - Current filter state
     * @param {Object} meta - Change metadata
     */
    function handleFilterBusChange(container, state, meta) {
        if (!state) return;

        var filterSubscribe = container.getAttribute('data-filter-subscribe');
        if (!filterSubscribe) return;

        var filterValue = state[filterSubscribe];
        var componentValue = container.getAttribute('data-filter-value');

        // Determine visibility
        var shouldShow = true;

        if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
            // Check if filter is "All" (case-insensitive) - show everything
            var filterLower = String(filterValue).toLowerCase();
            if (filterLower === 'all') {
                shouldShow = true;
            } else if (componentValue !== undefined && componentValue !== null) {
                // Check if component's filter value matches the current filter
                // Support comma-separated values for multi-match
                var componentValues = String(componentValue).split(',').map(function(v) {
                    return v.trim().toLowerCase();
                });
                shouldShow = componentValues.includes(filterLower);
            }
            // If container has no filterValue, it always shows
        }

        // Apply visibility
        if (shouldShow) {
            container.classList.remove('tabs-display-hidden');
            container.removeAttribute('aria-hidden');
        } else {
            container.classList.add('tabs-display-hidden');
            container.setAttribute('aria-hidden', 'true');
        }

        // Dispatch event
        container.dispatchEvent(new CustomEvent('rsl-tabs:filterbus-update', {
            bubbles: true,
            detail: { state: state, meta: meta, visible: shouldShow }
        }));
    }

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

        /**
         * Initialize all tab groups on the page
         * Automatically called on DOMContentLoaded and by JSON Layout API
         */
        init: function() {
            // Configure skip links for accessibility if ADAcompliantNavigator is available
            if (typeof ADAcompliantNavigator === 'function') {
                ADAcompliantNavigator({
                    'id-or-class': '.tabs-display',
                    'require-skip-below-link': 'true',
                    'require-skip-above-link': 'true',
                    'skip-below-link-text': 'Skip Below Tabbed Content',
                    'skip-above-link-text': 'Skip Above Tabbed Content',
                    'link-class': 'adaContentJump'
                });
            }

            // Find all tab displays and initialize them
            const tabDisplays = document.querySelectorAll('.tabs-display');
            tabDisplays.forEach(function(container) {
                if (!RSL.Tabs.instances.has(container)) {
                    RSL.Tabs.create(container);
                }
            });
        },

        /**
         * Create and initialize a specific tabs-display container
         * @param {HTMLElement} container - The .tabs-display container element
         */
        create: function(container) {
            if (RSL.Tabs.instances.has(container)) {
                return; // Already initialized
            }

            const tabLayout = container.querySelector('.slot-layout.tabs');
            if (!tabLayout) return;

            RSL.Tabs._initializeTabGroup(tabLayout);

            // Setup FilterBus subscription if configured
            setupFilterBusSubscription(container);

            // Setup date filter subscription if configured
            setupDateFilterSubscription(container);

            // Add initialized class for CSS transitions (after brief delay to prevent flicker)
            setTimeout(function() {
                container.classList.add('tabs-display-initialized');
            }, 50);

            // Mark as initialized
            RSL.Tabs.instances.add(container);
        },

        /**
         * Destroy a tabs instance and clean up resources
         * @param {HTMLElement} container - The .tabs-display container element
         */
        destroy: function(container) {
            if (!container) return;

            // Unsubscribe from FilterBus (visibility filter)
            var subscriberId = filterSubscriptions.get(container);
            if (subscriberId && window.RSL && window.RSL.FilterBus && window.RSL.FilterBus.unsubscribe) {
                window.RSL.FilterBus.unsubscribe(subscriberId);
            }
            filterSubscriptions.delete(container);

            // Unsubscribe from date filter
            var dateSubscriberId = dateFilterSubscriptions.get(container);
            if (dateSubscriberId && window.RSL && window.RSL.FilterBus && window.RSL.FilterBus.unsubscribe) {
                window.RSL.FilterBus.unsubscribe(dateSubscriberId);
            }
            dateFilterSubscriptions.delete(container);

            // Remove from instances
            RSL.Tabs.instances.delete(container);

            // Remove initialized class
            container.classList.remove('tabs-display-initialized');
        },

        /**
         * Initialize a single tab group
         *
         * Sets up ARIA attributes, event listeners, and keyboard navigation for
         * one group of tabs. Each tab group operates independently.
         *
         * @private
         * @param {HTMLElement} tabLayout - The .slot-layout.tabs container
         */
        _initializeTabGroup: function(tabLayout) {
            const tabs = tabLayout.querySelectorAll('.tab-link');
            // Only select direct sibling tab-content elements, not nested ones
            // Find the tabs-content container that is a direct sibling of the tab links container
            const tabsDisplay = tabLayout.parentElement;
            const tabsContentContainer = tabsDisplay.querySelector(':scope > .tabs-content, :scope > .slot-layout.tabs-content');
            const contents = tabsContentContainer
                ? tabsContentContainer.querySelectorAll(':scope > .tab-content')
                : tabLayout.parentElement.querySelectorAll(':scope > .tab-content');

            if (!tabs.length || !contents.length) return;

            // Set up ARIA role on the tab list container
            tabLayout.setAttribute('role', 'tablist');
            tabLayout.setAttribute('aria-orientation', 'horizontal');

            /**
             * Set a tab as active and show its corresponding content
             *
             * Updates ARIA attributes, CSS classes, and manages focus state.
             * Deactivates all other tabs and content panels in the group.
             *
             * @param {HTMLElement} tab - The tab element to activate
             * @param {HTMLElement} content - The content panel to display
             */
            function setActive(tab, content) {
                tabs.forEach(function(tabEl) {
                    tabEl.setAttribute('aria-selected', 'false');
                    tabEl.setAttribute('tabindex', '-1');
                    tabEl.classList.remove('active');
                });

                contents.forEach(function(contentEl) {
                    contentEl.setAttribute('aria-hidden', 'true');
                    contentEl.classList.remove('active');
                    // Ensure hidden via CSS (clear any inline styles that might override)
                    contentEl.style.display = '';
                });

                tab.setAttribute('aria-selected', 'true');
                tab.setAttribute('tabindex', '0');
                tab.classList.add('active');
                content.setAttribute('aria-hidden', 'false');
                content.classList.add('active');
                // Ensure visible (clear any inline styles and let .active class take over)
                content.style.display = '';

                // Trigger layout recalculation for any grids inside the newly visible tab
                const gridLayouts = content.querySelectorAll('.slot-layout, .nested-slot-layout');
                gridLayouts.forEach(function(layout) {
                    // Trigger a resize event to recalculate the layout
                    window.dispatchEvent(new Event('resize'));
                });
            }

            // Initialize each tab with ARIA attributes and event listeners
            tabs.forEach(function(tab, i) {
                const correspondingContent = contents[i];

                // Generate unique IDs if not present
                var tabId = tab.id || 'rsl-tab-' + Math.random().toString(36).substr(2, 9);
                var panelId = correspondingContent.id || 'rsl-tabpanel-' + Math.random().toString(36).substr(2, 9);

                tab.id = tabId;
                correspondingContent.id = panelId;

                // Set initial ARIA attributes on tab
                tab.setAttribute('role', 'tab');
                tab.setAttribute('aria-selected', 'false');
                tab.setAttribute('aria-controls', panelId);
                tab.setAttribute('tabindex', '-1');

                // Set ARIA attributes on content panel
                correspondingContent.setAttribute('role', 'tabpanel');
                correspondingContent.setAttribute('aria-labelledby', tabId);
                correspondingContent.setAttribute('tabindex', '0'); // Make panel focusable

                // Mark first and last tabs for reference (optional, for styling hooks)
                if (i === 0) {
                    tab.setAttribute('data-first', 'true');
                } else if (i === tabs.length - 1) {
                    tab.setAttribute('data-last', 'true');
                }

                /**
                 * Activate tab on click
                 * Primary interaction method for mouse/touch users
                 */
                tab.addEventListener('click', function(event) {
                    event.preventDefault();
                    setActive(tab, correspondingContent);
                    tab.focus();
                });

                /**
                 * Handle keyboard navigation within tabs
                 *
                 * WCAG 2.1 compliant keyboard pattern:
                 * - Arrow Left/Up: Move to previous tab
                 * - Arrow Right/Down: Move to next tab
                 * - Home: Move to first tab
                 * - End: Move to last tab
                 * - Enter/Space: Activate the focused tab
                 * - Tab: Exit tab list (default behavior, moves to content)
                 */
                tab.addEventListener('keydown', function(event) {
                    var key = event.key;
                    var currentIndex = i;
                    var targetIndex = null;

                    switch (key) {
                        case 'ArrowLeft':
                        case 'ArrowUp':
                            // Move to previous tab (wrap to last if at first)
                            event.preventDefault();
                            targetIndex = currentIndex > 0 ? currentIndex - 1 : tabs.length - 1;
                            break;

                        case 'ArrowRight':
                        case 'ArrowDown':
                            // Move to next tab (wrap to first if at last)
                            event.preventDefault();
                            targetIndex = currentIndex < tabs.length - 1 ? currentIndex + 1 : 0;
                            break;

                        case 'Home':
                            // Move to first tab
                            event.preventDefault();
                            targetIndex = 0;
                            break;

                        case 'End':
                            // Move to last tab
                            event.preventDefault();
                            targetIndex = tabs.length - 1;
                            break;

                        case 'Enter':
                        case ' ':
                            // Activate the focused tab
                            event.preventDefault();
                            setActive(tab, correspondingContent);
                            return;

                        default:
                            // Let Tab key pass through for normal navigation
                            return;
                    }

                    // Move focus to target tab and activate it
                    if (targetIndex !== null && tabs[targetIndex]) {
                        tabs[targetIndex].focus();
                        setActive(tabs[targetIndex], contents[targetIndex]);
                    }
                });
            });

            // Activate first tab by default
            setActive(tabs[0], contents[0]);
        }
    };

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

})();
