#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：word_generator.py
模块描述：功能测试报告 - Word文档生成模块，生成10章节功能测试报告

移植自独立工具 FunctionalTestReportGeneration/src/word_generator.py，
去除 REPORTS_DIR/TEMPLATE_FILE 依赖（输出路径由调用方传入），
修复"未执行用例数量"统计 bug（unverified+undeveloped），import 改为相对导入。

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

from pathlib import Path
from typing import Dict, List, Any, Optional
from datetime import datetime
import re

try:
    from docx import Document
    from docx.shared import Inches, Pt, RGBColor
    from docx.enum.text import WD_ALIGN_PARAGRAPH
    from docx.oxml.ns import qn
except ImportError:
    print("警告: 未安装python-docx库，请运行: pip install python-docx")
    raise

from .data_analyzer import TestCaseAnalysis, BugAnalysis, ModuleStat
from .excel_reader import TestCase, Bug
from .data_extractor import (
    extract_testers,
    extract_test_lead,
    extract_server_info,
    extract_version_info_from_bug_list,
    extract_deployment_env,
)
from .config import (
    WORD_FONT_NAME,
    WORD_FONT_SIZE,
    WORD_TITLE_LEVEL_1_SIZE,
    WORD_TITLE_LEVEL_2_SIZE,
    WORD_TITLE_LEVEL_3_SIZE,
    WORD_TITLE_LEVEL_4_SIZE,
    WORD_PARAGRAPH_FIRST_LINE_INDENT,
    DATE_FORMAT,
    get_report_number,
    get_default_config,
    merge_template_config,
    # 测试结果枚举
    TEST_RESULT_PASS,
    TEST_RESULT_FAIL,
    TEST_RESULT_UNVERIFIED,
    TEST_RESULT_UNDEVELOPED,
    # BUG等级枚举
    BUG_LEVEL_1,
    BUG_LEVEL_2,
    BUG_LEVEL_3,
    BUG_LEVEL_4,
    # BUG状态枚举
    BUG_STATUS_ACTIVE,
    BUG_STATUS_RESOLVED,
    BUG_STATUS_CLOSED,
    REMAINING_BUG_STATUS,
    # BUG等级描述
    BUG_LEVEL_DESCRIPTION,
    # 自动填充默认值
    DEFAULT_TEST_LEAD,
    DEFAULT_TESTER,
    DEFAULT_TEST_ENV,
    DEFAULT_SYSTEM_VERSION,
    DEFAULT_SERVER_ADDRESS,
    DEFAULT_DEPLOYMENT_ENV,
)


_ZH_NUM_MAP = {1: "一", 2: "二", 3: "三", 4: "四", 5: "五", 6: "六", 7: "七", 8: "八", 9: "九", 10: "十"}


def _zh_num(n: int) -> str:
    """整数转中文数字（1-10），超出返回阿拉伯数字"""
    return _ZH_NUM_MAP.get(n, str(n))


def _set_cell_border(cell):
    """
    设置单元格边框

    Args:
        cell: 单元格对象
    """
    from docx.oxml import OxmlElement
    from docx.oxml.ns import qn

    tcPr = cell._element.get_or_add_tcPr()
    tcBorders = OxmlElement('w:tcBorders')

    for border_name in ['top', 'left', 'bottom', 'right']:
        border = OxmlElement(f'w:{border_name}')
        border.set(qn('w:val'), 'single')
        border.set(qn('w:sz'), '4')
        border.set(qn('w:color'), '000000')
        tcBorders.append(border)

    tcPr.append(tcBorders)


