// modules/api-manager/PerformanceManager.js
import { Logger } from '../../core/logger.js';

/**
 * Performance APIs Manager - Timing, Metrics, Observers, Optimization
 */
export class PerformanceManager {
    constructor(config = {}) {
        this.config = config;
        this.marks = new Map();
        this.measures = new Map();
        this.observers = new Map();
        this.metrics = new Map();
        this.thresholds = {
            fcp: 2000,  // First Contentful Paint
            lcp: 2500,  // Largest Contentful Paint
            fid: 100,   // First Input Delay
            cls: 0.1,   // Cumulative Layout Shift
            ...config.thresholds
        };
        
        // Check API support
        this.support = {
            performance: 'performance' in window,
            timing: 'timing' in (window.performance || {}),
            navigation: 'navigation' in (window.performance || {}),
            observer: 'PerformanceObserver' in window,
            memory: 'memory' in (window.performance || {}),
            userTiming: 'mark' in (window.performance || {}),
            resourceTiming: 'getEntriesByType' in (window.performance || {}),
            paintTiming: 'PerformanceObserver' in window && PerformanceObserver.supportedEntryTypes?.includes('paint'),
            layoutInstability: 'PerformanceObserver' in window && PerformanceObserver.supportedEntryTypes?.includes('layout-shift'),
            longTask: 'PerformanceObserver' in window && PerformanceObserver.supportedEntryTypes?.includes('longtask')
        };
        
        Logger.info('[PerformanceManager] Initialized with support:', this.support);
        
        // Auto-start core metrics collection
        this.startCoreMetrics();
    }
    
    /**
     * User Timing API - Marks and Measures
     */
    timing = {
        // Create performance mark
        mark: (name, options = {}) => {
            if (!this.support.userTiming) {
                Logger.warn('[PerformanceManager] User Timing not supported');
                return null;
            }
            
            try {
                performance.mark(name, options);
                this.marks.set(name, {
                    name,
                    timestamp: performance.now(),
                    options
                });
                
                Logger.info(`[PerformanceManager] Mark created: ${name}`);
                return this.marks.get(name);
            } catch (error) {
                Logger.error('[PerformanceManager] Mark creation failed:', error);
                return null;
            }
        },
        
        // Create performance measure
        measure: (name, startMark, endMark, options = {}) => {
            if (!this.support.userTiming) {
                Logger.warn('[PerformanceManager] User Timing not supported');
                return null;
            }
            
            try {
                performance.measure(name, startMark, endMark, options);
                const entry = performance.getEntriesByName(name, 'measure')[0];
                
                const measure = {
                    name,
                    startTime: entry.startTime,
                    duration: entry.duration,
                    startMark,
                    endMark,
                    options
                };
                
                this.measures.set(name, measure);
                Logger.info(`[PerformanceManager] Measure created: ${name} (${measure.duration.toFixed(2)}ms)`);
                
                return measure;
            } catch (error) {
                Logger.error('[PerformanceManager] Measure creation failed:', error);
                return null;
            }
        },
        
        // Clear marks and measures
        clear: (name = null) => {
            if (!this.support.userTiming) return;
            
            try {
                if (name) {
                    performance.clearMarks(name);
                    performance.clearMeasures(name);
                    this.marks.delete(name);
                    this.measures.delete(name);
                } else {
                    performance.clearMarks();
                    performance.clearMeasures();
                    this.marks.clear();
                    this.measures.clear();
                }
                
                Logger.info(`[PerformanceManager] Cleared: ${name || 'all'}`);
            } catch (error) {
                Logger.error('[PerformanceManager] Clear failed:', error);
            }
        },
        
        // Get all marks
        getMarks: () => {
            if (!this.support.userTiming) return [];
            return Array.from(this.marks.values());
        },
        
        // Get all measures
        getMeasures: () => {
            if (!this.support.userTiming) return [];
            return Array.from(this.measures.values());
        }
    };
    
