#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
文档切分模块修复验证测试

测试目标：验证 "第十章 其他资料" 内容不会被错误合并到 "第九章 验收要求->五、验收人员" 中。

问题根因：
- `title_matcher.find_title_positions` 只取第一个匹配，导致第十章标题被错误定位到目录页（page 6）。
- 真正的第十章（page 46）未被发现，第九章成为最后一项，content_block 延伸到全文末尾。
- "计算书"、"相关施工图纸"、"编制及审核人员情况" 全部被合并进 doc_chunk_第九章->五_1。

修复点：
1. title_matcher.py：支持多位置匹配，结合 toc_page 页码择优。
2. text_splitter.py：增加 all_toc_items 硬边界保护，防止 content_block 跨章节溢出。

运行方式：
  python utils_test/Chunk_Split_Test/test_chunk_split_fix.py

可选环境变量：
  TEST_PDF_PATH=xxx.pdf  指定自定义 PDF 测试文档
"""

import json
import os
import sys
from pathlib import Path

# 添加项目根目录到路径
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))

from core.construction_review.component.doc_worker.pipeline import PipelineComponents, DefaultDocumentPipeline, DefaultFileParseFacade
from core.construction_review.component.doc_worker.config.provider import default_config_provider
from core.construction_review.component.doc_worker.pdf_worker.toc_extractor import PdfTOCExtractor
from core.construction_review.component.doc_worker.classification.hierarchy_classifier import HierarchyClassifier
from core.construction_review.component.doc_worker.pdf_worker.fulltext_extractor import PdfFullTextExtractor
from core.construction_review.component.doc_worker.pdf_worker.text_splitter import PdfTextSplitter
from core.construction_review.component.doc_worker.pdf_worker.json_writer import PdfJsonResultWriter


# 默认测试文档：四川路桥测试模版 PDF（注意：doc_worker CLI 目前仅支持 PDF）
DEFAULT_TEST_PDF = Path("D:/wx_work/sichuan_luqiao/lu_sgsc_testfile/测试模版-四川路桥专项施工方案框架以及编制说明（2025修订第三版）- v0.2.pdf")
ALTERNATIVE_TEST_DOCX = project_root / "utils_test" / "Completeness_Test" / "测试模版-四川路桥专项施工方案框架以及编制说明（2025修订第三版）- v0.2.docx"


def build_test_facade():
    """
    构建一个轻量级 facade：
    - 跳过 chunk 分类（避免大量 LLM 调用）
    - 使用 PyMuPDF 纯本地提取（避免 MinerU OCR 的耗时网络调用）
    """
    components = PipelineComponents(
        config=default_config_provider,
        toc_extractor=PdfTOCExtractor(),
        classifier=HierarchyClassifier(),
        fulltext_extractor=PdfFullTextExtractor(),  # 纯本地，速度远快于 Hybrid/MinerU
        splitter=PdfTextSplitter(),
        writers=[PdfJsonResultWriter()],
        chunk_classifier=None,  # 关键：跳过二级/三级分类
    )
    pipeline = DefaultDocumentPipeline(components)
    return DefaultFileParseFacade(pipeline)


def locate_test_file() -> Path | None:
    """定位可用的测试文档。"""
    custom = os.environ.get("TEST_PDF_PATH")
    if custom:
        p = Path(custom)
        if p.exists():
            return p
        print(f"[WARN] 自定义测试文件不存在: {p}")

    if DEFAULT_TEST_PDF.exists():
        return DEFAULT_TEST_PDF

    # 如果只有 docx，提示用户
    if ALTERNATIVE_TEST_DOCX.exists():
        print(f"[WARN] 找到 docx 版本但 pdf_worker 暂不支持 docx: {ALTERNATIVE_TEST_DOCX}")
        print(f"[HINT] 请将 docx 另存为 PDF 后放到: {DEFAULT_TEST_PDF}")

    return None


def run_pipeline(file_path: Path) -> dict:
    """运行 doc_worker 管线，返回结果。"""
    print(f"\n[INFO] 正在处理文档: {file_path}")
    print("[INFO] 使用测试 facade（仅 TOC + 一级分类 + 切分，跳过 chunk 级 LLM 分类）")

    facade = build_test_facade()
    result = facade.process_file(
        file_path=file_path,
        target_level=None,      # 使用配置默认值
        max_chunk_size=None,
        min_chunk_size=None,
        output_dir=None,
    )
    return result


def analyze_chunks(result: dict) -> dict:
    """分析 chunks 结构，提取关键指标。"""
    chunks = result.get("chunks", []) or []
    toc_info = result.get("toc_info", {}) or {}
    classification = result.get("classification", {}) or {}

    # 按 section_label 分组
    section_to_chunks: dict[str, list[dict]] = {}
    for chunk in chunks:
        label = chunk.get("section_label", "UNKNOWN")
        section_to_chunks.setdefault(label, []).append(chunk)

    # 定位关键 chunk
    chapter_10_chunks = [c for c in chunks if "第十章" in c.get("section_label", "")]
    chapter_9_last_chunks = [c for c in chunks if c.get("section_label", "").startswith("第九章")]

    # 找 "第九章->五" 的 chunk（问题原型的重灾区）
    nine_five_chunks = section_to_chunks.get("第九章 验收要求->五、 验收人员", [])

    # 提取 "计算书" 等关键词是否出现在不该出现的位置
    leak_keywords = ["计算书", "相关施工图纸", "编制及审核人员情况"]
    leaks: list[dict] = []
    for chunk in chunks:
        label = chunk.get("section_label", "")
        if "第九章" in label and "验收人员" in label:
            content = chunk.get("review_chunk_content", "") + chunk.get("content", "")
            for kw in leak_keywords:
                if kw in content:
                    leaks.append({"chunk_id": chunk.get("chunk_id"), "section_label": label, "keyword": kw})

    return {
        "total_chunks": len(chunks),
        "toc_count": toc_info.get("toc_count", 0),
        "target_level": classification.get("target_level"),
        "section_labels": sorted(section_to_chunks.keys()),
        "chapter_10_chunks": chapter_10_chunks,
        "chapter_9_last_chunks": chapter_9_last_chunks,
        "nine_five_chunks": nine_five_chunks,
        "leaks": leaks,
        "chunks": chunks,
    }


def print_report(report: dict) -> None:
    """打印readable报告。"""
    print("\n" + "=" * 80)
    print("文档切分修复验证报告")
    print("=" * 80)
    print(f"总 chunk 数: {report['total_chunks']}")
    print(f"目录项数: {report['toc_count']}")
    print(f"切分目标层级: {report['target_level']}")

    print("\n[SECTION_LABEL 列表]")
    for label in report["section_labels"]:
        print(f"  - {label}")

    print("\n[第十章相关 chunks]")
    if report["chapter_10_chunks"]:
        for c in report["chapter_10_chunks"]:
            print(f"  {c.get('chunk_id')} | {c.get('section_label')} | page={c.get('element_tag', {}).get('page')}")
    else:
        print("  (无) —— 严重异常！")

    print("\n[第九章 验收人员 chunks]")
    if report["nine_five_chunks"]:
        for c in report["nine_five_chunks"]:
            print(f"  {c.get('chunk_id')} | {c.get('section_label')} | page={c.get('element_tag', {}).get('page')}")
    else:
        print("  (无)")

    print("\n[内容泄漏检查]")
    if report["leaks"]:
        print("  FAIL —— 发现第十章关键词出现在第九章 chunk 中！")
        for leak in report["leaks"]:
            print(f"    -> {leak['chunk_id']} ({leak['section_label']}) 包含 '{leak['keyword']}'")
    else:
        print("  PASS —— 未发现跨章节内容泄漏。")

    print("\n[断言检查]")
    passed = 0
    failed = 0

    # 断言1: 必须存在第十章的 chunk
    labels = report["section_labels"]
    chapter_10_exists = any("第十章" in l for l in labels)
    if chapter_10_exists:
        print("  [PASS] 存在 section_label 包含 '第十章' 的 chunk")
        passed += 1
    else:
        print("  [FAIL] 未找到任何 section_label 包含 '第十章' 的 chunk")
        failed += 1

    # 断言2: 第九章->五 不应该包含第十章关键词
    if not report["leaks"]:
        print("  [PASS] 第九章->五 未包含第十章专属关键词")
        passed += 1
    else:
        print("  [FAIL] 第九章->五 包含第十章专属关键词")
        failed += 1

    # 断言3: 第十章不应该有 page=6 的异常 chunk
    abnormal_page_6 = [
        c for c in report["chapter_10_chunks"]
        if c.get("element_tag", {}).get("page") == 6
    ]
    if not abnormal_page_6:
        print("  [PASS] 未发现 page=6 的异常第十章 chunk")
        passed += 1
    else:
        print(f"  [FAIL] 发现 {len(abnormal_page_6)} 个 page=6 的异常第十章 chunk")
        for c in abnormal_page_6:
            print(f"       {c.get('chunk_id')} | {c.get('section_label')}")
        failed += 1

    print(f"\n结果: {passed} 通过, {failed} 失败")
    print("=" * 80)


def main() -> int:
    test_file = locate_test_file()
    if not test_file:
        print("[ERROR] 未找到可用的测试 PDF 文档。")
        print(f"[INFO] 请通过环境变量指定: TEST_PDF_PATH=xxx.pdf python {__file__}")
        return 1

    result = run_pipeline(test_file)
    report = analyze_chunks(result)
    print_report(report)

    # 写出中间结果，方便后续人工排查
    output_path = Path(__file__).parent / "last_test_result.json"
    with open(output_path, "w", encoding="utf-8") as f:
        # 只保留可读的关键字段
        dump_data = {
            "source": str(test_file),
            "section_labels": report["section_labels"],
            "chunks_summary": [
                {
                    "chunk_id": c.get("chunk_id"),
                    "section_label": c.get("section_label"),
                    "page": c.get("element_tag", {}).get("page"),
                    "content_preview": (c.get("review_chunk_content", "") or c.get("content", ""))[:200].replace("\n", " ") + "...",
                }
                for c in result.get("chunks", [])
            ],
        }
        json.dump(dump_data, f, ensure_ascii=False, indent=2)
    print(f"[INFO] 摘要已保存到: {output_path}")

    return 0 if report["leaks"] == [] and any("第十章" in l for l in report["section_labels"]) else 1


if __name__ == "__main__":
    sys.exit(main())
