"""
测试报告和分析
生成详细的测试报告
"""
import json
from typing import Optional, List, Dict, Any
from pathlib import Path
from datetime import datetime
from loguru import logger


class TestReportBuilder:
    """
    测试报告构建器
    生成详细的测试报告
    """
    
    def __init__(self, title: str = "Test Report"):
        self.title = title
        self.tests: List[Dict[str, Any]] = []
        self.start_time: Optional[datetime] = None
        self.end_time: Optional[datetime] = None
        self.metadata: Dict[str, Any] = {}
    
    def start(self):
        """开始记录"""
        self.start_time = datetime.now()
    
    def end(self):
        """结束记录"""
        self.end_time = datetime.now()
    
    def add_test(
        self,
        name: str,
        passed: bool,
        duration: float = 0,
        error: str = None,
        screenshot: str = None,
        logs: List[str] = None,
    ):
        """添加测试结果"""
        self.tests.append({
            "name": name,
            "passed": passed,
            "duration": duration,
            "error": error,
            "screenshot": screenshot,
            "logs": logs or [],
            "timestamp": datetime.now().isoformat(),
        })
    
    def add_metadata(self, key: str, value: Any):
        """添加元数据"""
        self.metadata[key] = value
    
    def summary(self) -> Dict[str, Any]:
        """生成摘要"""
        total = len(self.tests)
        passed = sum(1 for t in self.tests if t["passed"])
        failed = total - passed
        
        total_duration = sum(t["duration"] for t in self.tests)
        
        return {
            "total": total,
            "passed": passed,
            "failed": failed,
            "pass_rate": f"{passed/total*100:.1f}%" if total > 0 else "N/A",
            "total_duration": f"{total_duration:.2f}s",
            "start_time": self.start_time.isoformat() if self.start_time else None,
            "end_time": self.end_time.isoformat() if self.end_time else None,
        }
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            "title": self.title,
            "summary": self.summary(),
            "tests": self.tests,
            "metadata": self.metadata,
            "generated_at": datetime.now().isoformat(),
        }
    
    def to_json(self, filepath: str):
        """保存为JSON"""
        Path(filepath).parent.mkdir(parents=True, exist_ok=True)
        
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(self.to_dict(), f, ensure_ascii=False, indent=2)
        
        logger.info(f"报告已保存: {filepath}")
    
    def to_html(self, filepath: str):
        """生成HTML报告"""
        summary = self.summary()
        
        html = f"""
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{self.title}</title>
    <style>
        * {{ margin: 0; padding: 0; box-sizing: border-box; }}
        body {{ 
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: #f5f5f5;
            padding: 20px;
        }}
        .container {{ max-width: 1200px; margin: 0 auto; }}
        .header {{ 
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 30px;
            border-radius: 10px;
            margin-bottom: 20px;
        }}
        .header h1 {{ margin-bottom: 10px; }}
        .header .time {{ opacity: 0.8; }}
        
        .summary {{ 
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin-bottom: 20px;
        }}
        .summary-card {{ 
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }}
        .summary-card h3 {{ color: #666; margin-bottom: 10px; }}
        .summary-card .value {{ font-size: 32px; font-weight: bold; }}
        .summary-card.pass .value {{ color: #4CAF50; }}
        .summary-card.fail .value {{ color: #f44336; }}
        .summary-card.total .value {{ color: #2196F3; }}
        
        .tests {{ background: white; border-radius: 10px; overflow: hidden; }}
        .test-item {{ 
            padding: 15px 20px;
            border-bottom: 1px solid #eee;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }}
        .test-item:last-child {{ border-bottom: none; }}
        .test-item:hover {{ background: #f9f9f9; }}
        .test-item.pass {{ border-left: 4px solid #4CAF50; }}
        .test-item.fail {{ border-left: 4px solid #f44336; }}
        .test-name {{ font-weight: 500; }}
        .test-duration {{ color: #666; font-size: 14px; }}
        .status {{ 
            padding: 4px 12px;
            border-radius: 20px;
            font-size: 12px;
            font-weight: bold;
        }}
        .status.pass {{ background: #e8f5e9; color: #4CAF50; }}
        .status.fail {{ background: #ffebee; color: #f44336; }}
        
        .error {{ 
            background: #fff3e0;
            padding: 10px 15px;
            margin-top: 10px;
            border-radius: 5px;
            font-family: monospace;
            font-size: 13px;
            color: #e65100;
        }}
        
        .progress-bar {{
            height: 8px;
            background: #e0e0e0;
            border-radius: 4px;
            overflow: hidden;
            margin-top: 20px;
        }}
        .progress-bar .fill {{
            height: 100%;
            background: #4CAF50;
            transition: width 0.3s;
        }}
        
        .metadata {{ 
            background: white;
            padding: 20px;
            border-radius: 10px;
            margin-bottom: 20px;
        }}
        .metadata h3 {{ margin-bottom: 15px; }}
        .metadata table {{ width: 100%; }}
        .metadata td {{ padding: 8px 0; border-bottom: 1px solid #eee; }}
        .metadata td:first-child {{ color: #666; width: 200px; }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>{self.title}</h1>
            <div class="time">
                生成时间: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
            </div>
        </div>
        
        <div class="summary">
            <div class="summary-card total">
                <h3>总测试数</h3>
                <div class="value">{summary['total']}</div>
            </div>
            <div class="summary-card pass">
                <h3>通过</h3>
                <div class="value">{summary['passed']}</div>
            </div>
            <div class="summary-card fail">
                <h3>失败</h3>
                <div class="value">{summary['failed']}</div>
            </div>
            <div class="summary-card">
                <h3>通过率</h3>
                <div class="value">{summary['pass_rate']}</div>
            </div>
        </div>
        
        <div class="progress-bar">
            <div class="fill" style="width: {summary['pass_rate']}"></div>
        </div>
        
        {self._render_metadata()}
        
        <div class="tests">
            <h2 style="padding: 20px; background: #f9f9f9; border-bottom: 1px solid #eee;">
                测试结果
            </h2>
            {self._render_tests()}
        </div>
    </div>
</body>
</html>
        """
        
        Path(filepath).parent.mkdir(parents=True, exist_ok=True)
        Path(filepath).write_text(html, encoding='utf-8')
        
        logger.info(f"HTML报告已生成: {filepath}")
    
    def _render_tests(self) -> str:
        """渲染测试列表"""
        html = ""
        
        for test in self.tests:
            status = "pass" if test["passed"] else "fail"
            status_text = "PASS" if test["passed"] else "FAIL"
            
            html += f"""
            <div class="test-item {status}">
                <div>
                    <div class="test-name">{test['name']}</div>
                    <div class="test-duration">{test['duration']:.3f}s</div>
                    {'<div class="error">' + test['error'] + '</div>' if test.get('error') else ''}
                </div>
                <span class="status {status}">{status_text}</span>
            </div>
            """
        
        return html
    
    def _render_metadata(self) -> str:
        """渲染元数据"""
        if not self.metadata:
            return ""
        
        rows = ""
        for key, value in self.metadata.items():
            rows += f"<tr><td>{key}</td><td>{value}</td></tr>"
        
        return f"""
        <div class="metadata">
            <h3>环境信息</h3>
            <table>{rows}</table>
        </div>
        """


