#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：data_analyzer.py
模块描述：功能测试报告 - 数据分析模块，统计分析测试用例和BUG数据

移植自独立工具 FunctionalTestReportGeneration/src/data_analyzer.py，
import 改为相对导入。

作者：czj
创建日期：2026-08-12
最后修改：2026-08-12
"""

import re
from dataclasses import dataclass, field
from typing import Dict, List

from .config import (
    TEST_RESULT_PASS,
    TEST_RESULT_FAIL,
    TEST_RESULT_UNVERIFIED,
    TEST_RESULT_UNDEVELOPED,
    BUG_STATUS_ACTIVE,
    BUG_STATUS_RESOLVED,
    BUG_STATUS_CLOSED,
    REMAINING_BUG_STATUS,
    BUG_LEVEL_1,
    BUG_LEVEL_2,
    BUG_LEVEL_3,
    BUG_LEVEL_4,
    BUG_LEVEL_VALUES,
)
from .excel_reader import TestCase, Bug


@dataclass
class ModuleStat:
    """模块统计数据类"""
    module_name: str = ""
    total_cases: int = 0
    passed_cases: int = 0
    failed_cases: int = 0
    unverified_cases: int = 0
    undeveloped_cases: int = 0

    @property
    def pass_rate(self) -> float:
        """通过率（已执行用例中通过的占比）"""
        executed = self.passed_cases + self.failed_cases
        if executed == 0:
            return 0.0
        return round(self.passed_cases / executed * 100, 2)


@dataclass
class TestCaseAnalysis:
    """测试用例分析结果"""
    total_cases: int = 0
    executed_cases: int = 0
    passed_cases: int = 0
    failed_cases: int = 0
    unverified_cases: int = 0
    undeveloped_cases: int = 0

    @property
    def pass_rate(self) -> float:
        """通过率（已执行用例中通过的占比）"""
        if self.executed_cases == 0:
            return 0.0
        return round(self.passed_cases / self.executed_cases * 100, 2)

    @property
    def execution_rate(self) -> float:
        """执行率（已执行用例占总用例的占比）"""
        if self.total_cases == 0:
            return 0.0
        return round(self.executed_cases / self.total_cases * 100, 2)

    module_stats: Dict[str, ModuleStat] = field(default_factory=dict)


@dataclass
class BugAnalysis:
    """BUG分析结果"""
    total_bugs: int = 0
    remaining_bugs: int = 0
    closed_bugs: int = 0
    level_distribution: Dict[str, int] = field(default_factory=dict)
    status_distribution: Dict[str, int] = field(default_factory=dict)
    type_distribution: Dict[str, int] = field(default_factory=dict)
    module_distribution: Dict[str, int] = field(default_factory=dict)
    # 模块-等级分布 {模块名: {等级: 数量}}，用于按模块堆叠柱状图
    module_level_distribution: Dict[str, Dict[str, int]] = field(default_factory=dict)
    remaining_by_level: Dict[str, int] = field(default_factory=dict)


def analyze_test_cases(cases: List[TestCase]) -> TestCaseAnalysis:
    """
    分析测试用例数据

    Args:
        cases: 测试用例列表

    Returns:
        测试用例分析结果
    """
    analysis = TestCaseAnalysis()
    analysis.total_cases = len(cases)
    module_stats: Dict[str, ModuleStat] = {}

    for case in cases:
        result = case.test_result

        # 统计模块数据
        module_name = case.module if case.module else "未分类"
        if module_name not in module_stats:
            module_stats[module_name] = ModuleStat(module_name=module_name)
        module_stats[module_name].total_cases += 1

        if result == TEST_RESULT_PASS:
            analysis.passed_cases += 1
            analysis.executed_cases += 1
            module_stats[module_name].passed_cases += 1
        elif result == TEST_RESULT_FAIL:
            analysis.failed_cases += 1
            analysis.executed_cases += 1
            module_stats[module_name].failed_cases += 1
        elif result == TEST_RESULT_UNVERIFIED:
            analysis.unverified_cases += 1
            module_stats[module_name].unverified_cases += 1
        elif result == TEST_RESULT_UNDEVELOPED:
            analysis.undeveloped_cases += 1
            module_stats[module_name].undeveloped_cases += 1
        else:
            # 处理空值或无法识别的结果，视为未验证
            analysis.unverified_cases += 1
            module_stats[module_name].unverified_cases += 1

    analysis.module_stats = module_stats
    return analysis


def analyze_bugs(bugs: List[Bug]) -> BugAnalysis:
    """
    分析BUG数据

    Args:
        bugs: BUG列表

    Returns:
        BUG分析结果
    """
    analysis = BugAnalysis()
    analysis.total_bugs = len(bugs)

    # 初始化各等级分布
    for level in BUG_LEVEL_VALUES:
        analysis.level_distribution[level] = 0

    for bug in bugs:
        # 统计等级分布
        level = bug.bug_level
        if level in analysis.level_distribution:
            analysis.level_distribution[level] += 1
        else:
            analysis.level_distribution[level] = 1

        # 统计状态分布
        status = bug.bug_status
        analysis.status_distribution[status] = analysis.status_distribution.get(status, 0) + 1

        # 统计类型分布
        bug_type = bug.bug_type if bug.bug_type else "未分类"
        analysis.type_distribution[bug_type] = analysis.type_distribution.get(bug_type, 0) + 1

        # 统计模块分布（从BUG名称中提取模块名）
        module = _extract_module_from_bug_name(bug.bug_name)
        analysis.module_distribution[module] = analysis.module_distribution.get(module, 0) + 1

        # 统计模块-等级分布（用于按模块堆叠柱状图）
        if module not in analysis.module_level_distribution:
            analysis.module_level_distribution[module] = {}
        analysis.module_level_distribution[module][level] = \
            analysis.module_level_distribution[module].get(level, 0) + 1

    # 统计遗留BUG（激活+已解决）
    analysis.remaining_bugs = sum(
        1 for bug in bugs if bug.bug_status in REMAINING_BUG_STATUS
    )
    analysis.closed_bugs = sum(
        1 for bug in bugs if bug.bug_status == BUG_STATUS_CLOSED
    )

    # 统计各等级遗留BUG
    for level in BUG_LEVEL_VALUES:
        analysis.remaining_by_level[level] = sum(
            1 for bug in bugs
            if bug.bug_level == level and bug.bug_status in REMAINING_BUG_STATUS
        )

    return analysis


def _extract_module_from_bug_name(bug_name: str) -> str:
    """
    从BUG名称中提取模块名

    BUG名称格式: 【模块名-子模块】BUG描述 或 【模块名】BUG描述

    Args:
        bug_name: BUG名称

    Returns:
        模块名
    """
    if not bug_name:
        return "未分类"

    # 匹配 【模块名-子模块】 或 【模块名】
    pattern = r'【.*?-(.*?)】'
    match = re.search(pattern, bug_name)
    if match:
        return match.group(1).strip()

    # 尝试匹配简单的 【模块名】
    pattern2 = r'【(.+?)】'
    match = re.search(pattern2, bug_name)
    if match:
        return match.group(1).strip()

    return "未分类"


def group_by_module(cases: List[TestCase]) -> Dict[str, List[TestCase]]:
    """
    按模块分组

    Args:
        cases: 测试用例列表

    Returns:
        按模块名分组的字典
    """
    groups: Dict[str, List[TestCase]] = {}
    for case in cases:
        module = case.module if case.module else "未分类"
        if module not in groups:
            groups[module] = []
        groups[module].append(case)
    return groups


def link_bugs_to_cases(bugs: List[Bug], cases: List[TestCase]) -> Dict[str, List[Bug]]:
    """
    建立用例与BUG的关联关系

    从BUG的复现步骤中提取用例编号，建立关联。

    Args:
        bugs: BUG列表
        cases: 测试用例列表

    Returns:
        用例编号到BUG列表的映射字典
    """
    case_bug_map: Dict[str, List[Bug]] = {}

    for bug in bugs:
        # 从BUG的复现步骤中提取用例编号
        for case_number in bug.related_case_numbers:
            if case_number not in case_bug_map:
                case_bug_map[case_number] = []
            case_bug_map[case_number].append(bug)

    return case_bug_map


def get_failed_cases(cases: List[TestCase]) -> List[TestCase]:
    """
    获取失败的测试用例

    Args:
        cases: 测试用例列表

    Returns:
        失败的测试用例列表
    """
    return [c for c in cases if c.test_result == TEST_RESULT_FAIL]


def get_unexecuted_cases(cases: List[TestCase]) -> List[TestCase]:
    """
    获取未执行的测试用例

    Args:
        cases: 测试用例列表

    Returns:
        未执行的测试用例列表
    """
    return [c for c in cases if c.test_result in [TEST_RESULT_UNVERIFIED, TEST_RESULT_UNDEVELOPED]]


def get_remaining_bugs(bugs: List[Bug]) -> List[Bug]:
    """
    获取遗留BUG（未关闭的BUG）

    Args:
        bugs: BUG列表

    Returns:
        遗留BUG列表
    """
    return [b for b in bugs if b.bug_status in REMAINING_BUG_STATUS]


def calculate_pass_rate(passed: int, total: int) -> float:
    """
    计算通过率

    Args:
        passed: 通过数
        total: 总数

    Returns:
        通过率（百分比）
    """
    if total == 0:
        return 0.0
    return round(passed / total * 100, 2)


def get_test_result_summary(cases: List[TestCase]) -> Dict[str, int]:
    """
    获取测试结果汇总

    Args:
        cases: 测试用例列表

    Returns:
        测试结果汇总字典
    """
    summary = {
        TEST_RESULT_PASS: 0,
        TEST_RESULT_FAIL: 0,
        TEST_RESULT_UNVERIFIED: 0,
        TEST_RESULT_UNDEVELOPED: 0,
    }
    for case in cases:
        result = case.test_result
        if result in summary:
            summary[result] += 1
        else:
            # 无法识别的结果归为未验证
            summary[TEST_RESULT_UNVERIFIED] += 1
    return summary


def get_bug_summary(bugs: List[Bug]) -> Dict[str, int]:
    """
    获取BUG汇总

    Args:
        bugs: BUG列表

    Returns:
        BUG汇总字典
    """
    summary = {
        "total": len(bugs),
        "remaining": len(get_remaining_bugs(bugs)),
    }
    return summary