    /**
     * Navigation Timing API
     */
    navigation = {
        // Get navigation timing data
        get: () => {
            if (!this.support.navigation) {
                return this.getLegacyNavigationTiming();
            }
            
            try {
                const entry = performance.getEntriesByType('navigation')[0];
                if (!entry) return null;
                
                return {
                    // Navigation phases
                    redirect: entry.redirectEnd - entry.redirectStart,
                    dns: entry.domainLookupEnd - entry.domainLookupStart,
                    connect: entry.connectEnd - entry.connectStart,
                    ssl: entry.connectEnd - entry.secureConnectionStart,
                    ttfb: entry.responseStart - entry.requestStart, // Time to First Byte
                    download: entry.responseEnd - entry.responseStart,
                    domProcessing: entry.domContentLoadedEventStart - entry.responseEnd,
                    domComplete: entry.domComplete - entry.domContentLoadedEventStart,
                    loadComplete: entry.loadEventEnd - entry.loadEventStart,
                    
                    // Total times
                    totalTime: entry.loadEventEnd - entry.startTime,
                    
                    // Enhanced metrics
                    navigationStart: entry.startTime,
                    unloadTime: entry.unloadEventEnd - entry.unloadEventStart,
                    redirectCount: entry.redirectCount,
                    transferSize: entry.transferSize,
                    encodedBodySize: entry.encodedBodySize,
                    decodedBodySize: entry.decodedBodySize,
                    
                    // Connection info
                    connectionInfo: {
                        nextHopProtocol: entry.nextHopProtocol,
                        renderBlockingStatus: entry.renderBlockingStatus
                    }
                };
            } catch (error) {
                Logger.error('[PerformanceManager] Navigation timing failed:', error);
                return null;
            }
        },
        
        // Get performance insights
        getInsights: () => {
            const timing = this.navigation.get();
            if (!timing) return null;
            
            return {
                insights: {
                    serverResponseTime: this.getInsight('ttfb', timing.ttfb, 200, 500),
                    domProcessing: this.getInsight('domProcessing', timing.domProcessing, 500, 1000),
                    totalLoadTime: this.getInsight('totalTime', timing.totalTime, 2000, 4000),
                    transferEfficiency: this.getTransferEfficiency(timing)
                },
                recommendations: this.getNavigationRecommendations(timing)
            };
        }
    };
    
    /**
     * Resource Timing API
     */
    resources = {
        // Get resource timing data
        get: (type = null) => {
            if (!this.support.resourceTiming) {
                Logger.warn('[PerformanceManager] Resource Timing not supported');
                return [];
            }
            
            try {
                const entries = performance.getEntriesByType('resource');
                const resources = entries.map(entry => ({
                    name: entry.name,
                    type: this.getResourceType(entry),
                    startTime: entry.startTime,
                    duration: entry.duration,
                    size: {
                        transfer: entry.transferSize,
                        encoded: entry.encodedBodySize,
                        decoded: entry.decodedBodySize
                    },
                    timing: {
                        redirect: entry.redirectEnd - entry.redirectStart,
                        dns: entry.domainLookupEnd - entry.domainLookupStart,
                        connect: entry.connectEnd - entry.connectStart,
                        ssl: entry.connectEnd - entry.secureConnectionStart,
                        ttfb: entry.responseStart - entry.requestStart,
                        download: entry.responseEnd - entry.responseStart
                    },
                    protocol: entry.nextHopProtocol,
                    cached: entry.transferSize === 0 && entry.decodedBodySize > 0
                }));
                
                return type ? resources.filter(r => r.type === type) : resources;
            } catch (error) {
                Logger.error('[PerformanceManager] Resource timing failed:', error);
                return [];
            }
        },
        
        // Get resource performance summary
        getSummary: () => {
            const resources = this.resources.get();
            
            const summary = {
                total: resources.length,
                types: {},
                totalSize: 0,
                totalDuration: 0,
                cached: 0,
                slowResources: []
            };
            
            resources.forEach(resource => {
                const type = resource.type;
                if (!summary.types[type]) {
                    summary.types[type] = { count: 0, size: 0, duration: 0 };
                }
                
                summary.types[type].count++;
                summary.types[type].size += resource.size.transfer;
                summary.types[type].duration += resource.duration;
                
                summary.totalSize += resource.size.transfer;
                summary.totalDuration += resource.duration;
                
                if (resource.cached) summary.cached++;
                if (resource.duration > 1000) summary.slowResources.push(resource);
            });
            
            return summary;
        }
    };
    
