"""
测试报告生成脚本

生成完整的测试报告,包括:
- 测试执行摘要
- 覆盖率报告
- 性能测试结果
- 安全测试结果
- Bug清单
"""

import os
import json
import subprocess
from datetime import datetime
from pathlib import Path


class TestReportGenerator:
    """测试报告生成器"""

    def __init__(self, project_root: str):
        self.project_root = Path(project_root)
        self.report_dir = self.project_root / "test_reports"
        self.report_dir.mkdir(exist_ok=True)

        self.timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        self.report_data = {
            "timestamp": datetime.now().isoformat(),
            "project": "资产管理系统",
            "version": "1.0.0",
            "summary": {},
            "unit_tests": {},
            "integration_tests": {},
            "e2e_tests": {},
            "coverage": {},
            "performance": {},
            "security": {},
            "bugs": []
        }

    def run_unit_tests(self):
        """运行单元测试"""
        print("=" * 60)
        print("运行单元测试...")
        print("=" * 60)

        cmd = [
            "pytest",
            "-v",
            "-m", "unit",
            "--html=test_reports/unit_test_report.html",
            "--self-contained-html",
            "--json-report",
            "--json-report-file=test_reports/unit_test_results.json"
        ]

        result = subprocess.run(cmd, capture_output=True, text=True)

        # 解析结果
        if os.path.exists("test_reports/unit_test_results.json"):
            with open("test_reports/unit_test_results.json", "r") as f:
                data = json.load(f)
                self.report_data["unit_tests"] = {
                    "total": data.get("summary", {}).get("total", 0),
                    "passed": data.get("summary", {}).get("passed", 0),
                    "failed": data.get("summary", {}).get("failed", 0),
                    "skipped": data.get("summary", {}).get("skipped", 0),
                    "duration": data.get("summary", {}).get("duration", 0)
                }

        return result.returncode == 0

    def run_integration_tests(self):
        """运行集成测试"""
        print("\n" + "=" * 60)
        print("运行集成测试...")
        print("=" * 60)

        cmd = [
            "pytest",
            "-v",
            "-m", "integration",
            "--html=test_reports/integration_test_report.html",
            "--self-contained-html"
        ]

        result = subprocess.run(cmd, capture_output=True, text=True)
        return result.returncode == 0

    def run_coverage_tests(self):
        """运行覆盖率测试"""
        print("\n" + "=" * 60)
        print("生成覆盖率报告...")
        print("=" * 60)

        cmd = [
            "pytest",
            "--cov=app",
            "--cov-report=html:test_reports/htmlcov",
            "--cov-report=term-missing",
            "--cov-report=json:test_reports/coverage.json",
            "--cov-fail-under=70"
        ]

        result = subprocess.run(cmd, capture_output=True, text=True)

        # 解析覆盖率数据
        if os.path.exists("test_reports/coverage.json"):
            with open("test_reports/coverage.json", "r") as f:
                data = json.load(f)
                totals = data.get("totals", {})
                self.report_data["coverage"] = {
                    "line_coverage": totals.get("percent_covered", 0),
                    "lines_covered": totals.get("covered_lines", 0),
                    "lines_missing": totals.get("missing_lines", 0),
                    "num_statements": totals.get("num_statements", 0)
                }

        return result.returncode == 0

    def run_security_tests(self):
        """运行安全测试"""
        print("\n" + "=" * 60)
        print("运行安全测试...")
        print("=" * 60)

        cmd = [
            "pytest",
            "-v",
            "tests/security/",
            "-m", "security",
            "--html=test_reports/security_test_report.html"
        ]

        result = subprocess.run(cmd, capture_output=True, text=True)
        return result.returncode == 0

    def collect_bugs(self):
        """收集测试中发现的Bug"""
        print("\n" + "=" * 60)
        print("分析测试结果,收集Bug...")
        print("=" * 60)

        bugs = []

        # 从失败的测试中提取Bug
        test_results = [
            "test_reports/unit_test_results.json",
            "test_reports/integration_test_results.json"
        ]

        for result_file in test_results:
            if os.path.exists(result_file):
                with open(result_file, "r") as f:
                    data = json.load(f)

                for test in data.get("tests", []):
                    if test.get("outcome") == "failed":
                        bugs.append({
                            "test_name": test.get("name"),
                            "error": test.get("call", {}).get("crash", {}).get("message", ""),
                            "severity": "high" if "critical" in test.get("name", "").lower() else "medium",
                            "status": "open"
                        })

        self.report_data["bugs"] = bugs
        return bugs

    def generate_html_report(self):
        """生成HTML测试报告"""
        print("\n" + "=" * 60)
        print("生成HTML测试报告...")
        print("=" * 60)

        html_template = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>资产管理系统 - 测试报告</title>
    <style>
        * {{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }}

        body {{
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            background: #f5f5f5;
            padding: 20px;
            line-height: 1.6;
        }}

        .container {{
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }}

        h1 {{
            color: #333;
            border-bottom: 3px solid #FF6B35;
            padding-bottom: 10px;
            margin-bottom: 30px;
        }}

        h2 {{
            color: #FF6B35;
            margin-top: 30px;
            margin-bottom: 15px;
        }}

        .summary {{
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }}

        .metric {{
            padding: 20px;
            border-radius: 8px;
            text-align: center;
        }}

        .metric.success {{
            background: #d4edda;
            color: #155724;
        }}

        .metric.warning {{
            background: #fff3cd;
            color: #856404;
        }}

        .metric.danger {{
            background: #f8d7da;
            color: #721c24;
        }}

        .metric-value {{
            font-size: 32px;
            font-weight: bold;
            margin-bottom: 5px;
        }}

        .metric-label {{
            font-size: 14px;
            opacity: 0.8;
        }}

        .bug-list {{
            list-style: none;
        }}

        .bug-item {{
            padding: 15px;
            margin-bottom: 10px;
            border-left: 4px solid #dc3545;
            background: #f8f9fa;
            border-radius: 4px;
        }}

        .bug-item.high {{
            border-left-color: #dc3545;
        }}

        .bug-item.medium {{
            border-left-color: #ffc107;
        }}

        .bug-item.low {{
            border-left-color: #28a745;
        }}

        table {{
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
        }}

        th, td {{
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }}

        th {{
            background: #f8f9fa;
            font-weight: bold;
        }}

        .status-pass {{
            color: #28a745;
            font-weight: bold;
        }}

        .status-fail {{
            color: #dc3545;
            font-weight: bold;
        }}

        footer {{
            margin-top: 50px;
            padding-top: 20px;
            border-top: 1px solid #ddd;
            text-align: center;
            color: #666;
            font-size: 14px;
        }}
    </style>
