"""
性能分析模块
页面加载性能、资源分析、性能指标
"""
import json
from typing import Optional, Dict, Any, List
from playwright.async_api import Page
from loguru import logger
from dataclasses import dataclass, field
from datetime import datetime
import statistics


@dataclass
class PerformanceMetric:
    """性能指标"""
    name: str
    value: float
    unit: str = "ms"
    timestamp: datetime = field(default_factory=datetime.now)


@dataclass
class ResourceTiming:
    """资源加载时间"""
    name: str
    url: str
    resource_type: str
    start_time: float
    end_time: float
    duration: float
    size: int = 0
    status: int = 0


@dataclass
class PageLoadMetrics:
    """页面加载指标"""
    url: str
    dom_content_loaded: float = 0
    load: float = 0
    first_paint: float = 0
    first_contentful_paint: float = 0
    largest_contentful_paint: float = 0
    time_to_interactive: float = 0
    total_blocking_time: float = 0
    cumulative_layout_shift: float = 0
    speed_index: float = 0
    resources: List[ResourceTiming] = field(default_factory=list)
    timestamp: datetime = field(default_factory=datetime.now)


class PerformanceAnalyzer:
    """
    性能分析器
    分析页面加载性能和资源
    """
    
    def __init__(self, page: Page):
        self.page = page
        self._metrics: List[PageLoadMetrics] = []
    
    async def measure_page_load(self) -> PageLoadMetrics:
        """
        测量页面加载性能
        
        Returns:
            PageLoadMetrics: 页面加载指标
        """
        logger.info("开始测量页面加载性能")
        
        # 获取Navigation Timing
        timing = await self.page.evaluate("""
            () => {
                const timing = performance.getEntriesByType('navigation')[0];
                return timing ? {
                    domContentLoaded: timing.domContentLoadedEventEnd - timing.startTime,
                    load: timing.loadEventEnd - timing.startTime,
                } : null;
            }
        """)
        
        # 获取Paint Timing
        paint_timing = await self.page.evaluate("""
            () => {
                const paints = performance.getEntriesByType('paint');
                const result = {};
                paints.forEach(paint => {
                    result[paint.name] = paint.startTime;
                });
                return result;
            }
        """)
        
        # 获取Web Vitals
        web_vitals = await self.page.evaluate("""
            () => {
                return new Promise((resolve) => {
                    const vitals = {
                        lcp: 0,
                        fid: 0,
                        cls: 0,
                    };
                    
                    // LCP
                    if (PerformanceObserver) {
                        try {
                            const lcpObserver = new PerformanceObserver((list) => {
                                const entries = list.getEntries();
                                vitals.lcp = entries[entries.length - 1].startTime;
                            });
                            lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });
                        } catch (e) {}
                    }
                    
                    // 等待一小段时间让指标收集完成
                    setTimeout(() => resolve(vitals), 100);
                });
            }
        """)
        
        # 获取资源加载时间
        resources = await self.page.evaluate("""
            () => {
                const resources = performance.getEntriesByType('resource');
                return resources.map(r => ({
                    name: r.name,
                    type: r.initiatorType,
                    startTime: r.startTime,
                    duration: r.duration,
                    size: r.transferSize || 0,
                    status: r.responseStatus || 0,
                }));
            }
        """)
        
        # 构建结果
        metrics = PageLoadMetrics(
            url=self.page.url,
            dom_content_loaded=timing.get('domContentLoaded', 0) if timing else 0,
            load=timing.get('load', 0) if timing else 0,
            first_paint=paint_timing.get('first-paint', 0),
            first_contentful_paint=paint_timing.get('first-contentful-paint', 0),
            largest_contentful_paint=web_vitals.get('lcp', 0),
            resources=[
                ResourceTiming(
                    name=r['name'],
                    url=r['name'],
                    resource_type=r['type'],
                    start_time=r['startTime'],
                    end_time=r['startTime'] + r['duration'],
                    duration=r['duration'],
                    size=r['size'],
                    status=r['status'],
                )
                for r in resources
            ]
        )
        
        self._metrics.append(metrics)
        logger.info(f"页面加载性能测量完成: load={metrics.load:.0f}ms")
        
        return metrics
    
    async def get_memory_usage(self) -> Dict[str, float]:
        """
        获取内存使用情况
        
        Returns:
            Dict: 内存使用信息（MB）
        """
        memory = await self.page.evaluate("""
            () => {
                if (performance.memory) {
                    return {
                        usedJSHeapSize: performance.memory.usedJSHeapSize / 1048576,
                        totalJSHeapSize: performance.memory.totalJSHeapSize / 1048576,
                        jsHeapSizeLimit: performance.memory.jsHeapSizeLimit / 1048576,
                    };
                }
                return null;
            }
        """)
        
        return memory or {}
    
    async def get_cpu_usage(self, duration_ms: int = 1000) -> Dict[str, float]:
        """
        获取CPU使用情况
        
        Args:
            duration_ms: 测量持续时间
            
        Returns:
            Dict: CPU使用信息
        """
        cpu = await self.page.evaluate(f"""
            () => {{
                return new Promise((resolve) => {{
                    const start = performance.now();
                    let busy = 0;
                    
                    const interval = setInterval(() => {{
                        busy += 1;
                    }}, 0);
                    
                    setTimeout(() => {{
                        clearInterval(interval);
                        const elapsed = performance.now() - start;
                        resolve({{
                            busyTime: busy,
                            totalTime: elapsed,
                            cpuUsage: (busy / elapsed * 100)
                        }});
                    }}, {duration_ms});
                }});
            }}
        """)
        
        return cpu or {}
    
    async def analyze_resources(self) -> Dict[str, Any]:
        """
        分析资源加载情况
        
        Returns:
            Dict: 资源分析结果
        """
        resources = await self.page.evaluate("""
            () => {
                const resources = performance.getEntriesByType('resource');
                const result = {
                    total: resources.length,
                    totalSize: 0,
                    totalDuration: 0,
                    byType: {},
                    slowResources: [],
                };
                
                resources.forEach(r => {
                    const type = r.initiatorType || 'other';
                    const size = r.transferSize || 0;
                    
                    if (!result.byType[type]) {
                        result.byType[type] = { count: 0, size: 0, duration: 0 };
                    }
                    
                    result.byType[type].count += 1;
                    result.byType[type].size += size;
                    result.byType[type].duration += r.duration;
                    
                    result.totalSize += size;
                    result.totalDuration += r.duration;
                    
                    // 记录慢资源（>500ms）
                    if (r.duration > 500) {
                        result.slowResources.push({
                            name: r.name,
                            type: type,
                            duration: r.duration,
                            size: size,
                        });
                    }
                });
                
                result.totalSizeMB = result.totalSize / 1048576;
                
                return result;
            }
        """)
        
        logger.info(f"资源分析完成: {resources['total']}个资源, {resources['totalSizeMB']:.2f}MB")
        return resources
    
    async def get_web_vitals(self) -> Dict[str, float]:
        """
        获取Web Vitals指标
        
        Returns:
            Dict: Web Vitals
        """
        vitals = await self.page.evaluate("""
            () => {
                return new Promise((resolve) => {
                    const result = {
                        LCP: 0,  // Largest Contentful Paint
                        FID: 0,  // First Input Delay
                        CLS: 0,  // Cumulative Layout Shift
                        FCP: 0,  // First Contentful Paint
                        TTFB: 0, // Time to First Byte
                    };
                    
                    // FCP & TTFB
                    const paints = performance.getEntriesByType('paint');
                    paints.forEach(p => {
                        if (p.name === 'first-contentful-paint') {
                            result.FCP = p.startTime;
                        }
                    });
                    
                    // TTFB
                    const navigation = performance.getEntriesByType('navigation')[0];
                    if (navigation) {
                        result.TTFB = navigation.responseStart - navigation.requestStart;
                    }
                    
                    // LCP
                    try {
                        const lcpEntries = performance.getEntriesByType('largest-contentful-paint');
                        if (lcpEntries.length > 0) {
                            result.LCP = lcpEntries[lcpEntries.length - 1].startTime;
                        }
                    } catch (e) {}
                    
                    // CLS
                    try {
                        let clsValue = 0;
                        const layoutShifts = performance.getEntriesByType('layout-shift');
                        layoutShifts.forEach(entry => {
                            if (!entry.hadRecentInput) {
                                clsValue += entry.value;
                            }
                        });
                        result.CLS = clsValue;
                    } catch (e) {}
                    
                    resolve(result);
                });
            }
        """)
        
        return vitals
    
    def get_resource_by_type(self, resource_type: str) -> List[ResourceTiming]:
        """获取指定类型的资源"""
        if not self._metrics:
            return []
        
        return [
            r for r in self._metrics[-1].resources
            if r.resource_type == resource_type
        ]
    
    def get_slow_resources(self, threshold_ms: float = 1000) -> List[ResourceTiming]:
        """获取慢资源"""
        if not self._metrics:
            return []
        
        return [
            r for r in self._metrics[-1].resources
            if r.duration > threshold_ms
        ]
    
    def summary(self) -> Dict[str, Any]:
        """生成性能摘要"""
        if not self._metrics:
            return {}
        
        latest = self._metrics[-1]
        
        return {
            "url": latest.url,
            "page_load": {
                "dom_content_loaded": f"{latest.dom_content_loaded:.0f}ms",
                "load": f"{latest.load:.0f}ms",
                "first_paint": f"{latest.first_paint:.0f}ms",
                "first_contentful_paint": f"{latest.first_contentful_paint:.0f}ms",
            },
            "resources": {
                "total": len(latest.resources),
                "slow_count": len(self.get_slow_resources()),
            },
            "timestamp": latest.timestamp.isoformat(),
        }
    
    def print_summary(self):
        """打印性能摘要"""
        summary = self.summary()
        
        print("\n=== 性能分析摘要 ===")
        print(f"URL: {summary.get('url', 'N/A')}")
        
        if 'page_load' in summary:
            print("\n页面加载:")
            for key, value in summary['page_load'].items():
                print(f"  {key}: {value}")
        
        if 'resources' in summary:
            print(f"\n资源统计:")
            print(f"  总数: {summary['resources']['total']}")
            print(f"  慢资源: {summary['resources']['slow_count']}")
    
    def save_report(self, filepath: str):
        """保存性能报告"""
        report = {
            "metrics": [
                {
                    "url": m.url,
                    "dom_content_loaded": m.dom_content_loaded,
                    "load": m.load,
                    "first_paint": m.first_paint,
                    "first_contentful_paint": m.first_contentful_paint,
                    "largest_contentful_paint": m.largest_contentful_paint,
                    "resource_count": len(m.resources),
                    "timestamp": m.timestamp.isoformat(),
                }
                for m in self._metrics
            ],
            "summary": self.summary(),
        }
        
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(report, f, ensure_ascii=False, indent=2)
        
        logger.info(f"性能报告已保存: {filepath}")


