/**
 * AI Auto Tool - Performance Utilities
 * 
 * Utilities for optimizing JavaScript performance including debouncing, throttling,
 * request batching, and lazy loading
 * 
 * @package AI Auto Tool
 * @version 2.3.0
 */

(function(window) {
    'use strict';
    
    /**
     * Performance utilities object
     */
    const AiautotoolPerformance = {
        
        /**
         * Debounce function - delays function execution until after wait time
         * 
         * @param {Function} func Function to debounce
         * @param {number} wait Wait time in milliseconds
         * @param {boolean} immediate Execute immediately on first call
         * @returns {Function} Debounced function
         */
        debounce: function(func, wait, immediate) {
            let timeout;
            return function executedFunction() {
                const context = this;
                const args = arguments;
                
                const later = function() {
                    timeout = null;
                    if (!immediate) func.apply(context, args);
                };
                
                const callNow = immediate && !timeout;
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
                
                if (callNow) func.apply(context, args);
            };
        },
        
        /**
         * Throttle function - limits function execution frequency
         * 
         * @param {Function} func Function to throttle
         * @param {number} limit Time limit in milliseconds
         * @returns {Function} Throttled function
         */
        throttle: function(func, limit) {
            let inThrottle;
            return function() {
                const args = arguments;
                const context = this;
                if (!inThrottle) {
                    func.apply(context, args);
                    inThrottle = true;
                    setTimeout(() => inThrottle = false, limit);
                }
            };
        },
        
        /**
         * Request queue for batching AJAX requests
         */
        requestQueue: {
            queue: [],
            processing: false,
            batchDelay: 100, // Wait 100ms to collect multiple requests
            maxBatchSize: 5,
            
            /**
             * Add request to queue
             */
            add: function(request) {
                this.queue.push(request);
                this.process();
            },
            
            /**
             * Process queued requests
             */
            process: function() {
                if (this.processing || this.queue.length === 0) {
                    return;
                }
                
                this.processing = true;
                
                // Wait for batch delay to collect more requests
                setTimeout(() => {
                    const batch = this.queue.splice(0, this.maxBatchSize);
                    
                    if (batch.length === 1) {
                        // Single request - execute directly
                        this.executeRequest(batch[0]);
                    } else {
                        // Multiple requests - batch them
                        this.executeBatch(batch);
                    }
                    
                    this.processing = false;
                    
                    // Process remaining queue if any
                    if (this.queue.length > 0) {
                        this.process();
                    }
                }, this.batchDelay);
            },
            
            /**
             * Execute single request
             */
            executeRequest: function(request) {
                if (request && typeof request.callback === 'function') {
                    request.callback();
                }
            },
            
            /**
             * Execute batch of requests
             */
            executeBatch: function(batch) {
                // Execute all requests in batch
                batch.forEach(request => {
                    this.executeRequest(request);
                });
            }
        },
        
        /**
         * Lazy load images with intersection observer
         */
        lazyLoadImages: function() {
            if ('IntersectionObserver' in window) {
                const imageObserver = new IntersectionObserver((entries, observer) => {
                    entries.forEach(entry => {
                        if (entry.isIntersecting) {
                            const img = entry.target;
                            if (img.dataset.src) {
                                img.src = img.dataset.src;
                                img.removeAttribute('data-src');
                                img.classList.add('loaded');
                            }
                            observer.unobserve(img);
                        }
                    });
                });
                
                // Observe all images with data-src attribute
                document.querySelectorAll('img[data-src]').forEach(img => {
                    imageObserver.observe(img);
                });
            } else {
                // Fallback for older browsers
                document.querySelectorAll('img[data-src]').forEach(img => {
                    img.src = img.dataset.src;
                    img.removeAttribute('data-src');
                });
            }
        },
        
        /**
         * Optimized AJAX request with caching and debouncing
         */
        optimizedAjax: {
            cache: {},
            pendingRequests: {},
            
            /**
             * Make optimized AJAX request
             * 
             * @param {Object} options AJAX options
             * @param {boolean} useCache Use cache if available
             * @param {number} debounceDelay Debounce delay in ms
             * @returns {Promise} AJAX promise
             */
            request: function(options, useCache, debounceDelay) {
                const self = this;
                useCache = useCache !== false; // Default true
                debounceDelay = debounceDelay || 0;
                
                // Create cache key
                const cacheKey = JSON.stringify({
                    url: options.url,
                    data: options.data,
                    action: options.data && options.data.action
                });
                
                // Check cache
                if (useCache && this.cache[cacheKey]) {
                    const cached = this.cache[cacheKey];
                    // Check if cache is still valid (5 minutes TTL)
                    if (Date.now() - cached.timestamp < 300000) {
                        return Promise.resolve(cached.data);
                    }
                }
                
                // Check if same request is pending
                if (this.pendingRequests[cacheKey]) {
                    return this.pendingRequests[cacheKey];
                }
                
                // Create debounced request function
                const makeRequest = () => {
                    const promise = new Promise((resolve, reject) => {
                        jQuery.ajax(options).done(function(data) {
                            // Cache successful responses
                            if (useCache && data && data.code == '200') {
                                self.cache[cacheKey] = {
                                    data: data,
                                    timestamp: Date.now()
                                };
                            }
                            resolve(data);
                        }).fail(function(error) {
                            reject(error);
                        }).always(function() {
                            // Remove from pending requests
                            delete self.pendingRequests[cacheKey];
                        });
                    });
                    
                    this.pendingRequests[cacheKey] = promise;
                    return promise;
                };
                
                if (debounceDelay > 0) {
                    const debouncedRequest = AiautotoolPerformance.debounce(makeRequest, debounceDelay);
                    return debouncedRequest();
                } else {
                    return makeRequest();
                }
            },
            
            /**
             * Clear cache
             */
            clearCache: function() {
                this.cache = {};
            },
            
            /**
             * Clear specific cache entry
             */
            clearCacheEntry: function(key) {
                delete this.cache[key];
            }
        }
    };
    
    // Initialize lazy loading on DOM ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', function() {
            AiautotoolPerformance.lazyLoadImages();
        });
    } else {
        AiautotoolPerformance.lazyLoadImages();
    }
    
    // Expose to global scope
    window.AiautotoolPerformance = AiautotoolPerformance;
    
    // Export for use in other scripts
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = AiautotoolPerformance;
    }
    
})(window);