def _create_table_with_data(doc, headers: List[str], rows: List[List[str]]) -> None:
    """
    创建表格并填充数据

    Args:
        doc: Word文档对象
        headers: 表头列表
        rows: 数据行列表
    """
    if not rows:
        return

    # 创建表格
    table = doc.add_table(rows=1 + len(rows), cols=len(headers))
    table.style = 'Table Grid'  # 使用简单的网格样式（黑色边框）

    # 设置表头
    header_cells = table.rows[0].cells
    for i, header in enumerate(headers):
        header_cells[i].text = header
        # 设置表头样式：居中对齐、加粗、黑色
        for paragraph in header_cells[i].paragraphs:
            paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER  # 表头居中对齐
            for run in paragraph.runs:
                run.font.bold = True
                run.font.size = Pt(WORD_FONT_SIZE)
                run.font.name = WORD_FONT_NAME
                run.font.color.rgb = RGBColor(0, 0, 0)  # 黑色
                run._element.rPr.rFonts.set(qn('w:eastAsia'), WORD_FONT_NAME)
        # 设置表头单元格边框为黑色
        _set_cell_border(header_cells[i])

    # 填充数据行
    for i, row_data in enumerate(rows):
        row_cells = table.rows[i + 1].cells
        for j, cell_data in enumerate(row_data):
            cell_text = str(cell_data) if cell_data is not None else ""
            row_cells[j].text = cell_text
            # 设置单元格样式：居中对齐、黑色
            for paragraph in row_cells[j].paragraphs:
                paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER  # 表格内容居中对齐
                for run in paragraph.runs:
                    run.font.size = Pt(WORD_FONT_SIZE)
                    run.font.name = WORD_FONT_NAME
                    run.font.color.rgb = RGBColor(0, 0, 0)  # 黑色
                    run._element.rPr.rFonts.set(qn('w:eastAsia'), WORD_FONT_NAME)
            # 设置单元格边框为黑色
            _set_cell_border(row_cells[j])


def _add_title(doc, title: str, level: int = 1) -> None:
    """
    添加标题

    Args:
        doc: Word文档对象
        title: 标题文本
        level: 标题级别（1-4）
    """
    heading = doc.add_heading(title, level=level)

    # 根据标题级别设置字号
    font_sizes = {
        1: WORD_TITLE_LEVEL_1_SIZE,
        2: WORD_TITLE_LEVEL_2_SIZE,
        3: WORD_TITLE_LEVEL_3_SIZE,
        4: WORD_TITLE_LEVEL_4_SIZE
    }

    font_size = font_sizes.get(level, WORD_TITLE_LEVEL_1_SIZE)

    for run in heading.runs:
        run.font.size = Pt(font_size)
        run.font.name = WORD_FONT_NAME
        run.font.bold = True
        run.font.color.rgb = RGBColor(0, 0, 0)  # 黑色
        run._element.rPr.rFonts.set(qn('w:eastAsia'), WORD_FONT_NAME)

    # 设置左对齐
    heading.alignment = WD_ALIGN_PARAGRAPH.LEFT


def _add_paragraph(doc, text: str, bold: bool = False) -> None:
    """
    添加段落

    Args:
        doc: Word文档对象
        text: 段落文本
        bold: 是否加粗
    """
    from docx.shared import Twips

    paragraph = doc.add_paragraph(text)

    # 设置段落格式：首行缩进两字符（1字符约240缇）
    paragraph.paragraph_format.first_line_indent = Twips(WORD_PARAGRAPH_FIRST_LINE_INDENT * 240)

    for run in paragraph.runs:
        run.font.size = Pt(WORD_FONT_SIZE)
        run.font.name = WORD_FONT_NAME
        run.font.color.rgb = RGBColor(0, 0, 0)  # 黑色
        run._element.rPr.rFonts.set(qn('w:eastAsia'), WORD_FONT_NAME)
        run.font.bold = bold


def _add_image(doc, image_path: str, width: float = 6.0) -> None:
    """
    添加图片

    Args:
        doc: Word文档对象
        image_path: 图片文件路径
        width: 图片宽度（英寸）
    """
    if Path(image_path).exists():
        doc.add_picture(image_path, width=Inches(width))
        # 设置图片居中
        last_paragraph = doc.paragraphs[-1]
        last_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
    else:
        doc.add_paragraph(f"[图片文件不存在: {image_path}]")


