/**
 * RSL Universal Dark Mode (JavaScript-Based)
 *
 * Automatically generates dark mode styles for pages without custom dark mode CSS.
 * Works with the RSL theme toggle system (theme-toggle.js).
 *
 * @fileoverview JavaScript-based automatic dark mode generation
 * @version 2.0.0
 * @license MIT
 *
 * How it works:
 * 1. Listens for theme changes on document.documentElement
 * 2. Scans all visible elements and reads their computed colors
 * 3. Uses isLight() from color-adjuster.js to determine if transformation needed
 * 4. Applies inline style overrides dynamically for dark mode
 * 5. Restores original styles when switching back to light mode
 *
 * Dependencies:
 * - color-adjuster.js (for isLight(), adjustColor(), adjustColorPercentage())
 * - theme-toggle.js (for theme switching)
 *
 * Usage:
 * Include scripts in this order:
 * <script src="javascript/color-adjuster.js"></script>
 * <script src="javascript/theme-toggle.js"></script>
 * <script src="javascript/universal-dark-mode.js"></script>
 *
 * To exclude specific elements from dark mode transformation:
 * <div data-no-dark-mode>This stays as-is in dark mode</div>
 *
 * Note: This provides automatic dark mode. For brand-specific dark themes,
 * write custom [data-theme="dark"] CSS instead and don't include this script.
 */

