/* ============================================
   RSL Tooltip Component
   Version: 1.0.0
   Description: Accessible tooltip with smart positioning and keyboard support
   ============================================ */

(function() {
    'use strict';

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

    /**
     * Tooltip Component
     * Provides accessible tooltips with smart positioning, keyboard support,
     * and automatic show/hide based on hover, focus, and touch interactions.
     */
    window.RSL.Tooltip = {

        // Configuration defaults
        defaults: {
            position: 'top',        // top, bottom, left, right
            variant: 'default',     // default, light, primary, success, warning, danger
            size: 'md',            // sm, md, lg
            showDelay: 300,        // ms to wait before showing
            hideDelay: 200,        // ms to wait before hiding
            offset: 8,             // distance from trigger element
            autoPosition: true     // auto-flip if near viewport edge
        },

        // Store active tooltips
        activeTooltips: new Map(),

        // Store show/hide timers
        timers: new Map(),

        /**
         * Initialize all tooltips on the page
         * Finds all elements with [data-tooltip] and sets up event listeners
         */
        init: function() {
            var self = this;
            var tooltipTriggers = document.querySelectorAll('[data-tooltip]');

            tooltipTriggers.forEach(function(trigger) {
                self.attach(trigger);
            });
        },

        /**
         * Attach tooltip to a specific element
         * @param {HTMLElement|string} element - Element or selector
         * @param {Object} options - Custom options to override defaults
         */
        attach: function(element, options) {
            var self = this;
            var trigger = typeof element === 'string' ? document.querySelector(element) : element;

            if (!trigger) return;

            // Get tooltip content from data attribute
            var content = trigger.getAttribute('data-tooltip');
            if (!content) return;

            // Merge options
            var config = Object.assign({}, self.defaults, options || {}, {
                position: trigger.getAttribute('data-tooltip-position') || self.defaults.position,
                variant: trigger.getAttribute('data-tooltip-variant') || self.defaults.variant,
                size: trigger.getAttribute('data-tooltip-size') || self.defaults.size
            });

            // Store config on element
            trigger._tooltipConfig = config;
            trigger._tooltipContent = content;

            // Accessibility: add role and tabindex if not already focusable
            if (!trigger.hasAttribute('tabindex') && !self._isFocusable(trigger)) {
                trigger.setAttribute('tabindex', '0');
            }

            // Event listeners for show
            trigger.addEventListener('mouseenter', function(e) {
                self._scheduleShow(trigger, config.showDelay);
            });

            trigger.addEventListener('focus', function(e) {
                self._scheduleShow(trigger, 0); // Show immediately on focus
            });

            // Event listeners for hide
            trigger.addEventListener('mouseleave', function(e) {
                self._scheduleHide(trigger, config.hideDelay);
            });

            trigger.addEventListener('blur', function(e) {
                self._scheduleHide(trigger, config.hideDelay);
            });

            // Hide parent tooltip when hovering over child elements with their own tooltips
            trigger.addEventListener('mouseover', function(e) {
                var target = e.target;
                // Check if we're hovering over a child element (not the trigger itself)
                // that has its own tooltip
                if (target !== trigger && target.hasAttribute && target.hasAttribute('data-tooltip')) {
                    self._scheduleHide(trigger, 0); // Hide immediately
                }
            });

            // Keyboard support: hide on Escape
            trigger.addEventListener('keydown', function(e) {
                if (e.key === 'Escape') {
                    self.hide(trigger);
                }
            });

            // Touch support (mobile)
            trigger.addEventListener('touchstart', function(e) {
                // Toggle tooltip on touch
                if (self.activeTooltips.has(trigger)) {
                    self.hide(trigger);
                } else {
                    self.show(trigger);
                    // Auto-hide after 3 seconds on touch devices
                    self._scheduleHide(trigger, 3000);
                }
            }, { passive: true });
        },

        /**
         * Show tooltip for an element
         * @param {HTMLElement} trigger - Element that triggers the tooltip
         */
        show: function(trigger) {
            var self = this;

            // Clear any pending hide timer
            self._clearTimer(trigger);

            // If already showing, do nothing
            if (self.activeTooltips.has(trigger)) return;

            var content = trigger._tooltipContent;
            var config = trigger._tooltipConfig || self.defaults;

            // Create tooltip element
            var tooltip = document.createElement('div');
            tooltip.className = 'rsl-tooltip';
            tooltip.setAttribute('role', 'tooltip');
            tooltip.setAttribute('id', 'tooltip-' + self._generateId());
            tooltip.textContent = content;

            // Add variant class
            if (config.variant && config.variant !== 'default') {
                tooltip.classList.add('rsl-tooltip-' + config.variant);
            }

            // Add size class
            if (config.size && config.size !== 'md') {
                tooltip.classList.add('rsl-tooltip-' + config.size);
            }

            // Set initial position attribute
            tooltip.setAttribute('data-position', config.position);

            // Append to body
            document.body.appendChild(tooltip);

            // Calculate and set position
            self._positionTooltip(tooltip, trigger, config);

            // Create ARIA relationship
            trigger.setAttribute('aria-describedby', tooltip.id);

            // Make visible with slight delay for transition
            requestAnimationFrame(function() {
                tooltip.classList.add('visible');
            });

            // Store reference
            self.activeTooltips.set(trigger, tooltip);

            // Reposition on scroll/resize
            var repositionHandler = function() {
                self._positionTooltip(tooltip, trigger, config);
            };

            window.addEventListener('scroll', repositionHandler, true);
            window.addEventListener('resize', repositionHandler);

            tooltip._repositionHandler = repositionHandler;
        },

        /**
         * Hide tooltip for an element
         * @param {HTMLElement} trigger - Element that triggers the tooltip
         */
        hide: function(trigger) {
            var self = this;

            // Clear any pending show timer
            self._clearTimer(trigger);

            var tooltip = self.activeTooltips.get(trigger);
            if (!tooltip) return;

            // Remove visible class
            tooltip.classList.remove('visible');

            // Remove after transition
            setTimeout(function() {
                if (tooltip && tooltip.parentNode) {
                    tooltip.parentNode.removeChild(tooltip);

                    // Remove event listeners
                    if (tooltip._repositionHandler) {
                        window.removeEventListener('scroll', tooltip._repositionHandler, true);
                        window.removeEventListener('resize', tooltip._repositionHandler);
                    }
                }
            }, 200);

            // Remove ARIA relationship
            trigger.removeAttribute('aria-describedby');

            // Remove from active tooltips
            self.activeTooltips.delete(trigger);
        },

        /**
         * Toggle tooltip visibility
         * @param {HTMLElement} trigger - Element that triggers the tooltip
         */
        toggle: function(trigger) {
            if (this.activeTooltips.has(trigger)) {
                this.hide(trigger);
            } else {
                this.show(trigger);
            }
        },

        /**
         * Destroy tooltip functionality for an element
         * @param {HTMLElement} trigger - Element to detach tooltip from
         */
        destroy: function(trigger) {
            this.hide(trigger);
            // Remove stored config
            delete trigger._tooltipConfig;
            delete trigger._tooltipContent;
        },

        /**
         * Position tooltip relative to trigger element
         * Implements smart positioning with viewport edge detection
         * @private
         */
        _positionTooltip: function(tooltip, trigger, config) {
            var triggerRect = trigger.getBoundingClientRect();
            var tooltipRect = tooltip.getBoundingClientRect();
            var position = config.position;
            var offset = config.offset;

            // Viewport dimensions
            var viewportWidth = window.innerWidth;
            var viewportHeight = window.innerHeight;

            // Auto-position if near edges
            if (config.autoPosition) {
                position = this._getOptimalPosition(position, triggerRect, tooltipRect, viewportWidth, viewportHeight);
                tooltip.setAttribute('data-position', position);
            }

            var top, left;

            switch (position) {
                case 'top':
                    top = triggerRect.top + window.pageYOffset - tooltipRect.height - offset;
                    left = triggerRect.left + window.pageXOffset + (triggerRect.width / 2) - (tooltipRect.width / 2);
                    break;

                case 'bottom':
                    top = triggerRect.bottom + window.pageYOffset + offset;
                    left = triggerRect.left + window.pageXOffset + (triggerRect.width / 2) - (tooltipRect.width / 2);
                    break;

                case 'left':
                    top = triggerRect.top + window.pageYOffset + (triggerRect.height / 2) - (tooltipRect.height / 2);
                    left = triggerRect.left + window.pageXOffset - tooltipRect.width - offset;
                    break;

                case 'right':
                    top = triggerRect.top + window.pageYOffset + (triggerRect.height / 2) - (tooltipRect.height / 2);
                    left = triggerRect.right + window.pageXOffset + offset;
                    break;
            }

            // Constrain to viewport
            var scrollbarWidth = 20; // assume scrollbar width
            left = Math.max(8, Math.min(left, viewportWidth - tooltipRect.width - scrollbarWidth));
            top = Math.max(8, top);

            tooltip.style.top = top + 'px';
            tooltip.style.left = left + 'px';
        },

        /**
         * Determine optimal tooltip position based on available space
         * @private
         */
        _getOptimalPosition: function(preferred, triggerRect, tooltipRect, viewportWidth, viewportHeight) {
            var spaceTop = triggerRect.top;
            var spaceBottom = viewportHeight - triggerRect.bottom;
            var spaceLeft = triggerRect.left;
            var spaceRight = viewportWidth - triggerRect.right;

            // Check if preferred position has enough space
            switch (preferred) {
                case 'top':
                    if (spaceTop < tooltipRect.height + 16 && spaceBottom > tooltipRect.height + 16) {
                        return 'bottom';
                    }
                    break;

                case 'bottom':
                    if (spaceBottom < tooltipRect.height + 16 && spaceTop > tooltipRect.height + 16) {
                        return 'top';
                    }
                    break;

                case 'left':
                    if (spaceLeft < tooltipRect.width + 16 && spaceRight > tooltipRect.width + 16) {
                        return 'right';
                    }
                    break;

                case 'right':
                    if (spaceRight < tooltipRect.width + 16 && spaceLeft > tooltipRect.width + 16) {
                        return 'left';
                    }
                    break;
            }

            return preferred;
        },

        /**
         * Schedule tooltip show with delay
         * @private
         */
        _scheduleShow: function(trigger, delay) {
            var self = this;
            self._clearTimer(trigger);

            var timer = setTimeout(function() {
                self.show(trigger);
            }, delay);

            self.timers.set(trigger, timer);
        },

        /**
         * Schedule tooltip hide with delay
         * @private
         */
        _scheduleHide: function(trigger, delay) {
            var self = this;
            self._clearTimer(trigger);

            var timer = setTimeout(function() {
                self.hide(trigger);
            }, delay);

            self.timers.set(trigger, timer);
        },

        /**
         * Clear pending show/hide timer
         * @private
         */
        _clearTimer: function(trigger) {
            var timer = this.timers.get(trigger);
            if (timer) {
                clearTimeout(timer);
                this.timers.delete(trigger);
            }
        },

        /**
         * Check if element is focusable
         * @private
         */
        _isFocusable: function(element) {
            var focusableTags = ['A', 'BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'];
            return focusableTags.indexOf(element.tagName) !== -1 ||
                   element.hasAttribute('tabindex') ||
                   element.isContentEditable;
        },

        /**
         * Generate unique ID
         * @private
         */
        _generateId: function() {
            return Date.now().toString(36) + Math.random().toString(36).substr(2);
        }
    };

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

})();