class PerformanceReport:
    """性能报告"""
    
    def __init__(self):
        self.metrics: List[Dict[str, Any]] = []
    
    def add_metric(
        self,
        name: str,
        value: float,
        unit: str = "ms",
        threshold: float = None,
    ):
        """添加性能指标"""
        self.metrics.append({
            "name": name,
            "value": value,
            "unit": unit,
            "threshold": threshold,
            "status": "pass" if threshold is None or value <= threshold else "fail",
        })
    
    def to_html(self, filepath: str):
        """生成HTML报告"""
        html = f"""
<!DOCTYPE html>
<html>
<head>
    <title>Performance Report</title>
    <style>
        body {{ font-family: Arial, sans-serif; padding: 20px; background: #f5f5f5; }}
        .container {{ max-width: 800px; margin: 0 auto; }}
        .metric {{ 
            background: white;
            padding: 15px 20px;
            margin-bottom: 10px;
            border-radius: 8px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }}
        .metric.pass {{ border-left: 4px solid #4CAF50; }}
        .metric.fail {{ border-left: 4px solid #f44336; }}
        .metric-name {{ font-weight: 500; }}
        .metric-value {{ font-size: 18px; font-weight: bold; }}
    </style>
</head>
<body>
    <div class="container">
        <h1>Performance Report</h1>
        <div class="metrics">
            {self._render_metrics()}
        </div>
    </div>
</body>
</html>
        """
        
        Path(filepath).parent.mkdir(parents=True, exist_ok=True)
        Path(filepath).write_text(html, encoding='utf-8')
    
    def _render_metrics(self) -> str:
        html = ""
        for m in self.metrics:
            html += f"""
            <div class="metric {m['status']}">
                <span class="metric-name">{m['name']}</span>
                <span class="metric-value">{m['value']:.2f} {m['unit']}</span>
            </div>
            """
        return html


class CoverageReport:
    """覆盖率报告"""
    
    def __init__(self):
        self.coverage: Dict[str, Dict[str, Any]] = {}
    
    def add_page(self, url: str, elements_total: int, elements_interacted: int):
        """添加页面覆盖率"""
        self.coverage[url] = {
            "total": elements_total,
            "interacted": elements_interacted,
            "coverage": elements_interacted / elements_total * 100 if elements_total > 0 else 0,
        }
    
    def overall_coverage(self) -> float:
        """总体覆盖率"""
        total = sum(p["total"] for p in self.coverage.values())
        interacted = sum(p["interacted"] for p in self.coverage.values())
        return interacted / total * 100 if total > 0 else 0
    
    def to_html(self, filepath: str):
        """生成HTML报告"""
        html = f"""
<!DOCTYPE html>
<html>
<head>
    <title>Coverage Report</title>
    <style>
        body {{ font-family: Arial, sans-serif; padding: 20px; }}
        .summary {{ background: #e3f2fd; padding: 20px; border-radius: 8px; margin-bottom: 20px; }}
        .page {{ background: white; padding: 15px; margin-bottom: 10px; border-radius: 8px; }}
        .progress {{ height: 20px; background: #e0e0e0; border-radius: 10px; overflow: hidden; }}
        .progress-fill {{ height: 100%; background: #4CAF50; }}
    </style>
</head>
<body>
    <h1>Coverage Report</h1>
    <div class="summary">
        <h2>总体覆盖率: {self.overall_coverage():.1f}%</h2>
    </div>
    {self._render_pages()}
</body>
</html>
        """
        
        Path(filepath).write_text(html, encoding='utf-8')
    
    def _render_pages(self) -> str:
        html = ""
        for url, data in self.coverage.items():
            html += f"""
            <div class="page">
                <h3>{url}</h3>
                <div class="progress">
                    <div class="progress-fill" style="width: {data['coverage']:.1f}%"></div>
                </div>
                <p>{data['interacted']}/{data['total']} elements ({data['coverage']:.1f}%)</p>
            </div>
            """
        return html
