/* ============================================
   RSL Stats Component
   Version: 1.0.0
   Description: Lightweight, accessible statistics
   display for landing pages, dashboards, and
   marketing sections. Features count-up animation,
   multiple variants, and FilterBus integration.

   Accessibility: WCAG 2.1 AA compliant
   - Proper ARIA roles and labels
   - Reduced motion support
   - Screen reader optimized
   - Keyboard navigable

   JSON API V2 Ready: type: "stat" / "stats"
   ============================================ */

(function() {
    'use strict';

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

    /**
     * Track initialized stat instances
     * @type {Set<HTMLElement>}
     */
    var instances = new Set();

    /**
     * Track group instances
     * @type {Set<HTMLElement>}
     */
    var groupInstances = new Set();

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

    /**
     * IntersectionObserver for scroll-triggered animations
     * @type {IntersectionObserver|null}
     */
    var animationObserver = null;

    /**
     * Default configuration
     */
    var DEFAULTS = {
        animationDuration: 1500,
        animationDelay: 0,
        decimalPlaces: 0,
        threshold: 0.3,
        easing: 'easeOutQuart'
    };

    /**
     * Data attribute to config property mapping
     */
    var ATTR_MAP = {
        'data-value': 'value',
        'data-label': 'label',
        'data-description': 'description',
        'data-prefix': 'prefix',
        'data-suffix': 'suffix',
        'data-icon': 'icon',
        'data-color-scheme': 'colorScheme',
        'data-size': 'size',
        'data-variant': 'variant',
        'data-align': 'align',
        'data-animate': 'animate',
        'data-animate-duration': 'animationDuration',
        'data-animate-delay': 'animationDelay',
        'data-decimal-places': 'decimalPlaces',
        'data-gradient': 'gradient',
        'data-clickable': 'clickable',
        'data-href': 'href',
        'data-target': 'target',
        // FilterBus integration
        'data-filter-subscribe': 'filterSubscribe',
        'data-filter-value': 'filterValue'
    };

    /**
     * Easing functions for count-up animation
     */
    var easingFunctions = {
        linear: function(t) { return t; },
        easeOutQuad: function(t) { return t * (2 - t); },
        easeOutCubic: function(t) { return (--t) * t * t + 1; },
        easeOutQuart: function(t) { return 1 - (--t) * t * t * t; },
        easeOutQuint: function(t) { return 1 + (--t) * t * t * t * t; },
        easeInOutQuad: function(t) { return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; }
    };

    /**
     * Check if reduced motion is preferred
     * @returns {boolean}
     */
    function prefersReducedMotion() {
        return window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    }

    /**
     * Parse a data attribute value
     * @param {string} value - Raw attribute value
     * @param {*} defaultValue - Default value if parsing fails
     * @returns {*} Parsed value
     */
    function parseDataValue(value, defaultValue) {
        if (value === null || value === undefined) return defaultValue;
        if (value === '' || value === 'true') return true;
        if (value === 'false') return false;

        var num = parseFloat(value);
        return isNaN(num) ? value : num;
    }

    /**
     * Get configuration from element data attributes
     * @param {HTMLElement} element - Stat element
     * @returns {Object} Configuration object
     */
    function getConfig(element) {
        var config = Object.assign({}, DEFAULTS);

        Object.keys(ATTR_MAP).forEach(function(attr) {
            var value = element.getAttribute(attr);
            if (value !== null) {
                config[ATTR_MAP[attr]] = parseDataValue(value, config[ATTR_MAP[attr]]);
            }
        });

        // Handle boolean attributes (presence = true)
        ['data-animate', 'data-gradient', 'data-clickable'].forEach(function(attr) {
            if (element.hasAttribute(attr) && element.getAttribute(attr) === '') {
                var key = ATTR_MAP[attr];
                config[key] = true;
            }
        });

        return config;
    }

    /**
     * Format a number with locale formatting and abbreviation
     * @param {number} value - Number to format
     * @param {number} decimalPlaces - Decimal places
     * @param {boolean} abbreviate - Whether to abbreviate large numbers
     * @returns {string} Formatted number
     */
    function formatNumber(value, decimalPlaces, abbreviate) {
        if (typeof value !== 'number' || isNaN(value)) return String(value);

        // Abbreviate large numbers if requested
        if (abbreviate !== false) {
            if (Math.abs(value) >= 1000000000) {
                return (value / 1000000000).toFixed(1).replace(/\.0$/, '') + 'B';
            } else if (Math.abs(value) >= 1000000) {
                return (value / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
            } else if (Math.abs(value) >= 10000) {
                return (value / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
            }
        }

        return value.toLocaleString(undefined, {
            minimumFractionDigits: decimalPlaces,
            maximumFractionDigits: decimalPlaces
        });
    }

    /**
     * Parse a value string to extract numeric value
     * @param {string} valueStr - Value string (e.g., "$124,500", "12.5%")
     * @returns {Object} Parsed value with prefix, number, and suffix
     */
    function parseValueString(valueStr) {
        if (typeof valueStr === 'number') {
            return { prefix: '', number: valueStr, suffix: '', raw: valueStr };
        }

        if (typeof valueStr !== 'string') {
            return { prefix: '', number: 0, suffix: '', raw: valueStr };
        }

        var match = valueStr.match(/^([^0-9-]*)(-?[\d,]+\.?\d*)(.*)$/);
        if (match) {
            var numStr = match[2].replace(/,/g, '');
            return {
                prefix: match[1] || '',
                number: parseFloat(numStr) || 0,
                suffix: match[3] || '',
                raw: valueStr
            };
        }

        return { prefix: '', number: 0, suffix: '', raw: valueStr };
    }

    /**
     * Animate count-up effect
     * @param {HTMLElement} valueEl - Value element to animate
     * @param {number} startValue - Starting value
     * @param {number} endValue - Ending value
     * @param {Object} options - Animation options
     */
    function animateCountUp(valueEl, startValue, endValue, options) {
        var duration = options.duration || DEFAULTS.animationDuration;
        var prefix = options.prefix || '';
        var suffix = options.suffix || '';
        var decimalPlaces = options.decimalPlaces || 0;
        var easingName = options.easing || 'easeOutQuart';
        var easing = easingFunctions[easingName] || easingFunctions.easeOutQuart;

        var startTime = null;
        var currentValue = startValue;

        function animate(timestamp) {
            if (!startTime) startTime = timestamp;
            var progress = Math.min((timestamp - startTime) / duration, 1);
            var easedProgress = easing(progress);

            currentValue = startValue + (endValue - startValue) * easedProgress;

            var displayValue = formatNumber(currentValue, decimalPlaces, false);
            valueEl.textContent = prefix + displayValue + suffix;

            if (progress < 1) {
                requestAnimationFrame(animate);
            } else {
                // Final value
                valueEl.textContent = prefix + formatNumber(endValue, decimalPlaces, false) + suffix;

                // Dispatch completion event
                var stat = valueEl.closest('.rsl-stat');
                if (stat) {
                    stat.dispatchEvent(new CustomEvent('rsl-stat:animated', {
                        bubbles: true,
                        detail: { value: endValue }
                    }));
                }
            }
        }

        requestAnimationFrame(animate);
    }

    /**
     * Generate ARIA label for screen readers
     * @param {Object} config - Stat configuration
     * @returns {string} Accessible label
     */
    function generateAriaLabel(config) {
        var parts = [];

        // Build the full value string
        var valueStr = '';
        if (config.prefix) valueStr += config.prefix;
        valueStr += String(config.value);
        if (config.suffix) valueStr += config.suffix;

        parts.push(valueStr);

        if (config.label) {
            parts.push(config.label);
        }

        if (config.description) {
            parts.push(config.description);
        }

        return parts.join(' ');
    }

    /**
     * Build stat HTML structure from data attributes
     * @param {HTMLElement} element - Stat container element
     * @param {Object} config - Configuration object
     */
    function buildStatStructure(element, config) {
        // Clear existing content if rebuilding
        element.innerHTML = '';

        // Ensure the stat has the required class
        if (!element.classList.contains('rsl-stat')) {
            element.classList.add('rsl-stat');
        }

        // Apply data attributes for CSS
        if (config.colorScheme) {
            element.setAttribute('data-color-scheme', config.colorScheme);
        }
        if (config.size) {
            element.setAttribute('data-size', config.size);
        }
        if (config.variant) {
            element.setAttribute('data-variant', config.variant);
        }
        if (config.align) {
            element.setAttribute('data-align', config.align);
        }
        if (config.gradient) {
            element.setAttribute('data-gradient', '');
        }

        // Set ARIA attributes
        element.setAttribute('role', 'figure');
        element.setAttribute('aria-label', generateAriaLabel(config));

        // Make clickable stats keyboard accessible
        if (config.clickable || config.href) {
            element.setAttribute('tabindex', '0');
            element.setAttribute('data-clickable', '');
        }

        // Build icon if provided
        if (config.icon) {
            var iconWrapper = document.createElement('div');
            iconWrapper.className = 'rsl-stat-icon';

            var icon = document.createElement('i');
            // Support both "fa-icon" and "fas fa-icon" formats
            if (config.icon.indexOf(' ') === -1 && config.icon.indexOf('fa-') === 0) {
                icon.className = 'fas ' + config.icon;
            } else {
                icon.className = config.icon;
            }
            icon.setAttribute('aria-hidden', 'true');
            iconWrapper.appendChild(icon);
            element.appendChild(iconWrapper);
        }

        // Build value
        if (config.value !== undefined) {
            var parsed = parseValueString(String(config.value));
            var prefix = config.prefix !== undefined ? config.prefix : parsed.prefix;
            var suffix = config.suffix !== undefined ? config.suffix : parsed.suffix;

            var valueContainer = document.createElement('div');
            valueContainer.className = 'rsl-stat-value';

            // Add prefix
            if (prefix) {
                var prefixEl = document.createElement('span');
                prefixEl.className = 'rsl-stat-prefix';
                prefixEl.textContent = prefix;
                valueContainer.appendChild(prefixEl);
            }

            // Add number
            var numberEl = document.createElement('span');
            numberEl.className = 'rsl-stat-number';

            if (config.animate && !prefersReducedMotion()) {
                // Start at 0 for animation
                numberEl.textContent = '0';
                element.setAttribute('data-animate', '');
            } else {
                // Show final value immediately
                numberEl.textContent = formatNumber(parsed.number, config.decimalPlaces || 0, false);
            }
            valueContainer.appendChild(numberEl);

            // Add suffix
            if (suffix) {
                var suffixEl = document.createElement('span');
                suffixEl.className = 'rsl-stat-suffix';
                suffixEl.textContent = suffix;
                valueContainer.appendChild(suffixEl);
            }

            element.appendChild(valueContainer);

            // Store animation data
            if (config.animate && !prefersReducedMotion()) {
                element._animationData = {
                    numberEl: numberEl,
                    endValue: parsed.number,
                    prefix: prefix,
                    suffix: suffix,
                    duration: config.animationDuration || DEFAULTS.animationDuration,
                    decimalPlaces: config.decimalPlaces || 0
                };
            }
        }

        // Build label
        if (config.label) {
            var label = document.createElement('div');
            label.className = 'rsl-stat-label';
            label.textContent = config.label;
            element.appendChild(label);
        }

        // Build description
        if (config.description) {
            var description = document.createElement('div');
            description.className = 'rsl-stat-description';
            description.textContent = config.description;
            element.appendChild(description);
        }

        // Handle click events
        if (config.clickable || config.href) {
            var handleClick = function() {
                if (config.href) {
                    if (config.target === '_blank') {
                        window.open(config.href, '_blank', 'noopener,noreferrer');
                    } else {
                        window.location.href = config.href;
                    }
                }
                element.dispatchEvent(new CustomEvent('rsl-stat:click', {
                    bubbles: true,
                    detail: { config: config }
                }));
            };

            element.addEventListener('click', handleClick);
            element.addEventListener('keydown', function(e) {
                if (e.key === 'Enter' || e.key === ' ') {
                    e.preventDefault();
                    handleClick();
                }
            });
        }
    }

    /**
     * Trigger animation for a stat
     * @param {HTMLElement} element - Stat element
     */
    function triggerAnimation(element) {
        if (!element._animationData) return;
        if (element.classList.contains('rsl-stat-animated')) return;

        var data = element._animationData;

        // Add animated class for CSS
        element.classList.add('rsl-stat-animated');

        // Animate the number
        animateCountUp(data.numberEl, 0, data.endValue, {
            duration: data.duration,
            prefix: '',  // Prefix/suffix are separate elements
            suffix: '',
            decimalPlaces: data.decimalPlaces
        });
    }

    /**
     * Initialize IntersectionObserver for scroll-triggered animations
     */
    function initAnimationObserver() {
        if (animationObserver) return;
        if (!('IntersectionObserver' in window)) {
            // Fallback: animate all immediately
            document.querySelectorAll('.rsl-stat[data-animate]').forEach(triggerAnimation);
            return;
        }

        animationObserver = new IntersectionObserver(function(entries) {
            entries.forEach(function(entry) {
                if (entry.isIntersecting) {
                    var delay = parseInt(entry.target.getAttribute('data-animate-delay')) || 0;
                    setTimeout(function() {
                        triggerAnimation(entry.target);
                    }, delay);
                    animationObserver.unobserve(entry.target);
                }
            });
        }, {
            threshold: DEFAULTS.threshold,
            rootMargin: '0px'
        });
    }

    /**
     * Setup FilterBus subscription for a stat
     * @param {HTMLElement} element - Stat element
     * @param {Object} config - Configuration object
     */
    function setupFilterBusSubscription(element, config) {
        if (!window.RSL || !window.RSL.FilterBus) return;
        if (!config.filterSubscribe) return;

        var subscriberId = 'stat-' + (element.id || Math.random().toString(36).substr(2, 9));

        window.RSL.FilterBus.subscribe(
            subscriberId,
            function(state, meta) {
                handleFilterBusChange(element, config, state, meta);
            },
            { keys: config.filterSubscribe.split(',').map(function(k) { return k.trim(); }) }
        );

        filterSubscriptions.set(element, subscriberId);
    }

    /**
     * Handle FilterBus state changes
     * @param {HTMLElement} element - Stat element
     * @param {Object} config - Configuration object
     * @param {Object} state - Current filter state
     * @param {Object} meta - Change metadata
     */
    function handleFilterBusChange(element, config, state, meta) {
        var filterKey = config.filterSubscribe;
        var filterValue = state[filterKey];
        var statValue = config.filterValue;

        var shouldShow = true;

        if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
            var filterLower = String(filterValue).toLowerCase();
            if (filterLower === 'all') {
                shouldShow = true;
            } else if (statValue !== undefined && statValue !== null) {
                var statValues = String(statValue).split(',').map(function(v) { return v.trim().toLowerCase(); });
                shouldShow = statValues.includes(filterLower);
            }
        }

        if (shouldShow) {
            element.classList.remove('rsl-stat-hidden');
            element.removeAttribute('aria-hidden');
        } else {
            element.classList.add('rsl-stat-hidden');
            element.setAttribute('aria-hidden', 'true');
        }

        element.dispatchEvent(new CustomEvent('rsl-stat:filterbus-update', {
            bubbles: true,
            detail: { state: state, visible: shouldShow }
        }));
    }

    /**
     * Create/initialize a single stat
     * @param {HTMLElement} element - Stat element
     * @returns {Object} Instance object
     */
    function create(element) {
        if (!element) return null;

        // Prevent double-initialization
        if (instances.has(element)) {
            return { element: element, config: getConfig(element) };
        }

        var config = getConfig(element);

        // Build structure if element is empty or has data-rsl-stat
        if (element.innerHTML.trim() === '' || element.hasAttribute('data-rsl-stat')) {
            buildStatStructure(element, config);
        }

        // Setup animation observer
        if (config.animate && !prefersReducedMotion()) {
            initAnimationObserver();
            if (animationObserver) {
                animationObserver.observe(element);
            }
        }

        // Setup FilterBus subscription
        setupFilterBusSubscription(element, config);

        // Add to instances
        instances.add(element);

        return { element: element, config: config };
    }

    /**
     * Initialize a stats group
     * @param {HTMLElement} group - Stats group element
     */
    function createGroup(group) {
        if (!group) return;
        if (groupInstances.has(group)) return;

        // Ensure class
        if (!group.classList.contains('rsl-stats')) {
            group.classList.add('rsl-stats');
        }

        // Set ARIA attributes
        var groupLabel = group.getAttribute('data-label') || group.getAttribute('aria-label') || 'Statistics';
        group.setAttribute('role', 'group');
        group.setAttribute('aria-label', groupLabel);

        // Initialize child stats
        var stats = group.querySelectorAll('.rsl-stat, [data-rsl-stat]');
        stats.forEach(function(stat) {
            create(stat);
        });

        groupInstances.add(group);
    }

    /**
     * Initialize all stats on the page
     */
    function init() {
        // Initialize groups first
        var groups = document.querySelectorAll('.rsl-stats, [data-rsl-stats]');
        groups.forEach(createGroup);

        // Initialize standalone stats
        var stats = document.querySelectorAll('.rsl-stat[data-value], [data-rsl-stat]');
        stats.forEach(function(stat) {
            // Skip if already in a group
            if (!stat.closest('.rsl-stats')) {
                create(stat);
            }
        });
    }

    /**
     * Update a stat with new value
     * @param {HTMLElement} element - Stat element
     * @param {number|string} newValue - New value
     * @param {Object} options - Update options
     */
    function update(element, newValue, options) {
        if (!element) return;

        options = options || {};
        var config = getConfig(element);

        // Parse new value
        var parsed = parseValueString(String(newValue));

        // Update data attribute
        element.setAttribute('data-value', newValue);

        // Find value element
        var numberEl = element.querySelector('.rsl-stat-number');
        if (!numberEl) return;

        // Animate if requested and not reduced motion
        if (options.animate && !prefersReducedMotion()) {
            var currentValue = parseFloat(numberEl.textContent.replace(/[^0-9.-]/g, '')) || 0;
            animateCountUp(numberEl, currentValue, parsed.number, {
                duration: options.duration || config.animationDuration || DEFAULTS.animationDuration,
                decimalPlaces: config.decimalPlaces || 0
            });
        } else {
            numberEl.textContent = formatNumber(parsed.number, config.decimalPlaces || 0, false);
        }

        // Update ARIA label
        config.value = newValue;
        element.setAttribute('aria-label', generateAriaLabel(config));

        // Announce change for screen readers
        if (options.announce) {
            announceChange(element, generateAriaLabel(config));
        }

        element.dispatchEvent(new CustomEvent('rsl-stat:updated', {
            bubbles: true,
            detail: { value: newValue, config: config }
        }));
    }

    /**
     * Announce a change for screen readers
     * @param {HTMLElement} element - Stat element
     * @param {string} message - Message to announce
     */
    function announceChange(element, message) {
        var liveRegion = document.getElementById('rsl-stat-announcer');
        if (!liveRegion) {
            liveRegion = document.createElement('div');
            liveRegion.id = 'rsl-stat-announcer';
            liveRegion.setAttribute('role', 'status');
            liveRegion.setAttribute('aria-live', 'polite');
            liveRegion.setAttribute('aria-atomic', 'true');
            liveRegion.style.cssText = 'position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;';
            document.body.appendChild(liveRegion);
        }

        liveRegion.textContent = message;
    }

    /**
     * Destroy a stat instance
     * @param {HTMLElement} element - Stat element
     */
    function destroy(element) {
        if (!element) return;

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

        // Unobserve from animation observer
        if (animationObserver) {
            animationObserver.unobserve(element);
        }

        // Clean up
        instances.delete(element);
        element.innerHTML = '';
        element.removeAttribute('role');
        element.removeAttribute('aria-label');
        element.removeAttribute('tabindex');
    }

    /**
     * Refresh all stats (re-trigger animations)
     */
    function refresh() {
        instances.forEach(function(element) {
            element.classList.remove('rsl-stat-animated');
            if (element._animationData && animationObserver) {
                animationObserver.observe(element);
            }
        });
    }

    /**
     * Public API
     * @namespace RSL.Stats
     */
    window.RSL.Stats = {
        /**
         * Track initialized instances
         */
        instances: instances,

        /**
         * Default configuration
         */
        defaults: DEFAULTS,

        /**
         * Initialize all stats on the page
         * @returns {void}
         */
        init: init,

        /**
         * Create/initialize a single stat
         * @param {HTMLElement} element - Stat element
         * @returns {Object} Instance object
         */
        create: create,

        /**
         * Create/initialize a stats group
         * @param {HTMLElement} group - Stats group element
         */
        createGroup: createGroup,

        /**
         * Update a stat with new value
         * @param {HTMLElement} element - Stat element
         * @param {number|string} newValue - New value
         * @param {Object} options - Update options
         */
        update: update,

        /**
         * Destroy a stat instance
         * @param {HTMLElement} element - Stat element
         */
        destroy: destroy,

        /**
         * Refresh all stats (re-trigger animations)
         */
        refresh: refresh,

        /**
         * Format a number
         * @param {number} value - Number to format
         * @param {Object} options - Formatting options
         * @returns {string} Formatted number
         */
        formatNumber: formatNumber,

        /**
         * Get configuration from element
         * @param {HTMLElement} element - Stat element
         * @returns {Object} Configuration object
         */
        getConfig: getConfig
    };

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

})();
