"""根级 conftest — 全局 fixture：配置加载、日志、中文 HTML 报告生成。

Usage:
    def test_xxx(admin_config):    # 管理端配置
    def test_xxx(driver_android_config):  # 司机安卓配置
"""

from pathlib import Path
import sys

import pytest

sys.path.insert(0, str(Path(__file__).parent.parent))


@pytest.fixture(scope="session")
def config():
    """全局配置（session 级，只加载一次）。"""
    from tests.config.test_config import load_config
    return load_config()


@pytest.fixture(scope="function")
def logger(request):
    """每个测试函数的 logger。"""
    from tests.utils.logger import get_logger
    module_name = request.module.__name__.replace("tests.", "")
    return get_logger(module_name)


# ═══════════════════════════════════════════════════════════════════
# 各端配置 fixture（从 config 中摘取对应 section）
# ═══════════════════════════════════════════════════════════════════

@pytest.fixture(scope="session")
def admin_config(config):
    """管理端 (Playwright) 配置。"""
    return config["admin"]


@pytest.fixture(scope="session")
def mini_program_config(config):
    """司机端小程序 (Playwright) 配置。"""
    return config["mini_program"]


@pytest.fixture(scope="session")
def driver_android_config(config):
    """司机安卓端 (Appium) 配置。"""
    return config["driver_android"]


@pytest.fixture(scope="session")
def shipper_android_config(config):
    """货主安卓端 (Appium) 配置。"""
    return config["shipper_android"]


@pytest.fixture(scope="session")
def driver_ios_config(config):
    """司机苹果端 (Appium) 配置。"""
    return config["driver_ios"]


@pytest.fixture(scope="session")
def shipper_ios_config(config):
    """货主苹果端 (Appium) 配置。"""
    return config["shipper_ios"]


# ═══════════════════════════════════════════════════════════════════
# 中文 HTML 报告生成 (pytest_sessionfinish hook)
# ═══════════════════════════════════════════════════════════════════

def pytest_sessionfinish(session):
    """测试会话结束后，生成中文 HTML 报告。"""
    from datetime import datetime
    from xml.etree import ElementTree as ET

    report_dir = Path("output/reports")
    report_dir.mkdir(parents=True, exist_ok=True)

    junit_path = report_dir / "junit.xml"
    if not junit_path.exists():
        return

    try:
        tree = ET.parse(junit_path)
        root = tree.getroot()
    except Exception:
        return

    total = 0
    passed = 0
    failed = 0
    skipped = 0
    cases = []

    for suite in root:
        for case in suite:
            total += 1
            func_name = case.attrib.get("name", "")
            cn_name = _resolve_cn_name(session, func_name)
            time_elapsed = case.attrib.get("time", "0")
            failure = case.find("failure")
            if failure is not None:
                failed += 1
                msg = failure.attrib.get("message", "")[:300]
                cases.append((cn_name, "失败", time_elapsed, msg))
            elif case.find("skipped") is not None:
                skipped += 1
                cases.append((cn_name, "跳过", time_elapsed, ""))
            else:
                passed += 1
                cases.append((cn_name, "通过", time_elapsed, ""))

    pass_rate = (passed / total * 100) if total > 0 else 0
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    html = _build_cn_report_html(total, passed, failed, skipped, pass_rate, cases, now)
    (report_dir / "report_cn.html").write_text(html, encoding="utf-8-sig")


def _resolve_cn_name(session, func_name: str) -> str:
    """从用例元信息中提取中文名称。

    优先级:
      1) 用例 docstring 中显式声明的 "用例名称: xxx"
      2) display_name 属性
      3) docstring 第一行去 【P0】 前缀

    用例 docstring 格式示例:
        用例ID: TC-D2S-001
        用例名称: 司机APP接单到管理端核算打款完整流程
        优先级: P0
    """
    for item in session.items:
        item_func_name = getattr(item, "originalname", None) or item.name.rsplit("::", 1)[-1]
        if item_func_name == func_name:
            test_cls = item.cls if hasattr(item, "cls") else None
            test_func = getattr(test_cls, item_func_name, None) if test_cls else None
            doc = (test_func.__doc__ or "") if test_func else ""

            # 策略1: 从 docstring 中提取 "用例名称: xxx"
            import re
            m = re.search(r"用例名称[:：]\s*(.+)", doc)
            if m:
                return m.group(1).strip()

            # 策略2: display_name 属性
            if test_func and hasattr(test_func, "display_name"):
                return test_func.display_name

            # 策略3: docstring 第一行去 【P0】 前缀
            if doc:
                first_line = doc.strip().split("\n")[0].strip()
                if first_line.startswith("【"):
                    idx = first_line.find("】")
                    if idx > 0:
                        first_line = first_line[idx + 1:]
                if first_line and len(first_line) > 2:
                    return first_line
            break
    return func_name

    pass_rate = (passed / total * 100) if total > 0 else 0
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    html = _build_cn_report_html(total, passed, failed, skipped, pass_rate, cases, now)
    (report_dir / "report_cn.html").write_text(html, encoding="utf-8-sig")