    /**
     * Core Web Vitals monitoring
     */
    vitals = {
        // Start monitoring Core Web Vitals
        start: (callback = null) => {
            const vitalsData = {};
            
            // First Contentful Paint
            this.observePaint((entries) => {
                entries.forEach(entry => {
                    if (entry.name === 'first-contentful-paint') {
                        vitalsData.fcp = entry.startTime;
                        this.checkThreshold('fcp', entry.startTime);
                        if (callback) callback('fcp', entry.startTime);
                    }
                });
            });
            
            // Largest Contentful Paint
            this.observeLCP((entries) => {
                entries.forEach(entry => {
                    vitalsData.lcp = entry.startTime;
                    this.checkThreshold('lcp', entry.startTime);
                    if (callback) callback('lcp', entry.startTime);
                });
            });
            
            // First Input Delay
            this.observeFID((entries) => {
                entries.forEach(entry => {
                    vitalsData.fid = entry.processingStart - entry.startTime;
                    this.checkThreshold('fid', vitalsData.fid);
                    if (callback) callback('fid', vitalsData.fid);
                });
            });
            
            // Cumulative Layout Shift
            this.observeCLS((entries) => {
                let cls = 0;
                entries.forEach(entry => {
                    if (!entry.hadRecentInput) {
                        cls += entry.value;
                    }
                });
                vitalsData.cls = cls;
                this.checkThreshold('cls', cls);
                if (callback) callback('cls', cls);
            });
            
            return vitalsData;
        },
        
        // Get current vitals
        get: () => {
            return {
                fcp: this.getMetric('fcp'),
                lcp: this.getMetric('lcp'),
                fid: this.getMetric('fid'),
                cls: this.getMetric('cls'),
                ratings: {
                    fcp: this.getRating('fcp', this.getMetric('fcp')),
                    lcp: this.getRating('lcp', this.getMetric('lcp')),
                    fid: this.getRating('fid', this.getMetric('fid')),
                    cls: this.getRating('cls', this.getMetric('cls'))
                }
            };
        }
    };
    
    /**
     * Memory monitoring
     */
    memory = {
        // Get memory usage
        get: () => {
            if (!this.support.memory) {
                Logger.warn('[PerformanceManager] Memory API not supported');
                return null;
            }
            
            try {
                const memory = performance.memory;
                return {
                    used: memory.usedJSHeapSize,
                    total: memory.totalJSHeapSize,
                    limit: memory.jsHeapSizeLimit,
                    percentage: (memory.usedJSHeapSize / memory.jsHeapSizeLimit) * 100,
                    formatted: {
                        used: this.formatBytes(memory.usedJSHeapSize),
                        total: this.formatBytes(memory.totalJSHeapSize),
                        limit: this.formatBytes(memory.jsHeapSizeLimit)
                    }
                };
            } catch (error) {
                Logger.error('[PerformanceManager] Memory get failed:', error);
                return null;
            }
        },
        
        // Monitor memory usage
        monitor: (callback, interval = 5000) => {
            if (!this.support.memory) return null;
            
            const intervalId = setInterval(() => {
                const memoryData = this.memory.get();
                if (memoryData) {
                    callback(memoryData);
                    
                    // Warn if memory usage is high
                    if (memoryData.percentage > 80) {
                        Logger.warn('[PerformanceManager] High memory usage detected:', memoryData.percentage.toFixed(1) + '%');
                    }
                }
            }, interval);
            
            return {
                stop: () => clearInterval(intervalId)
            };
        }
    };
    
    /**
     * Long Task monitoring
     */
    longTasks = {
        // Start monitoring long tasks
        start: (callback = null) => {
            if (!this.support.longTask) {
                Logger.warn('[PerformanceManager] Long Task API not supported');
                return null;
            }
            
            try {
                const observer = new PerformanceObserver((list) => {
                    list.getEntries().forEach(entry => {
                        const taskInfo = {
                            duration: entry.duration,
                            startTime: entry.startTime,
                            name: entry.name,
                            attribution: entry.attribution || []
                        };
                        
                        Logger.warn('[PerformanceManager] Long task detected:', taskInfo);
                        if (callback) callback(taskInfo);
                    });
                });
                
                observer.observe({ entryTypes: ['longtask'] });
                
                const observerId = this.generateId('longtask');
                this.observers.set(observerId, observer);
                
                return {
                    id: observerId,
                    stop: () => {
                        observer.disconnect();
                        this.observers.delete(observerId);
                    }
                };
            } catch (error) {
                Logger.error('[PerformanceManager] Long task monitoring failed:', error);
                return null;
            }
        }
    };
    