</head>
<body>
    <div class="container">
        <h1>📊 资产管理系统 - 测试报告</h1>

        <div class="summary">
            <div class="metric success">
                <div class="metric-value">{total_tests}</div>
                <div class="metric-label">总测试数</div>
            </div>
            <div class="metric success">
                <div class="metric-value">{passed_tests}</div>
                <div class="metric-label">通过</div>
            </div>
            <div class="metric {failed_class}">
                <div class="metric-value">{failed_tests}</div>
                <div class="metric-label">失败</div>
            </div>
            <div class="metric {coverage_class}">
                <div class="metric-value">{coverage}%</div>
                <div class="metric-label">代码覆盖率</div>
            </div>
        </div>

        <h2>📋 测试摘要</h2>
        <table>
            <tr>
                <th>测试类型</th>
                <th>总数</th>
                <th>通过</th>
                <th>失败</th>
                <th>通过率</th>
            </tr>
            <tr>
                <td>单元测试</td>
                <td>{unit_total}</td>
                <td>{unit_passed}</td>
                <td>{unit_failed}</td>
                <td>{unit_pass_rate}%</td>
            </tr>
            <tr>
                <td>集成测试</td>
                <td>{integration_total}</td>
                <td>{integration_passed}</td>
                <td>{integration_failed}</td>
                <td>{integration_pass_rate}%</td>
            </tr>
            <tr>
                <td>E2E测试</td>
                <td>{e2e_total}</td>
                <td>{e2e_passed}</td>
                <td>{e2e_failed}</td>
                <td>{e2e_pass_rate}%</td>
            </tr>
        </table>

        <h2>🐛 Bug清单 ({bug_count})</h2>
        <ul class="bug-list">
            {bug_items}
        </ul>

        <footer>
            <p>生成时间: {timestamp}</p>
            <p>资产管理系统 v{version} | 测试框架: Pytest + Vitest + Playwright</p>
        </footer>
    </div>
