/* ============================================
   RSL Gallery Component
   Version: 2.0.0
   Description: Masonry-style image gallery with
   filtering, lightbox, date range filtering,
   and full accessibility support
   ============================================ */

(function() {
    'use strict';

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

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

        // Already a Date object
        if (dateStr instanceof Date) return dateStr;

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

        // ISO format: YYYY-MM-DD
        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: try native parsing
        var fallback = new Date(str);
        return isNaN(fallback.getTime()) ? null : fallback;
    }

    /**
     * RSL Gallery Component
     * Provides filtering, lightbox viewing, and keyboard navigation
     */
    window.RSL.Gallery = {

        // Track initialized galleries
        instances: new Set(),

        // Track FilterBus subscriptions for cleanup
        filterSubscriptions: new Map(),

        // Track items with date filtering for efficient updates
        dateFilteredItems: new Map(),

        /**
         * Initialize all galleries on the page
         */
        init: function() {
            var galleries = document.querySelectorAll('.rsl-gallery');
            var self = this;

            galleries.forEach(function(gallery) {
                if (!self.instances.has(gallery)) {
                    self.create(gallery);
                    self.instances.add(gallery);
                }
            });
        },

        /**
         * Create a gallery instance
         * @param {HTMLElement} gallery - The gallery container element
         */
        create: function(gallery) {
            var self = this;
            var filterId = gallery.dataset.filter;
            var lightboxId = gallery.dataset.lightbox;

            // Initialize filter if specified
            if (filterId) {
                var filterContainer = document.getElementById(filterId);
                if (filterContainer) {
                    self.initFilter(gallery, filterContainer);
                }
            }

            // Initialize lightbox if specified
            if (lightboxId) {
                var lightbox = document.getElementById(lightboxId);
                if (lightbox) {
                    self.initLightbox(gallery, lightbox);
                }
            }

            // Set up FilterBus subscriptions for gallery items
            self.setupFilterBusSubscriptions(gallery);

            // Mark gallery as initialized (prevents CSS flash)
            gallery.classList.add('rsl-gallery-initialized');
        },

        /**
         * Set up FilterBus subscriptions for gallery items
         * @param {HTMLElement} gallery - The gallery container
         */
        setupFilterBusSubscriptions: function(gallery) {
            var self = this;
            var galleryItems = gallery.querySelectorAll('.rsl-gallery-item[data-filter-subscribe]');

            if (!window.RSL || !window.RSL.FilterBus) {
                return;
            }

            // Set up visibility filtering subscriptions (per-item)
            galleryItems.forEach(function(item, index) {
                var filterKey = item.dataset.filterSubscribe;
                var filterValue = item.dataset.filterValue;

                if (!filterKey) return;

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

                // Subscribe to FilterBus
                window.RSL.FilterBus.subscribe(
                    subscriberId,
                    function(state, meta) {
                        self.handleFilterBusChange(item, filterKey, filterValue, state);
                    },
                    { keys: [filterKey] }
                );

                // Store subscription for cleanup
                if (!self.filterSubscriptions.has(gallery)) {
                    self.filterSubscriptions.set(gallery, []);
                }
                self.filterSubscriptions.get(gallery).push(subscriberId);

                // Check initial state
                var initialState = window.RSL.FilterBus.getState();
                if (initialState && initialState[filterKey] !== undefined) {
                    self.handleFilterBusChange(item, filterKey, filterValue, initialState);
                }
            });

            // Set up date filtering subscription (gallery-level, subscribes to all keys)
            // Check if gallery container has date field attribute
            // data-filterbus-date-field becomes dataset.filterbusDateField in JS
            var dateFieldAttr = gallery.dataset.filterbusDateField;
            if (dateFieldAttr) {
                // Find all gallery items (they don't need individual date-field attributes)
                var allItems = gallery.querySelectorAll('.rsl-gallery-item');

                // Store date-filtered items for this gallery
                self.dateFilteredItems.set(gallery, Array.from(allItems));

                // Generate unique subscriber ID for date filtering
                var dateSubscriberId = 'gallery-date-' + (gallery.id || Math.random().toString(36).substr(2, 9));

                // Subscribe to ALL keys to catch date objects
                window.RSL.FilterBus.subscribe(
                    dateSubscriberId,
                    function(state, meta) {
                        self.handleDateFilterChange(gallery, state, meta);
                    }
                    // No keys filter - subscribe to all
                );

                // Store subscription for cleanup
                if (!self.filterSubscriptions.has(gallery)) {
                    self.filterSubscriptions.set(gallery, []);
                }
                self.filterSubscriptions.get(gallery).push(dateSubscriberId);
            }
        },

        /**
         * Handle FilterBus state changes for a gallery item
         * @param {HTMLElement} item - The gallery item
         * @param {string} filterKey - The filter key being watched
         * @param {string} filterValue - The value this item matches
         * @param {Object} state - The current filter state object
         */
        handleFilterBusChange: function(item, filterKey, filterValue, state) {
            if (!filterValue) {
                item.classList.remove('rsl-filterbus-hidden');
                return;
            }

            // Get the value for our specific key from the state object
            var currentValue = state[filterKey];
            if (currentValue === undefined || currentValue === null) {
                // No filter set, show all
                item.classList.remove('rsl-filterbus-hidden');
                return;
            }

            var stateStr = String(currentValue).toLowerCase();
            var values = filterValue.toLowerCase().split(',').map(function(v) {
                return v.trim();
            });

            // Show if state is "all" or matches any of the item's values
            var shouldShow = stateStr === 'all' || values.indexOf(stateStr) !== -1;

            if (shouldShow) {
                item.classList.remove('rsl-filterbus-hidden');
            } else {
                item.classList.add('rsl-filterbus-hidden');
            }
        },

        /**
         * Handle date filter changes for gallery items
         * @param {HTMLElement} gallery - The gallery container
         * @param {Object} state - The current filter state object
         * @param {Object} meta - Change metadata
         */
        handleDateFilterChange: function(gallery, state, meta) {
            var self = this;
            var items = self.dateFilteredItems.get(gallery);
            if (!items || items.length === 0) return;

            // Get the date field from the gallery container
            // data-filterbus-date-field becomes dataset.filterbusDateField in JS
            var dateField = gallery.dataset.filterbusDateField || 'date';

            // Find date filter in state - look for objects with mode: 'range' or 'single'
            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;
                }
            });

            // Apply date filter to each item
            items.forEach(function(item) {
                // Get date from the field specified on the gallery container
                var itemDateStr = item.dataset[dateField];

                if (!itemDateStr) {
                    // No date on item, don't hide it based on date filter
                    item.classList.remove('rsl-date-hidden');
                    return;
                }

                var itemDate = parseDate(itemDateStr);
                if (!itemDate) {
                    // Invalid date, don't hide
                    item.classList.remove('rsl-date-hidden');
                    return;
                }

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

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

                if (!filterStart || !filterEnd) {
                    item.classList.remove('rsl-date-hidden');
                    return;
                }

                // Make end date inclusive (end of day)
                filterEnd.setHours(23, 59, 59, 999);

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

                if (shouldShow) {
                    item.classList.remove('rsl-date-hidden');
                } else {
                    item.classList.add('rsl-date-hidden');
                }
            });

            // Dispatch event
            gallery.dispatchEvent(new CustomEvent('rsl-gallery:date-filter', {
                bubbles: true,
                detail: {
                    dateFilter: dateFilter,
                    totalItems: items.length,
                    visibleItems: items.filter(function(item) {
                        return !item.classList.contains('rsl-date-hidden');
                    }).length
                }
            }));
        },

        /**
         * Initialize gallery filter functionality
         * @param {HTMLElement} gallery - The gallery container
         * @param {HTMLElement} filterContainer - The filter buttons container
         */
        initFilter: function(gallery, filterContainer) {
            var filterButtons = filterContainer.querySelectorAll('.rsl-gallery-filter-btn');
            var galleryItems = gallery.querySelectorAll('.rsl-gallery-item');
            var statusRegion = gallery.parentElement.querySelector('.rsl-gallery-status');

            if (filterButtons.length === 0 || galleryItems.length === 0) return;

            function activateFilter(button) {
                var filter = button.dataset.filter;

                // Update active button and tabindex
                filterButtons.forEach(function(btn) {
                    btn.classList.remove('active');
                    btn.setAttribute('aria-selected', 'false');
                    btn.setAttribute('tabindex', '-1');
                });
                button.classList.add('active');
                button.setAttribute('aria-selected', 'true');
                button.setAttribute('tabindex', '0');

                // Filter items with animation
                var visibleCount = 0;
                galleryItems.forEach(function(item) {
                    var category = item.dataset.category;
                    var shouldShow = filter === 'all' || category === filter;

                    if (shouldShow) {
                        visibleCount++;
                        item.style.display = '';
                        item.classList.remove('rsl-filtering-out');
                        item.classList.add('rsl-filtering-in');
                    } else {
                        item.classList.remove('rsl-filtering-in');
                        item.classList.add('rsl-filtering-out');
                        setTimeout(function() {
                            if (item.classList.contains('rsl-filtering-out')) {
                                item.style.display = 'none';
                            }
                        }, 300);
                    }
                });

                // Announce to screen readers
                if (statusRegion) {
                    var categoryName = filter === 'all' ? 'all categories' : filter;
                    statusRegion.textContent = 'Showing ' + visibleCount + ' photos in ' + categoryName;
                }
            }

            // Click handlers
            filterButtons.forEach(function(button) {
                button.addEventListener('click', function() {
                    activateFilter(this);
                });
            });

            // Keyboard navigation (arrow keys for tab-like behavior)
            filterButtons.forEach(function(button, index) {
                button.addEventListener('keydown', function(e) {
                    var targetIndex = index;

                    switch (e.key) {
                        case 'ArrowRight':
                        case 'ArrowDown':
                            e.preventDefault();
                            targetIndex = (index + 1) % filterButtons.length;
                            break;
                        case 'ArrowLeft':
                        case 'ArrowUp':
                            e.preventDefault();
                            targetIndex = (index - 1 + filterButtons.length) % filterButtons.length;
                            break;
                        case 'Home':
                            e.preventDefault();
                            targetIndex = 0;
                            break;
                        case 'End':
                            e.preventDefault();
                            targetIndex = filterButtons.length - 1;
                            break;
                        default:
                            return;
                    }

                    filterButtons[targetIndex].focus();
                    activateFilter(filterButtons[targetIndex]);
                });
            });

            // Set initial tabindex
            filterButtons.forEach(function(btn, i) {
                btn.setAttribute('tabindex', i === 0 ? '0' : '-1');
            });
        },

        /**
         * Initialize lightbox functionality
         * @param {HTMLElement} gallery - The gallery container
         * @param {HTMLElement} lightbox - The lightbox element
         */
        initLightbox: function(gallery, lightbox) {
            var galleryLinks = gallery.querySelectorAll('.rsl-gallery-link');

            if (galleryLinks.length === 0) return;

            var lightboxImage = lightbox.querySelector('.rsl-lightbox-image');
            var lightboxTitle = lightbox.querySelector('.rsl-lightbox-title');
            var lightboxMeta = lightbox.querySelector('.rsl-lightbox-meta');
            var closeBtn = lightbox.querySelector('.rsl-lightbox-close');
            var prevBtn = lightbox.querySelector('.rsl-lightbox-prev');
            var nextBtn = lightbox.querySelector('.rsl-lightbox-next');
            var currentCounter = lightbox.querySelector('.rsl-lightbox-current');
            var totalCounter = lightbox.querySelector('.rsl-lightbox-total');

            var currentIndex = 0;
            var visibleItems = [];
            var lastFocusedElement = null;

            function updateVisibleItems() {
                visibleItems = Array.from(galleryLinks).filter(function(link) {
                    return link.closest('.rsl-gallery-item').style.display !== 'none';
                });
                if (totalCounter) {
                    totalCounter.textContent = visibleItems.length;
                }
            }

            function openLightbox(index) {
                updateVisibleItems();
                if (index < 0 || index >= visibleItems.length) return;

                lastFocusedElement = document.activeElement;
                currentIndex = index;

                var link = visibleItems[index];
                var item = link.closest('.rsl-gallery-item');
                var title = item.querySelector('.rsl-gallery-title');
                var meta = item.querySelector('.rsl-gallery-meta');
                var img = item.querySelector('img');

                lightboxImage.src = link.href;
                lightboxImage.alt = img ? img.alt : '';

                if (lightboxTitle) {
                    lightboxTitle.textContent = title ? title.textContent : '';
                }
                if (lightboxMeta) {
                    lightboxMeta.textContent = meta ? meta.textContent : '';
                }
                if (currentCounter) {
                    currentCounter.textContent = index + 1;
                }

                lightbox.hidden = false;
                lightbox.setAttribute('aria-hidden', 'false');
                document.body.style.overflow = 'hidden';

                if (closeBtn) {
                    closeBtn.focus();
                }

                // Trap focus in lightbox
                lightbox.addEventListener('keydown', trapFocus);
            }

            function closeLightbox() {
                lightbox.hidden = true;
                lightbox.setAttribute('aria-hidden', 'true');
                document.body.style.overflow = '';
                lightbox.removeEventListener('keydown', trapFocus);

                if (lastFocusedElement) {
                    lastFocusedElement.focus();
                }
            }

            function showPrev() {
                updateVisibleItems();
                currentIndex = (currentIndex - 1 + visibleItems.length) % visibleItems.length;
                openLightbox(currentIndex);
            }

            function showNext() {
                updateVisibleItems();
                currentIndex = (currentIndex + 1) % visibleItems.length;
                openLightbox(currentIndex);
            }

            function trapFocus(e) {
                var focusableElements = lightbox.querySelectorAll(
                    'button, [href], [tabindex]:not([tabindex="-1"])'
                );
                var firstElement = focusableElements[0];
                var lastElement = focusableElements[focusableElements.length - 1];

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

            // Event listeners for gallery links
            galleryLinks.forEach(function(link) {
                link.addEventListener('click', function(e) {
                    e.preventDefault();
                    updateVisibleItems();
                    var visibleIndex = visibleItems.indexOf(link);
                    openLightbox(visibleIndex >= 0 ? visibleIndex : 0);
                });
            });

            // Lightbox controls
            if (closeBtn) {
                closeBtn.addEventListener('click', closeLightbox);
            }
            if (prevBtn) {
                prevBtn.addEventListener('click', showPrev);
            }
            if (nextBtn) {
                nextBtn.addEventListener('click', showNext);
            }

            // Keyboard navigation
            document.addEventListener('keydown', function(e) {
                if (lightbox.hidden) return;

                switch (e.key) {
                    case 'Escape':
                        closeLightbox();
                        break;
                    case 'ArrowLeft':
                        showPrev();
                        break;
                    case 'ArrowRight':
                        showNext();
                        break;
                }
            });

            // Close on background click
            lightbox.addEventListener('click', function(e) {
                if (e.target === lightbox) {
                    closeLightbox();
                }
            });
        },

        /**
         * Destroy a gallery instance
         * @param {HTMLElement} gallery - The gallery to destroy
         */
        destroy: function(gallery) {
            // Unsubscribe from FilterBus
            if (this.filterSubscriptions.has(gallery) && window.RSL && window.RSL.FilterBus) {
                var subscriptions = this.filterSubscriptions.get(gallery);
                subscriptions.forEach(function(subscriberId) {
                    window.RSL.FilterBus.unsubscribe(subscriberId);
                });
                this.filterSubscriptions.delete(gallery);
            }

            this.instances.delete(gallery);
        }
    };

    // Auto-initialize on DOM ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', function() {
            window.RSL.Gallery.init();
        });
    } else {
        window.RSL.Gallery.init();
    }

})();