    /**
     * Performance optimization utilities
     */
    optimize = {
        // Defer non-critical JavaScript
        deferScript: (src, callback = null) => {
            const script = document.createElement('script');
            script.src = src;
            script.defer = true;
            if (callback) script.onload = callback;
            document.head.appendChild(script);
            return script;
        },
        
        // Preload critical resources
        preload: (href, as, crossorigin = false) => {
            const link = document.createElement('link');
            link.rel = 'preload';
            link.href = href;
            link.as = as;
            if (crossorigin) link.crossOrigin = 'anonymous';
            document.head.appendChild(link);
            return link;
        },
        
        // Prefetch future resources
        prefetch: (href) => {
            const link = document.createElement('link');
            link.rel = 'prefetch';
            link.href = href;
            document.head.appendChild(link);
            return link;
        },
        
        // Optimize images with lazy loading
        lazyImages: (selector = 'img[data-src]') => {
            if ('IntersectionObserver' in window) {
                const images = document.querySelectorAll(selector);
                const imageObserver = new IntersectionObserver((entries) => {
                    entries.forEach(entry => {
                        if (entry.isIntersecting) {
                            const img = entry.target;
                            img.src = img.dataset.src;
                            img.classList.remove('lazy');
                            imageObserver.unobserve(img);
                        }
                    });
                });
                
                images.forEach(img => imageObserver.observe(img));
                return imageObserver;
            } else {
                // Fallback for older browsers
                const images = document.querySelectorAll(selector);
                images.forEach(img => {
                    img.src = img.dataset.src;
                    img.classList.remove('lazy');
                });
            }
        },
        
        // Bundle size analyzer
        analyzeBundles: () => {
            const scripts = Array.from(document.querySelectorAll('script[src]'));
            const styles = Array.from(document.querySelectorAll('link[rel="stylesheet"]'));
            
            const analysis = {
                scripts: scripts.map(script => ({
                    src: script.src,
                    async: script.async,
                    defer: script.defer
                })),
                styles: styles.map(style => ({
                    href: style.href,
                    media: style.media
                })),
                recommendations: []
            };
            
            // Add recommendations
            if (scripts.length > 10) {
                analysis.recommendations.push('Consider bundling JavaScript files');
            }
            if (styles.length > 5) {
                analysis.recommendations.push('Consider bundling CSS files');
            }
            
            return analysis;
        }
    };
    
    // Helper methods
    
    startCoreMetrics() {
        // Auto-start vitals monitoring
        this.vitals.start((metric, value) => {
            this.setMetric(metric, value);
        });
        
        // Start memory monitoring if supported
        if (this.support.memory) {
            this.memory.monitor((memoryData) => {
                this.setMetric('memory', memoryData);
            });
        }
    }
    
    observePaint(callback) {
        if (!this.support.paintTiming) return;
        
        try {
            const observer = new PerformanceObserver((list) => {
                callback(list.getEntries());
            });
            observer.observe({ entryTypes: ['paint'] });
            return observer;
        } catch (error) {
            Logger.error('[PerformanceManager] Paint observer failed:', error);
        }
    }
    
    observeLCP(callback) {
        if (!this.support.observer) return;
        
        try {
            const observer = new PerformanceObserver((list) => {
                callback(list.getEntries());
            });
            observer.observe({ entryTypes: ['largest-contentful-paint'] });
            return observer;
        } catch (error) {
            Logger.error('[PerformanceManager] LCP observer failed:', error);
        }
    }
    
    observeFID(callback) {
        if (!this.support.observer) return;
        
        try {
            const observer = new PerformanceObserver((list) => {
                callback(list.getEntries());
            });
            observer.observe({ entryTypes: ['first-input'] });
            return observer;
        } catch (error) {
            Logger.error('[PerformanceManager] FID observer failed:', error);
        }
    }
    
    observeCLS(callback) {
        if (!this.support.layoutInstability) return;
        
        try {
            const observer = new PerformanceObserver((list) => {
                callback(list.getEntries());
            });
            observer.observe({ entryTypes: ['layout-shift'] });
            return observer;
        } catch (error) {
            Logger.error('[PerformanceManager] CLS observer failed:', error);
        }
    }
    