(function() {
    'use strict';

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

    /**
     * Universal Dark Mode Module (JavaScript-Based)
     */
    window.RSL.UniversalDarkMode = {

        /** Whether the module has been initialized */
        initialized: false,

        /** Store original styles for restoration */
        originalStyles: new WeakMap(),

        /** Elements that have been transformed */
        transformedElements: new Set(),

        /** Mutation observer for dynamic content */
        observer: null,

        /** Debounce timer for batch processing */
        debounceTimer: null,

        /** Dark mode color palette */
        colors: {
            bgDark: '#1a1a2e',
            bgDarkSecondary: '#16213e',
            bgDarkTertiary: '#0f3460',
            textLight: '#ffffff',
            textLightSecondary: 'rgba(255, 255, 255, 0.85)',
            textLightTertiary: 'rgba(255, 255, 255, 0.7)',
            accent: '#6E7BFF'
        },

        /** Minimum contrast ratio for readability */
        minContrastRatio: 4.5,

        /**
         * Initialize universal dark mode
         */
        init: function() {
            if (this.initialized) return;

            // Check for color-adjuster.js dependency
            if (typeof window.isLight !== 'function') {
                console.warn('[RSL UniversalDarkMode] Missing dependency: color-adjuster.js. Include it before universal-dark-mode.js');
                return;
            }

            // Set up theme change listener
            this._setupThemeListener();

            // Process current theme state
            var currentTheme = document.documentElement.getAttribute('data-theme');
            if (currentTheme === 'dark') {
                this._applyDarkMode();
            }

            // Set up mutation observer for dynamic content
            this._setupMutationObserver();

            this.initialized = true;
            console.log('[RSL] Universal Dark Mode v2.0 (JS-based) initialized');
        },

        /**
         * Set up listener for theme attribute changes
         * @private
         */
        _setupThemeListener: function() {
            var self = this;

            // Use MutationObserver to watch for theme changes
            var themeObserver = new MutationObserver(function(mutations) {
                mutations.forEach(function(mutation) {
                    if (mutation.type === 'attributes' && mutation.attributeName === 'data-theme') {
                        var newTheme = document.documentElement.getAttribute('data-theme');
                        if (newTheme === 'dark') {
                            self._applyDarkMode();
                        } else {
                            self._removeDarkMode();
                        }
                    }
                });
            });

            themeObserver.observe(document.documentElement, {
                attributes: true,
                attributeFilter: ['data-theme']
            });
        },

        /**
         * Set up mutation observer for dynamically added content
         * @private
         */
        _setupMutationObserver: function() {
            var self = this;

            this.observer = new MutationObserver(function(mutations) {
                var currentTheme = document.documentElement.getAttribute('data-theme');
                if (currentTheme !== 'dark') return;

                // Debounce to batch process multiple mutations
                clearTimeout(self.debounceTimer);
                self.debounceTimer = setTimeout(function() {
                    mutations.forEach(function(mutation) {
                        mutation.addedNodes.forEach(function(node) {
                            if (node.nodeType === Node.ELEMENT_NODE) {
                                self._processElement(node);
                                // Also process children
                                var children = node.querySelectorAll('*');
                                children.forEach(function(child) {
                                    self._processElement(child);
                                });
                            }
                        });
                    });
                }, 50);
            });

            this.observer.observe(document.body, {
                childList: true,
                subtree: true
            });
        },

        /**
         * Apply dark mode transformations to all elements
         * @private
         */
        _applyDarkMode: function() {
            var self = this;

            // Get all elements in the document
            var allElements = document.querySelectorAll('body, body *');

            allElements.forEach(function(el) {
                self._processElement(el);
            });
        },

        /**
         * Process a single element for dark mode transformation
         * @param {HTMLElement} el - Element to process
         * @private
         */
        _processElement: function(el) {
            // Skip non-element nodes
            if (!el || el.nodeType !== Node.ELEMENT_NODE) return;

            // Skip elements with data-no-dark-mode
            if (el.hasAttribute('data-no-dark-mode')) return;

            // Skip if inside a data-no-dark-mode parent
            if (el.closest('[data-no-dark-mode]')) return;

            // Skip certain element types
            var tagName = el.tagName.toLowerCase();
            if (['script', 'style', 'link', 'meta', 'head', 'noscript', 'br', 'hr', 'img', 'video', 'iframe', 'canvas', 'svg'].indexOf(tagName) !== -1) {
                return;
            }

            // Skip if already transformed
            if (this.transformedElements.has(el)) return;

            // Get computed styles
            var computed = window.getComputedStyle(el);
            var bgColor = computed.backgroundColor;
            var bgImage = computed.backgroundImage;
            var textColor = computed.color;
            var borderColor = computed.borderColor;

            // Store original styles
            if (!this.originalStyles.has(el)) {
                this.originalStyles.set(el, {
                    backgroundColor: el.style.backgroundColor,
                    backgroundImage: el.style.backgroundImage,
                    color: el.style.color,
                    borderColor: el.style.borderColor
                });
            }

            var stylesApplied = false;

            // Process background gradient (linear-gradient, radial-gradient)
            if (bgImage && bgImage !== 'none' && bgImage.indexOf('gradient') !== -1) {
                var newGradient = this._transformGradient(bgImage, el);
                if (newGradient && newGradient !== bgImage) {
                    el.style.backgroundImage = newGradient;
                    stylesApplied = true;
                }
            }
            // Process solid background color
            else if (bgColor && bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent') {
                var newBg = this._transformBackgroundColor(bgColor, el);
                if (newBg && newBg !== bgColor) {
                    el.style.backgroundColor = newBg;
                    stylesApplied = true;
                }
            }

            // Process text color
            if (textColor) {
                var parentBg = this._getEffectiveBackgroundColor(el);
                var newText = this._transformTextColor(textColor, parentBg, el);
                if (newText && newText !== textColor) {
                    el.style.color = newText;
                    stylesApplied = true;
                }
            }

            // Process border color (only if it's visible)
            var borderWidth = computed.borderWidth;
            if (borderColor && borderWidth && borderWidth !== '0px') {
                var newBorder = this._transformBorderColor(borderColor);
                if (newBorder && newBorder !== borderColor) {
                    el.style.borderColor = newBorder;
                    stylesApplied = true;
                }
            }

            if (stylesApplied) {
                this.transformedElements.add(el);
            }
        },

        /**
         * Get the effective background color for an element (checks parents)
         * @param {HTMLElement} el - Element to check
         * @returns {string} RGB color string
         * @private
         */
        _getEffectiveBackgroundColor: function(el) {
            var current = el;
            while (current && current !== document.documentElement) {
                var computed = window.getComputedStyle(current);
                var bg = computed.backgroundColor;
                var bgImage = computed.backgroundImage;

                // Check for solid background color
                if (bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent') {
                    return bg;
                }

                // Check for gradient - extract first color as representative
                if (bgImage && bgImage !== 'none' && bgImage.indexOf('gradient') !== -1) {
                    var colorMatch = bgImage.match(/#[0-9a-fA-F]{3,8}|rgba?\([^)]+\)/);
                    if (colorMatch) {
                        return colorMatch[0];
                    }
                }

                current = current.parentElement;
            }
            // Default to dark background if none found
            return this.colors.bgDark;
        },

        /**
         * Transform a background color for dark mode
         * @param {string} color - Original color
         * @param {HTMLElement} el - Element for context
         * @returns {string|null} Transformed color or null if no change
         * @private
         */
        _transformBackgroundColor: function(color, el) {
            var rgb = this._parseColor(color);
            if (!rgb) return null;

            // Check if it's a light background that needs darkening
            if (window.isLight(color)) {
                // It's a light background - darken it

                // Check if it's a semantic/colored background (has saturation)
                var hsl = this._rgbToHsl(rgb);
                var saturation = hsl.s;
                var luminance = this._getLuminance(rgb);

                // If it has noticeable color (saturation > 5%), preserve the hue
                // Note: Light tinted backgrounds like #f0fff4 have very low saturation (~10%)
                if (saturation > 0.05 && luminance < 0.98) {
                    // This is a colored background (like light blue, light green, etc.)
                    // Darken it significantly but keep the hue

                    // Adjust lightness based on hue - greens and yellows need more lightness to be visible
                    // Hue ranges: Red ~0, Yellow ~0.16, Green ~0.33, Cyan ~0.5, Blue ~0.66, Magenta ~0.83
                    var baseLightness = 0.12;
                    var hueDegrees = hsl.h * 360;

                    // Yellow-green range (30-180 degrees) needs higher lightness
                    if (hueDegrees >= 30 && hueDegrees <= 180) {
                        // Peak boost around yellow-green (60-120), taper off at edges
                        var center = 90;
                        var distance = Math.abs(hueDegrees - center);
                        var boost = Math.max(0, 1 - (distance / 90)); // 0 to 1
                        baseLightness = 0.12 + (boost * 0.08); // 0.12 to 0.20
                    }

                    // Create a dark version: low lightness, moderate saturation
                    var darkened = this._hslToRgb({
                        h: hsl.h,
                        s: Math.min(hsl.s * 0.8, 0.5), // Keep more saturation for visibility
                        l: baseLightness
                    });
                    return 'rgb(' + darkened.r + ', ' + darkened.g + ', ' + darkened.b + ')';
                }

                // Neutral/grayscale backgrounds
                if (luminance > 0.95) {
                    // Pure white or nearly white - use our dark base
                    return this.colors.bgDark;
                } else if (luminance > 0.85) {
                    // Very light - use secondary dark
                    return this.colors.bgDarkSecondary;
                } else if (luminance > 0.6) {
                    // Light - darken by percentage
                    return window.adjustColorPercentage(color, -0.7);
                } else {
                    // Medium light - darken less
                    return window.adjustColorPercentage(color, -0.5);
                }
            } else {
                // It's already dark - might need slight adjustment
                var luminance = this._getLuminance(rgb);

                if (luminance < 0.05) {
                    // Pure black or nearly black - make slightly lighter for depth
                    return window.adjustColorPercentage(color, 0.1);
                }
            }

            return null; // No change needed
        },

        /**
         * Convert RGB to HSL
         * @param {Object} rgb - {r, g, b} values 0-255
         * @returns {Object} {h, s, l} values 0-1
         * @private
         */
        _rgbToHsl: function(rgb) {
            var r = rgb.r / 255;
            var g = rgb.g / 255;
            var b = rgb.b / 255;

            var max = Math.max(r, g, b);
            var min = Math.min(r, g, b);
            var h, s, l = (max + min) / 2;

            if (max === min) {
                h = s = 0; // achromatic
            } else {
                var d = max - min;
                s = l > 0.5 ? d / (2 - max - min) : d / (max + min);

                switch (max) {
                    case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break;
                    case g: h = ((b - r) / d + 2) / 6; break;
                    case b: h = ((r - g) / d + 4) / 6; break;
                }
            }

            return { h: h, s: s, l: l };
        },

        /**
         * Convert HSL to RGB
         * @param {Object} hsl - {h, s, l} values 0-1
         * @returns {Object} {r, g, b} values 0-255
         * @private
         */
        _hslToRgb: function(hsl) {
            var h = hsl.h;
            var s = hsl.s;
            var l = hsl.l;
            var r, g, b;

            if (s === 0) {
                r = g = b = l; // achromatic
            } else {
                var hue2rgb = function(p, q, t) {
                    if (t < 0) t += 1;
                    if (t > 1) t -= 1;
                    if (t < 1/6) return p + (q - p) * 6 * t;
                    if (t < 1/2) return q;
                    if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
                    return p;
                };

                var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
                var p = 2 * l - q;
                r = hue2rgb(p, q, h + 1/3);
                g = hue2rgb(p, q, h);
                b = hue2rgb(p, q, h - 1/3);
            }

            return {
                r: Math.round(r * 255),
                g: Math.round(g * 255),
                b: Math.round(b * 255)
            };
        },

        /**
         * Transform text color for dark mode
         * @param {string} color - Original text color
         * @param {string} bgColor - Background color for contrast check
         * @param {HTMLElement} el - Element for context
         * @returns {string|null} Transformed color or null if no change
         * @private
         */
        _transformTextColor: function(color, bgColor, el) {
            var rgb = this._parseColor(color);
            if (!rgb) return null;

            // Check if this is a semantic/colored text (not just gray/black)
            var hsl = this._rgbToHsl(rgb);
            var saturation = hsl.s;
            var luminance = this._getLuminance(rgb);

            // Dark text on what will be a dark background needs to become light
            if (!window.isLight(color)) {
                // Check if it's a colored text (semantic color like blue, green, etc.)
                if (saturation > 0.3) {
                    // This is colored text - lighten it while preserving hue
                    var lightened = this._hslToRgb({
                        h: hsl.h,
                        s: Math.min(hsl.s * 1.2, 0.7), // Boost saturation slightly
                        l: 0.65 // Light enough to read on dark background
                    });
                    return 'rgb(' + lightened.r + ', ' + lightened.g + ', ' + lightened.b + ')';
                }

                // Neutral dark text - make it light
                if (luminance < 0.1) {
                    // Very dark (black or near-black) - use primary light text
                    return this.colors.textLight;
                } else if (luminance < 0.3) {
                    // Dark gray - use secondary light text
                    return this.colors.textLightSecondary;
                } else if (luminance < 0.5) {
                    // Medium dark - lighten significantly
                    return window.adjustColorPercentage(color, 0.6);
                }
            } else {
                // Light text - check if it's light enough for dark background
                if (luminance < 0.7) {
                    // Not light enough - boost it
                    return window.adjustColorPercentage(color, 0.3);
                }
            }

            return null; // No change needed
        },

        /**
         * Transform border color for dark mode
         * @param {string} color - Original border color
         * @returns {string|null} Transformed color or null if no change
         * @private
         */
        _transformBorderColor: function(color) {
            var rgb = this._parseColor(color);
            if (!rgb) return null;

            // Check if this is a semantic/colored border
            var hsl = this._rgbToHsl(rgb);
            var saturation = hsl.s;

            // If the border has strong color (semantic border like alert stripes), preserve it
            if (saturation > 0.4) {
                // This is a colored border - keep it but possibly adjust brightness
                if (window.isLight(color)) {
                    // Light colored border - darken it slightly but keep the color
                    var adjusted = this._hslToRgb({
                        h: hsl.h,
                        s: hsl.s,
                        l: Math.max(hsl.l * 0.7, 0.35) // Darken but not too much
                    });
                    return 'rgb(' + adjusted.r + ', ' + adjusted.g + ', ' + adjusted.b + ')';
                }
                // Dark colored border - leave it alone
                return null;
            }

            // Neutral borders
            if (window.isLight(color)) {
                return 'rgba(255, 255, 255, 0.15)';
            } else {
                // Dark borders - make them slightly visible
                return 'rgba(255, 255, 255, 0.1)';
            }
        },

        /**
         * Transform a CSS gradient for dark mode
         * @param {string} gradient - Original gradient string (linear-gradient, radial-gradient)
         * @param {HTMLElement} el - Element for context
         * @returns {string|null} Transformed gradient or null if no change
         * @private
         */
        _transformGradient: function(gradient, el) {
            var self = this;

            // Extract all color values from the gradient
            // Matches: #hex, rgb(), rgba(), and color names
            var colorRegex = /(#[0-9a-fA-F]{3,8}|rgba?\([^)]+\)|[a-zA-Z]+(?=\s+\d|,|\)))/g;
            var colors = gradient.match(colorRegex);

            if (!colors || colors.length === 0) return null;

            // Check if at least one color is light (needs transformation)
            var hasLightColor = colors.some(function(color) {
                // Skip CSS keywords that aren't colors
                if (['to', 'from', 'at', 'circle', 'ellipse', 'closest', 'farthest', 'side', 'corner'].indexOf(color.toLowerCase()) !== -1) {
                    return false;
                }
                var rgb = self._parseColor(color);
                if (!rgb) return false;
                return window.isLight(color);
            });

            if (!hasLightColor) return null;

            // Transform each color in the gradient
            var transformedGradient = gradient;
            colors.forEach(function(color) {
                // Skip CSS keywords
                if (['to', 'from', 'at', 'circle', 'ellipse', 'closest', 'farthest', 'side', 'corner'].indexOf(color.toLowerCase()) !== -1) {
                    return;
                }

                var rgb = self._parseColor(color);
                if (!rgb) return;

                var newColor;
                if (window.isLight(color)) {
                    // Transform light colors to dark
                    var luminance = self._getLuminance(rgb);
                    if (luminance > 0.9) {
                        // Very light (white-ish) -> dark base
                        newColor = self.colors.bgDark;
                    } else if (luminance > 0.7) {
                        // Light -> secondary dark
                        newColor = self.colors.bgDarkSecondary;
                    } else {
                        // Medium light -> darken by percentage
                        newColor = window.adjustColorPercentage(color, -0.6);
                    }
                } else {
                    // Already dark - slight adjustment for depth
                    newColor = window.adjustColorPercentage(color, 0.05);
                }

                if (newColor) {
                    // Replace this color occurrence in the gradient
                    // Use a function to handle special regex characters in color strings
                    transformedGradient = transformedGradient.split(color).join(newColor);
                }
            });

            return transformedGradient;
        },

        /**
         * Parse a color string to RGB object
         * @param {string} color - Color string (rgb, rgba, hex)
         * @returns {Object|null} {r, g, b, a} or null if unparseable
         * @private
         */
        _parseColor: function(color) {
            if (!color) return null;

            // Handle RGB/RGBA
            var rgbaMatch = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
            if (rgbaMatch) {
                return {
                    r: parseInt(rgbaMatch[1]),
                    g: parseInt(rgbaMatch[2]),
                    b: parseInt(rgbaMatch[3]),
                    a: rgbaMatch[4] ? parseFloat(rgbaMatch[4]) : 1
                };
            }

            // Handle HEX
            if (color.startsWith('#')) {
                var hex = color.slice(1);
                if (hex.length === 3) {
                    hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
                }
                return {
                    r: parseInt(hex.slice(0, 2), 16),
                    g: parseInt(hex.slice(2, 4), 16),
                    b: parseInt(hex.slice(4, 6), 16),
                    a: 1
                };
            }

            // Handle named colors (basic set)
            var namedColors = {
                'white': { r: 255, g: 255, b: 255, a: 1 },
                'black': { r: 0, g: 0, b: 0, a: 1 },
                'transparent': null
            };

            return namedColors[color.toLowerCase()] || null;
        },

        /**
         * Calculate relative luminance of a color
         * @param {Object} rgb - {r, g, b} color object
         * @returns {number} Luminance value 0-1
         * @private
         */
        _getLuminance: function(rgb) {
            // sRGB to linear
            var r = rgb.r / 255;
            var g = rgb.g / 255;
            var b = rgb.b / 255;

            r = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
            g = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
            b = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);

            // Relative luminance
            return 0.2126 * r + 0.7152 * g + 0.0722 * b;
        },

        /**
         * Remove dark mode transformations
         * @private
         */
        _removeDarkMode: function() {
            var self = this;

            this.transformedElements.forEach(function(el) {
                // Restore original styles
                var original = self.originalStyles.get(el);
                if (original) {
                    el.style.backgroundColor = original.backgroundColor;
                    el.style.backgroundImage = original.backgroundImage;
                    el.style.color = original.color;
                    el.style.borderColor = original.borderColor;
                }
            });

            // Clear the set
            this.transformedElements.clear();
        },

        /**
         * Force refresh all transformations
         * Call this after major DOM changes
         */
        refresh: function() {
            var currentTheme = document.documentElement.getAttribute('data-theme');
            if (currentTheme === 'dark') {
                this._removeDarkMode();
                this._applyDarkMode();
            }
        },

        /**
         * Destroy the module and clean up
         */
        destroy: function() {
            this._removeDarkMode();

            if (this.observer) {
                this.observer.disconnect();
                this.observer = null;
            }

            this.originalStyles = new WeakMap();
            this.initialized = false;
        },

        /**
         * Customize the color palette
         * @param {Object} customColors - Object with color overrides
         */
        setColors: function(customColors) {
            Object.assign(this.colors, customColors);

            // If in dark mode, reapply
            var currentTheme = document.documentElement.getAttribute('data-theme');
            if (currentTheme === 'dark') {
                this.refresh();
            }
        },

        /**
         * Get current color palette
         * @returns {Object} Color palette
         */
        getColors: function() {
            return Object.assign({}, this.colors);
        }
    };

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

})();