</body>
</html>
        """

        # 计算统计数据
        total_tests = (
            self.report_data["unit_tests"].get("total", 0) +
            self.report_data["integration_tests"].get("total", 0) +
            self.report_data["e2e_tests"].get("total", 0)
        )

        passed_tests = (
            self.report_data["unit_tests"].get("passed", 0) +
            self.report_data["integration_tests"].get("passed", 0) +
            self.report_data["e2e_tests"].get("passed", 0)
        )

        failed_tests = (
            self.report_data["unit_tests"].get("failed", 0) +
            self.report_data["integration_tests"].get("failed", 0) +
            self.report_data["e2e_tests"].get("failed", 0)
        )

        coverage = self.report_data["coverage"].get("line_coverage", 0)

        # 生成Bug列表HTML
        bug_items = ""
        for bug in self.report_data.get("bugs", []):
            bug_items += f"""
            <li class="bug-item {bug.get('severity', 'medium')}">
                <strong>{bug.get('test_name', '')}</strong><br>
                <small>{bug.get('error', '')}</small>
            </li>
            """

        html = html_template.format(
            total_tests=total_tests,
            passed_tests=passed_tests,
            failed_tests=failed_tests,
            coverage=int(coverage),
            failed_class="success" if failed_tests == 0 else "danger",
            coverage_class="success" if coverage >= 70 else "warning" if coverage >= 50 else "danger",
            unit_total=self.report_data["unit_tests"].get("total", 0),
            unit_passed=self.report_data["unit_tests"].get("passed", 0),
            unit_failed=self.report_data["unit_tests"].get("failed", 0),
            unit_pass_rate=0,
            integration_total=self.report_data["integration_tests"].get("total", 0),
            integration_passed=self.report_data["integration_tests"].get("passed", 0),
            integration_failed=self.report_data["integration_tests"].get("failed", 0),
            integration_pass_rate=0,
            e2e_total=self.report_data["e2e_tests"].get("total", 0),
            e2e_passed=self.report_data["e2e_tests"].get("passed", 0),
            e2e_failed=self.report_data["e2e_tests"].get("failed", 0),
            e2e_pass_rate=0,
            bug_count=len(self.report_data.get("bugs", [])),
            bug_items=bug_items if bug_items else "<li>暂无Bug</li>",
            timestamp=self.report_data["timestamp"],
            version=self.report_data["version"]
        )

        report_path = self.report_dir / f"test_report_{self.timestamp}.html"
        with open(report_path, "w", encoding="utf-8") as f:
            f.write(html)

        print(f"✓ HTML报告已生成: {report_path}")
        return report_path

    def generate_json_report(self):
        """生成JSON测试报告"""
        json_path = self.report_dir / f"test_report_{self.timestamp}.json"

        with open(json_path, "w", encoding="utf-8") as f:
            json.dump(self.report_data, f, ensure_ascii=False, indent=2)

        print(f"✓ JSON报告已生成: {json_path}")
        return json_path

    def generate_all_reports(self):
        """生成所有报告"""
        print("\n" + "=" * 60)
        print("🚀 开始生成测试报告...")
        print("=" * 60)

        # 运行各类测试
        self.run_unit_tests()
        self.run_integration_tests()
        self.run_coverage_tests()
        self.run_security_tests()

        # 收集Bug
        self.collect_bugs()

        # 生成报告
        html_report = self.generate_html_report()
        json_report = self.generate_json_report()

        print("\n" + "=" * 60)
        print("✅ 测试报告生成完成!")
        print("=" * 60)
        print(f"\n📄 HTML报告: {html_report}")
        print(f"📄 JSON报告: {json_report}")
        print(f"📄 覆盖率报告: {self.report_dir}/htmlcov/index.html")
        print(f"📄 单元测试报告: {self.report_dir}/unit_test_report.html")
        print(f"📄 集成测试报告: {self.report_dir}/integration_test_report.html")
        print(f"📄 安全测试报告: {self.report_dir}/security_test_report.html")
        print("\n" + "=" * 60)


if __name__ == "__main__":
    import sys

    # 项目根目录
    project_root = sys.argv[1] if len(sys.argv) > 1 else "."

    # 生成测试报告
    generator = TestReportGenerator(project_root)
    generator.generate_all_reports()