    getLegacyNavigationTiming() {
        if (!this.support.timing) return null;
        
        const timing = performance.timing;
        const navigationStart = timing.navigationStart;
        
        return {
            redirect: timing.redirectEnd - timing.redirectStart,
            dns: timing.domainLookupEnd - timing.domainLookupStart,
            connect: timing.connectEnd - timing.connectStart,
            ssl: timing.connectEnd - timing.secureConnectionStart,
            ttfb: timing.responseStart - timing.requestStart,
            download: timing.responseEnd - timing.responseStart,
            domProcessing: timing.domContentLoadedEventStart - timing.responseEnd,
            domComplete: timing.domComplete - timing.domContentLoadedEventStart,
            loadComplete: timing.loadEventEnd - timing.loadEventStart,
            totalTime: timing.loadEventEnd - navigationStart
        };
    }
    
    getResourceType(entry) {
        const url = new URL(entry.name);
        const extension = url.pathname.split('.').pop().toLowerCase();
        
        const typeMap = {
            js: 'script',
            css: 'stylesheet',
            png: 'image', jpg: 'image', jpeg: 'image', gif: 'image', svg: 'image', webp: 'image',
            woff: 'font', woff2: 'font', ttf: 'font', eot: 'font',
            json: 'fetch', xml: 'fetch'
        };
        
        return typeMap[extension] || entry.initiatorType || 'other';
    }
    
    getInsight(metric, value, good, needs) {
        if (value < good) return { rating: 'good', message: `Excellent ${metric}` };
        if (value < needs) return { rating: 'needs-improvement', message: `${metric} needs improvement` };
        return { rating: 'poor', message: `Poor ${metric} performance` };
    }
    
    getTransferEfficiency(timing) {
        const compressionRatio = timing.decodedBodySize > 0 ? 
            timing.encodedBodySize / timing.decodedBodySize : 1;
        
        return {
            ratio: compressionRatio,
            rating: compressionRatio < 0.7 ? 'good' : compressionRatio < 0.9 ? 'fair' : 'poor'
        };
    }
    
    getNavigationRecommendations(timing) {
        const recommendations = [];
        
        if (timing.ttfb > 500) {
            recommendations.push('Server response time is slow. Consider optimizing backend performance.');
        }
        if (timing.dns > 100) {
            recommendations.push('DNS lookup time is high. Consider using a faster DNS provider.');
        }
        if (timing.connect > 1000) {
            recommendations.push('Connection time is slow. Check network latency.');
        }
        if (timing.domProcessing > 1000) {
            recommendations.push('DOM processing is slow. Consider optimizing JavaScript execution.');
        }
        
        return recommendations;
    }
    
    checkThreshold(metric, value) {
        const threshold = this.thresholds[metric];
        if (threshold && value > threshold) {
            Logger.warn(`[PerformanceManager] ${metric.toUpperCase()} threshold exceeded: ${value}ms (threshold: ${threshold}ms)`);
        }
    }
    
    getRating(metric, value) {
        const thresholds = {
            fcp: { good: 1800, poor: 3000 },
            lcp: { good: 2500, poor: 4000 },
            fid: { good: 100, poor: 300 },
            cls: { good: 0.1, poor: 0.25 }
        };
        
        const threshold = thresholds[metric];
        if (!threshold || value === null || value === undefined) return 'unknown';
        
        if (value <= threshold.good) return 'good';
        if (value <= threshold.poor) return 'needs-improvement';
        return 'poor';
    }
    
    setMetric(key, value) {
        this.metrics.set(key, {
            value,
            timestamp: Date.now()
        });
    }
    
    getMetric(key) {
        const metric = this.metrics.get(key);
        return metric ? metric.value : null;
    }
    
    formatBytes(bytes) {
        if (bytes === 0) return '0 Bytes';
        
        const k = 1024;
        const sizes = ['Bytes', 'KB', 'MB', 'GB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    }
    
    generateId(prefix = 'perf') {
        return `${prefix}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    }
    
    /**
     * Stop all observers and clear data
     */
    cleanup() {
        this.observers.forEach(observer => {
            observer.disconnect();
        });
        this.observers.clear();
        this.metrics.clear();
        this.marks.clear();
        this.measures.clear();
        Logger.info('[PerformanceManager] Cleanup completed');
    }
    
    /**
     * Get comprehensive performance report
     */
    getReport() {
        return {
            support: this.support,
            navigation: this.navigation.get(),
            resources: this.resources.getSummary(),
            vitals: this.vitals.get(),
            memory: this.memory.get(),
            marks: this.timing.getMarks(),
            measures: this.timing.getMeasures(),
            activeObservers: this.observers.size,
            timestamp: Date.now()
        };
    }
}