def generate_report(
    template_path: str,
    case_analysis: TestCaseAnalysis,
    bug_analysis: BugAnalysis,
    case_bug_link: Dict[str, List[Bug]],
    chart_paths: Dict[str, str],
    output_path: str,
    project_name: str,
    cases: List[TestCase],
    bugs: List[Bug],
    template_config: Optional[Dict] = None,
) -> str:
    """
    生成功能测试报告

    Args:
        template_path: 模板文件路径（暂未使用，使用固定格式生成）
        case_analysis: 用例分析结果
        bug_analysis: BUG分析结果
        case_bug_link: 用例-BUG关联
        chart_paths: 图表文件路径字典
        output_path: 输出文件路径
        project_name: 项目名称
        cases: 测试用例列表
        bugs: BUG列表
        template_config: 模板配置字典（可选，提供则覆盖硬编码默认值）

    Returns:
        生成的报告文件路径
    """
    # 合并模板配置
    cfg = merge_template_config(get_default_config(), template_config)
    ws = cfg["word_style"]
    chapters = cfg["chapters"]
    defaults = cfg["defaults"]

    # 局部别名：方便读取配置
    _font_name = ws.get("font_name", WORD_FONT_NAME)
    _font_size = ws.get("font_size", WORD_FONT_SIZE)
    _title_sizes = {
        1: ws.get("title_level_1_size", WORD_TITLE_LEVEL_1_SIZE),
        2: ws.get("title_level_2_size", WORD_TITLE_LEVEL_2_SIZE),
        3: ws.get("title_level_3_size", WORD_TITLE_LEVEL_3_SIZE),
        4: ws.get("title_level_4_size", WORD_TITLE_LEVEL_4_SIZE),
    }
    _title_color = ws.get("title_color", "#000000")
    _first_line_indent = ws.get("paragraph_first_line_indent", WORD_PARAGRAPH_FIRST_LINE_INDENT)
    _test_lead = defaults.get("test_lead", DEFAULT_TEST_LEAD)
    _tester = defaults.get("tester", DEFAULT_TESTER)
    _test_env = defaults.get("test_env", DEFAULT_TEST_ENV)
    _system_version = defaults.get("system_version", DEFAULT_SYSTEM_VERSION)
    _server_address = defaults.get("server_address", DEFAULT_SERVER_ADDRESS)
    _deployment_env = defaults.get("deployment_env", DEFAULT_DEPLOYMENT_ENV)

    # 创建Word文档
    doc = Document()

    # 设置文档默认字体
    doc.styles['Normal'].font.name = _font_name
    doc.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), _font_name)
    doc.styles['Normal'].font.size = Pt(_font_size)

    # 获取当前日期
    current_date = datetime.now().strftime(DATE_FORMAT)
    report_number = get_report_number(project_name, current_date)

    # ==================== 报告标题 ====================
    _add_title(doc, f"{project_name}功能测试报告", level=1)

    # 章节计数器（动态编号，仅对启用章节自增）
    ch_idx = 0

    # ==================== 一、报告基本信息 ====================
    def _add_title_local(title, level=1):
        """内部标题函数，使用模板配置的样式"""
        heading = doc.add_heading(title, level=level)
        font_size = _title_sizes.get(level, _title_sizes[1])
        # 解析颜色
        color_hex = _title_color.lstrip("#")
        if len(color_hex) == 6:
            r, g, b = int(color_hex[0:2], 16), int(color_hex[2:4], 16), int(color_hex[4:6], 16)
            rgb_color = RGBColor(r, g, b)
        else:
            rgb_color = RGBColor(0, 0, 0)
        for run in heading.runs:
            run.font.size = Pt(font_size)
            run.font.name = _font_name
            run.font.bold = True
            run.font.color.rgb = rgb_color
            run._element.rPr.rFonts.set(qn('w:eastAsia'), _font_name)
        heading.alignment = WD_ALIGN_PARAGRAPH.LEFT

    def _add_paragraph_local(text, bold=False):
        """内部段落函数，使用模板配置的样式"""
        from docx.shared import Twips
        paragraph = doc.add_paragraph(text)
        paragraph.paragraph_format.first_line_indent = Twips(_first_line_indent * 240)
        for run in paragraph.runs:
            run.font.size = Pt(_font_size)
            run.font.name = _font_name
            run.font.color.rgb = RGBColor(0, 0, 0)
            run._element.rPr.rFonts.set(qn('w:eastAsia'), _font_name)
            run.font.bold = bold

    def _create_table_local(headers, rows):
        """内部表格函数，使用模板配置的样式"""
        if not rows:
            return
        table = doc.add_table(rows=1 + len(rows), cols=len(headers))
        table.style = 'Table Grid'
        header_cells = table.rows[0].cells
        for i, header in enumerate(headers):
            header_cells[i].text = header
            for paragraph in header_cells[i].paragraphs:
                paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
                for run in paragraph.runs:
                    run.font.bold = True
                    run.font.size = Pt(_font_size)
                    run.font.name = _font_name
                    run.font.color.rgb = RGBColor(0, 0, 0)
                    run._element.rPr.rFonts.set(qn('w:eastAsia'), _font_name)
            _set_cell_border(header_cells[i])
        for i, row_data in enumerate(rows):
            row_cells = table.rows[i + 1].cells
            for j, cell_data in enumerate(row_data):
                cell_text = str(cell_data) if cell_data is not None else ""
                row_cells[j].text = cell_text
                for paragraph in row_cells[j].paragraphs:
                    paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
                    for run in paragraph.runs:
                        run.font.size = Pt(_font_size)
                        run.font.name = _font_name
                        run.font.color.rgb = RGBColor(0, 0, 0)
                        run._element.rPr.rFonts.set(qn('w:eastAsia'), _font_name)
                _set_cell_border(row_cells[j])
    # ==================== 一、报告基本信息 ====================
    if chapters.get("report_basic_info", True):
        ch_idx += 1
        _add_title_local(f"{_zh_num(ch_idx)}、报告基本信息", level=2)
        _add_title_local(f"{ch_idx}.1 报告标识", level=3)

        headers = ["项目", "内容"]
        rows = [
            ["报告编号", report_number],
            ["报告标题", f"{project_name}功能测试报告"],
            ["报告版本", "v1.0"],
            ["生成日期", current_date],
            ["报告状态", "已生成"],
        ]
        _create_table_local(headers, rows)

        _add_title_local(f"{ch_idx}.2 测试概览", level=3)
        headers = ["项目", "内容"]
        rows = [
            ["项目名称", project_name],
            ["测试负责人", extract_test_lead(bugs) if bugs else _test_lead],
            ["测试人员", extract_testers(bugs) if bugs else _tester],
            ["测试环境", extract_server_info(cases) if cases else _test_env],
            ["测试类型", "功能测试"],
        ]
        _create_table_local(headers, rows)

        _add_title_local(f"{ch_idx}.3 被测系统信息", level=3)
        headers = ["项目", "内容"]
        # 提取自动填充数据
        system_version = extract_version_info_from_bug_list(bugs) if bugs else _system_version
        server_address = extract_server_info(cases) if cases else _server_address
        deployment_env = extract_deployment_env(cases) if cases else _deployment_env

        # 处理多行版本信息，在Word表格中需要特殊处理
        # 如果版本信息包含换行符，需要分段显示
        if "\n" in system_version:
            # 将多行版本信息合并为一行显示（用空格分隔）
            system_version_display = " ".join(system_version.split("\n"))
        else:
            system_version_display = system_version

        rows = [
            ["系统名称", project_name],
            ["系统版本", system_version_display],
            ["服务器地址", server_address],
            ["部署环境", deployment_env],
        ]
        _create_table_local(headers, rows)

    # ==================== 二、测试执行摘要 ====================
    if chapters.get("execution_summary", True):
        ch_idx += 1
        _add_title_local(f"{_zh_num(ch_idx)}、测试执行摘要", level=2)

        _add_title_local(f"{ch_idx}.1 测试结果统计", level=3)
        total = case_analysis.total_cases
        headers = ["统计项", "数量", "占比"]
        unexecuted = case_analysis.unverified_cases + case_analysis.undeveloped_cases
        rows = [
            ["测试用例总数", str(total), "100%"],
            ["执行用例数量", str(case_analysis.executed_cases), f"{case_analysis.execution_rate}%"],
            ["通过用例数量", str(case_analysis.passed_cases), f"{case_analysis.pass_rate}%"],
            ["失败用例数量", str(case_analysis.failed_cases), f"{round(case_analysis.failed_cases / total * 100, 2)}%" if total > 0 else "0%"],
            ["未执行用例数量", str(unexecuted),
             f"{round(unexecuted / total * 100, 2)}%" if total > 0 else "0%"],
        ]
        _create_table_local(headers, rows)

        _add_title_local(f"{ch_idx}.2 BUG统计汇总", level=3)
        total_bugs = bug_analysis.total_bugs
        headers = ["BUG等级", "数量", "占比", "已关闭", "未关闭"]
        rows = []
        for level in [BUG_LEVEL_1, BUG_LEVEL_2, BUG_LEVEL_3, BUG_LEVEL_4]:
            count = bug_analysis.level_distribution.get(level, 0)
            percentage = round(count / total_bugs * 100, 2) if total_bugs > 0 else 0
            # 计算该等级的未关闭数量
            remaining = sum(
                1 for bug in bugs
                if bug.bug_level == level and bug.bug_status in REMAINING_BUG_STATUS
            )
            closed = count - remaining
            rows.append([
                f"{BUG_LEVEL_DESCRIPTION[level]}({level})",
                str(count),
                f"{percentage}%",
                str(closed),
                str(remaining)
            ])
        _create_table_local(headers, rows)

        _add_title_local(f"{ch_idx}.3 测试结论", level=3)
        if bug_analysis.remaining_bugs == 0 and case_analysis.failed_cases == 0:
            conclusion = "✓ 测试通过 - 系统功能正常，无致命/严重缺陷，可以发布"
        elif case_analysis.failed_cases > 0:
            conclusion = "✗ 测试不通过 - 存在失败的测试用例，不建议发布"
        elif bug_analysis.remaining_bugs > 0:
            critical = bug_analysis.remaining_by_level.get(BUG_LEVEL_1, 0) + \
                       bug_analysis.remaining_by_level.get(BUG_LEVEL_2, 0)
            if critical > 0:
                conclusion = "✗ 测试不通过 - 存在阻塞性缺陷，不建议发布"
            else:
                conclusion = "⚠ 有条件通过 - 存在非阻塞性缺陷，经评估可以发布"
        else:
            conclusion = "待评估"
        _add_paragraph_local(conclusion)

    # ==================== 三、测试范围 ====================
    if chapters.get("test_scope", True):
        ch_idx += 1
        _add_title_local(f"{_zh_num(ch_idx)}、测试范围", level=2)

        _add_title_local(f"{ch_idx}.1 测试模块覆盖", level=3)
        headers = ["序号", "功能模块", "用例数量", "通过", "失败", "未执行", "覆盖率"]
        module_rows = []
        for i, (module_name, stat) in enumerate(case_analysis.module_stats.items(), 1):
            module_rows.append([
                str(i),
                module_name,
                str(stat.total_cases),
                str(stat.passed_cases),
                str(stat.failed_cases),
                str(stat.unverified_cases + stat.undeveloped_cases),
                f"{stat.pass_rate}%"
            ])
        _create_table_local(headers, module_rows)

    # ==================== 四、测试用例执行详情 ====================
    if chapters.get("case_details", True):
        ch_idx += 1
        _add_title_local(f"{_zh_num(ch_idx)}、测试用例执行详情", level=2)

        # 通过用例列表
        _add_title_local(f"{ch_idx}.1 通过用例列表", level=3)
        passed_cases = [c for c in cases if c.test_result == TEST_RESULT_PASS]
        if passed_cases:
            headers = ["序号", "用例编号", "功能模块", "用例名称", "用例等级", "测试结果"]
            rows = []
            for i, case in enumerate(passed_cases[:20], 1):  # 限制显示20条
                rows.append([
                    str(i),
                    case.case_number,
                    case.module,
                    case.name[:50],  # 限制长度
                    str(case.level),
                    case.test_result
                ])
            if len(passed_cases) > 20:
                rows.append(["...", f"等{len(passed_cases)}条通过用例", "", "", "", ""])
            _create_table_local(headers, rows)
        else:
            _add_paragraph_local("无通过用例")

        # 失败用例列表
        _add_title_local(f"{ch_idx}.2 失败用例列表", level=3)
        failed_cases = [c for c in cases if c.test_result == TEST_RESULT_FAIL]
        if failed_cases:
            headers = ["序号", "用例编号", "功能模块", "用例名称", "用例等级", "关联BUG"]
            rows = []
            for i, case in enumerate(failed_cases, 1):
                related_bugs = case_bug_link.get(case.case_number, [])
                bug_str = "; ".join([b.bug_name[:30] for b in related_bugs[:3]])  # 限制显示
                if len(related_bugs) > 3:
                    bug_str += f" 等{len(related_bugs)}个"
                rows.append([
                    str(i),
                    case.case_number,
                    case.module,
                    case.name[:50],
                    str(case.level),
                    bug_str if bug_str else "无"
                ])
            _create_table_local(headers, rows)
        else:
            _add_paragraph_local("无失败用例")

        # 未执行用例列表
        _add_title_local(f"{ch_idx}.3 未执行用例列表", level=3)
        unexecuted_cases = [c for c in cases if c.test_result in [TEST_RESULT_UNVERIFIED, TEST_RESULT_UNDEVELOPED]]
        if unexecuted_cases:
            headers = ["序号", "用例编号", "功能模块", "用例名称", "用例等级", "未执行原因"]
            rows = []
            for i, case in enumerate(unexecuted_cases[:10], 1):  # 限制显示10条
                reason = "未验证" if case.test_result == TEST_RESULT_UNVERIFIED else "未开发"
                rows.append([
                    str(i),
                    case.case_number,
                    case.module,
                    case.name[:50],
                    str(case.level),
                    reason
                ])
            if len(unexecuted_cases) > 10:
                rows.append(["...", f"等{len(unexecuted_cases)}条未执行用例", "", "", "", ""])
            _create_table_local(headers, rows)
        else:
            _add_paragraph_local("无未执行用例")

    # ==================== 五、BUG详细列表 ====================
    if chapters.get("bug_list", True):
        ch_idx += 1
        _add_title_local(f"{_zh_num(ch_idx)}、BUG详细列表", level=2)

        _add_title_local(f"{ch_idx}.1 BUG详细记录", level=3)
        if bugs:
            headers = ["序号", "BUG等级", "BUG状态", "BUG名称", "BUG类型", "提单人员", "负责人员"]
            rows = []
            for i, bug in enumerate(bugs, 1):
                rows.append([
                    str(i),
                    bug.bug_level,
                    bug.bug_status,
                    bug.bug_name[:50],
                    bug.bug_type,
                    bug.reporter,
                    bug.owner
                ])
            _create_table_local(headers, rows)
        else:
            _add_paragraph_local("无BUG记录")

        _add_title_local(f"{ch_idx}.2 遗留BUG说明", level=3)
        remaining_bugs = [b for b in bugs if b.bug_status in REMAINING_BUG_STATUS]
        if remaining_bugs:
            headers = ["BUG编号", "BUG等级", "问题描述", "遗留原因", "后续计划"]
            rows = []
            for bug in remaining_bugs:
                rows.append([
                    bug.bug_name[:30],
                    bug.bug_level,
                    bug.bug_name[:60],
                    "待修复",
                    "后续版本修复"
                ])
            _create_table_local(headers, rows)
        else:
            _add_paragraph_local("无遗留BUG")

    # ==================== 六、图表分析 ====================
    if chapters.get("chart_analysis", True):
        ch_idx += 1
        _add_title_local(f"{_zh_num(ch_idx)}、图表分析", level=2)

        # 添加图表
        if "bug_level" in chart_paths:
            _add_title_local(f"{ch_idx}.1 BUG等级分布", level=3)
            _add_image(doc, chart_paths["bug_level"])

        if "test_result" in chart_paths:
            _add_title_local(f"{ch_idx}.2 用例执行结果分布", level=3)
            _add_image(doc, chart_paths["test_result"])

        if "pass_rate" in chart_paths:
            _add_title_local(f"{ch_idx}.3 用例执行情况统计", level=3)
            _add_image(doc, chart_paths["pass_rate"])

        if "bug_by_module" in chart_paths:
            _add_title_local(f"{ch_idx}.4 各模块BUG分布", level=3)
            _add_image(doc, chart_paths["bug_by_module"])

    # ==================== 七、测试执行记录 ====================
    if chapters.get("execution_records", True):
        ch_idx += 1
        _add_title_local(f"{_zh_num(ch_idx)}、测试执行记录", level=2)

        _add_title_local(f"{ch_idx}.1 执行时间统计", level=3)
        headers = ["统计项", "时间"]
        rows = [
            ["测试开始时间", current_date],
            ["测试结束时间", current_date],
            ["测试总耗时", "自动化生成"],
            ["平均用例执行时间", "N/A"]
        ]
        _create_table_local(headers, rows)

        _add_title_local(f"{ch_idx}.2 执行人员分工", level=3)
        headers = ["测试人员", "负责模块", "执行用例数", "发现BUG数"]
        rows = [
            ["自动化工具", "全模块", str(case_analysis.total_cases), str(bug_analysis.total_bugs)]
        ]
        _create_table_local(headers, rows)

    # ==================== 八、测试附件 ====================
    if chapters.get("attachments", True):
        ch_idx += 1
        _add_title_local(f"{_zh_num(ch_idx)}、测试附件", level=2)

        _add_title_local(f"{ch_idx}.1 测试截图", level=3)
        _add_paragraph_local("无测试截图")

        _add_title_local(f"{ch_idx}.2 测试日志", level=3)
        _add_paragraph_local("无测试日志")

    # ==================== 九、风险评估与建议 ====================
    if chapters.get("risk_assessment", True):
        ch_idx += 1
        _add_title_local(f"{_zh_num(ch_idx)}、风险评估与建议", level=2)

        _add_title_local(f"{ch_idx}.1 质量风险分析", level=3)
        _add_paragraph_local("无特别风险")

        _add_title_local(f"{ch_idx}.2 发布建议", level=3)
        # 根据测试结果自动生成发布建议
        if case_analysis.failed_cases == 0 and bug_analysis.remaining_bugs == 0:
            recommendation = "建议发布 - 质量达标，风险可控"
        elif case_analysis.failed_cases > 0:
            recommendation = "建议延期 - 存在失败的测试用例，需要修复"
        elif bug_analysis.remaining_bugs > 0:
            critical = bug_analysis.remaining_by_level.get(BUG_LEVEL_1, 0) + \
                       bug_analysis.remaining_by_level.get(BUG_LEVEL_2, 0)
            if critical > 0:
                recommendation = "建议延期 - 存在重大缺陷，需要修复"
            else:
                recommendation = "有条件发布 - 存在已知问题，需制定规避方案"
        else:
            recommendation = "建议发布 - 质量达标，风险可控"
        _add_paragraph_local(recommendation)

        _add_title_local(f"{ch_idx}.3 改进建议", level=3)
        _add_paragraph_local("待补充")

    # ==================== 十、附录 ====================
    if chapters.get("appendix", True):
        ch_idx += 1
        _add_title_local(f"{_zh_num(ch_idx)}、附录", level=2)

        _add_title_local(f"{ch_idx}.1 用例与BUG关联表", level=3)
        headers = ["用例编号", "用例名称", "关联BUG编号", "BUG状态"]
        rows = []
        for case_number, bug_list in case_bug_link.items():
            if bug_list:
                for bug in bug_list[:3]:  # 每个用例限制显示3个BUG
                    rows.append([
                        case_number,
                        "关联用例",
                        bug.bug_name[:30],
                        bug.bug_status
                    ])
        if rows:
            _create_table_local(headers, rows)
        else:
            _add_paragraph_local("无关联数据")

        _add_title_local(f"{ch_idx}.2 术语表", level=3)
        _add_paragraph_local("无术语定义")

        _add_title_local(f"{ch_idx}.3 参考文档", level=3)
        _add_paragraph_local("无参考文档")

        _add_title_local(f"{ch_idx}.4 修订历史", level=3)
        headers = ["版本", "修订日期", "修订人", "修订内容"]
        rows = [
            ["v1.0", current_date, "自动化工具", "自动生成初始报告"]
        ]
        _create_table_local(headers, rows)

    # ==================== 保存文档 ====================
    # 确保输出目录存在
    output_dir = Path(output_path).parent
    output_dir.mkdir(parents=True, exist_ok=True)

    # 保存文档
    doc.save(output_path)

    return output_path


def fill_template(template_path: str, data: Dict[str, Any]) -> str:
    """
    填充模板内容

    Args:
        template_path: 模板文件路径
        data: 填充数据

    Returns:
        填充后的内容
    """
    # 读取模板文件
    template_file = Path(template_path)
    if not template_file.exists():
        raise FileNotFoundError(f"模板文件不存在: {template_path}")

    with open(template_file, 'r', encoding='utf-8') as f:
        content = f.read()

    # 替换占位符
    for key, value in data.items():
        placeholder = f"{{{key}}}"
        content = content.replace(placeholder, str(value))

    return content