class PerformanceBudget:
    """
    性能预算
    设置性能阈值，超出时告警
    """
    
    def __init__(self):
        self.thresholds: Dict[str, float] = {
            "dom_content_loaded": 1500,  # ms
            "load": 3000,  # ms
            "first_paint": 1000,  # ms
            "first_contentful_paint": 1800,  # ms
            "largest_contentful_paint": 2500,  # ms
            "total_resources": 100,  # count
            "total_size_mb": 5,  # MB
        }
        self.violations: List[Dict[str, Any]] = []
    
    def set_threshold(self, metric: str, value: float):
        """设置阈值"""
        self.thresholds[metric] = value
    
    def check(self, metrics: PageLoadMetrics) -> List[Dict[str, Any]]:
        """
        检查性能指标是否超出预算
        
        Args:
            metrics: 页面加载指标
            
        Returns:
            List: 违规列表
        """
        violations = []
        
        checks = [
            ("dom_content_loaded", metrics.dom_content_loaded),
            ("load", metrics.load),
            ("first_paint", metrics.first_paint),
            ("first_contentful_paint", metrics.first_contentful_paint),
            ("largest_contentful_paint", metrics.largest_contentful_paint),
        ]
        
        for metric_name, value in checks:
            threshold = self.thresholds.get(metric_name)
            if threshold and value > threshold:
                violation = {
                    "metric": metric_name,
                    "actual": value,
                    "threshold": threshold,
                    "over": value - threshold,
                }
                violations.append(violation)
                logger.warning(
                    f"性能预算违规: {metric_name}={value:.0f}ms, "
                    f"阈值={threshold}ms, 超出={value-threshold:.0f}ms"
                )
        
        self.violations.extend(violations)
        return violations
    
    def is_within_budget(self, metrics: PageLoadMetrics) -> bool:
        """检查是否在预算内"""
        return len(self.check(metrics)) == 0