def _build_cn_report_html(total, passed, failed, skipped, rate, cases, now):
    """拼装中文 HTML 报告字符串。"""
    rows = ""
    for i, (name, status, elapsed, msg) in enumerate(cases, 1):
        cls = {"通过": "s-pass", "失败": "s-fail", "跳过": "s-skip"}.get(status, "")
        msg_html = f'<span class="msg">{msg}</span>' if msg else "-"
        rows += f"<tr><td>{i}</td><td>{name}</td><td class=\"{cls}\">{status}</td>"
        rows += f"<td>{float(elapsed):.1f}</td><td>{msg_html}</td></tr>"

    return f"""<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>自动化测试报告 - {now}</title>
<style>
*{{margin:0;padding:0;box-sizing:border-box}}
body{{font-family:'Microsoft YaHei','PingFang SC',sans-serif;background:#f5f7fa;color:#333}}
.header{{background:linear-gradient(135deg,#409eff,#337ecc);color:#fff;padding:24px 32px}}
.header h1{{font-size:22px;font-weight:500}}
.header .time{{font-size:13px;opacity:.75;margin-top:6px}}
.summary{{display:flex;gap:20px;padding:24px 32px;background:#fff;border-bottom:1px solid #e4e7ed}}
.card{{flex:1;text-align:center;padding:16px;border-radius:8px}}
.card .num{{font-size:36px;font-weight:600}}
.card .label{{font-size:14px;color:#909399;margin-top:4px}}
.card.total{{background:#f0f5ff}}.card.total .num{{color:#409eff}}
.card.pass{{background:#f0f9eb}}.card.pass .num{{color:#67c23a}}
.card.fail{{background:#fef0f0}}.card.fail .num{{color:#f56c6c}}
.card.skip{{background:#fdf6ec}}.card.skip .num{{color:#e6a23c}}
.rate{{text-align:center;padding:8px 32px;font-size:16px;color:#67c23a}}
.tbl{{margin:20px 32px;background:#fff;border-radius:8px;box-shadow:0 1px 4px rgba(0,0,0,.06);overflow:hidden}}
table{{width:100%;border-collapse:collapse}}
th{{background:#f5f7fa;text-align:left;padding:12px 16px;font-size:13px;color:#909399;border-bottom:1px solid #ebeef5}}
td{{padding:12px 16px;font-size:14px;border-bottom:1px solid #ebeef5}}
tr:hover td{{background:#f5f7fa}}
.s-pass{{color:#67c23a;font-weight:500}}
.s-fail{{color:#f56c6c;font-weight:500}}
.s-skip{{color:#e6a23c;font-weight:500}}
.msg{{font-size:12px;color:#909399;max-width:400px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block}}
.ft{{text-align:center;padding:20px;font-size:12px;color:#c0c4cc}}
</style>
</head>
<body>
<div class="header">
<h1>自动化测试报告</h1>
<div class="time">执行时间: {now} | 运八网络货运平台 QaAutomationHub</div>
</div>
<div class="summary">
<div class="card total"><div class="num">{total}</div><div class="label">总计</div></div>
<div class="card pass"><div class="num">{passed}</div><div class="label">通过</div></div>
<div class="card fail"><div class="num">{failed}</div><div class="label">失败</div></div>
<div class="card skip"><div class="num">{skipped}</div><div class="label">跳过</div></div>
</div>
<div class="rate">通过率: {rate:.1f}% ({passed}/{total})</div>
<div class="tbl"><table>
<thead><tr><th>#</th><th>用例名称</th><th>状态</th><th>耗时(s)</th><th>备注</th></tr></thead>
<tbody>{rows}</tbody>
</table></div>
<div class="ft">报告自动生成于 {now}</div>
</body></html>"""
