"""
PDF 文本切分实现 - 简化版

基于 splitter_pdf.py 的严格正则匹配逻辑：
- 章标题：第[一二三四五六七八九十百]+章
- 节标题：[一二三四五六七八九十百]+、

特点：
- 自动跳过目录页
- 裁剪页眉页脚
- 严格章节检查（不规范或缺失提醒）
"""

from __future__ import annotations

import re
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Set

import fitz

from foundation.observability.logger.loggering import review_logger as logger
from foundation.observability.cachefiles.cache_manager import cache, CacheBaseDir

from ..interfaces import DocumentSource, TextSplitter
# TODO: 暂时移除本地分类器引用，待一级分类优化完成后再考虑恢复
# from ..classification.smart_local_classifier import classify_local


@dataclass
class ChapterValidationResult:
    """章节验证结果"""
    chapter_title: str
    is_valid: bool
    issues: List[str] = field(default_factory=list)
    section_count: int = 0
    invalid_sections: List[str] = field(default_factory=list)


class PdfTextSplitter(TextSplitter):
    """
    基于严格正则匹配的 PDF 文本切分器

    匹配规则：
    - 章标题：第[一二三四五六七八九十百]+章
    - 节标题：[一二三四五六七八九十百]+、
    """

    # 严格章节标题正则
    CHAPTER_PATTERN = re.compile(r'^第[一二三四五六七八九十百]+章\s*.*')
    SECTION_PATTERN = re.compile(r'^[一二三四五六七八九十百]+、\s*.*')

    # 目录特征：连续的三个以上小数点或省略号
    TOC_PATTERN = re.compile(r'\.{3,}|…{2,}')

    # 页眉页脚过滤关键词
    HEADER_FOOTER_KEYWORDS = [
        "四川路桥建设集团股份有限公司",
        "T梁运输及安装专项施工方案",
    ]

    def __init__(
        self,
        clip_top: float = 60,
        clip_bottom: float = 60,
        enable_validation: bool = True,
        expected_chapters: Optional[List[str]] = None
    ) -> None:
        """
        初始化

        Args:
            clip_top: 顶部裁剪磅数（过滤页眉）
            clip_bottom: 底部裁剪磅数（过滤页脚）
            enable_validation: 是否启用章节规范检查
            expected_chapters: 期望的章节列表（用于检查缺失）
        """
        self.clip_top = clip_top
        self.clip_bottom = clip_bottom
        self.enable_validation = enable_validation
        self.expected_chapters = expected_chapters or []

        # 验证结果
        self.validation_results: List[ChapterValidationResult] = []
        self.uncategorized_content: List[str] = []
        self.warnings: List[str] = []

    def split_by_hierarchy(
        self,
        classification_items: List[Dict[str, Any]],
        pages_content: List[Dict[str, Any]],
        toc_info: Dict[str, Any],
        target_level: int,
        max_chunk_size: int,
        min_chunk_size: int,
    ) -> List[Dict[str, Any]]:
        """
        主入口：按章节正则匹配切分文本

        使用 classification_items (LLM分类结果) 来映射章节到分类代码
        """
        if not pages_content:
            logger.warning("PDF页面内容为空")
            return []

        # 执行切分（逐页处理，与 splitter_pdf.py 一致）
        structured_data = self._extract_by_pattern(pages_content)

        # 章节验证
        if self.enable_validation:
            self.validation_results = self._validate_chapters(structured_data)
            self._log_validation_results()

        # 构建章节标题到分类代码的映射（来自LLM分类结果）
        chapter_classification_map = self._build_classification_map(classification_items)

        # 转换为标准 chunk 格式（传入分类映射）
        chunks = self._convert_to_chunks(structured_data, chapter_classification_map)

        logger.info(f"  切分完成: {len(chunks)} 个内容块")

        # 保存切分结果到缓存
        self._save_split_result(chunks, structured_data)

        return chunks

    def _build_classification_map(self, classification_items: List[Dict[str, Any]]) -> Dict[str, str]:
        """构建章节标题到分类代码的映射"""
        classification_map = {}
        for item in classification_items:
            title = item.get("title", "").strip()
            category_code = item.get("category_code", "")
            if title and category_code:
                # 1. 原始标题（来自一级分类结果，如 "第一章编制依据"）
                classification_map[title] = category_code

                # 2. 不带空格的版本
                classification_map[title.replace(" ", "")] = category_code
                classification_map[title.replace(" ", "").replace("\t", "")] = category_code

                # 3. 清理后的标题（与 _clean_chapter_title 输出一致，如 "第一章 编制依据"）
                cleaned_title = self._clean_chapter_title(title)
                if cleaned_title and cleaned_title != title:
                    classification_map[cleaned_title] = category_code
                    # 清理后的标题也可能有空格版本，存储其无空格版本
                    classification_map[cleaned_title.replace(" ", "")] = category_code

                # 4. 只保留章节号（如 "第一章"）作为备选匹配
                chapter_match = __import__('re').search(r'第[一二三四五六七八九十百]+章', title)
                if chapter_match:
                    chapter_only = chapter_match.group(0)
                    classification_map[chapter_only] = category_code

        return classification_map

    def _save_split_result(
        self,
        chunks: List[Dict[str, Any]],
        structured_data: Dict[str, Dict[str, str]]
    ) -> None:
        """保存切分结果到缓存"""
        try:
            result = {
                "chunk_count": len(chunks),
                "chapter_count": len(structured_data),
                "chapters": list(structured_data.keys()),
                "chunks": [
                    {
                        "chunk_id": c.get("chunk_id"),
                        "section_label": c.get("section_label"),
                        "chapter_classification": c.get("chapter_classification"),
                        "content_length": len(c.get("review_chunk_content", "")),
                    }
                    for c in chunks
                ],
                "validation": self.get_validation_report(structured_data) if self.validation_results else {},
            }

            cache.save(
                data=result,
                subdir="document_temp",
                filename="文档切分预处理结果.json",
                base_cache_dir=CacheBaseDir.CONSTRUCTION_REVIEW
            )
            logger.debug("  切分结果已保存到缓存: document_temp/文档切分预处理结果.json")
        except Exception as e:
            logger.warning(f"  保存切分结果失败: {e}")

    def extract_from_pdf(self, source: DocumentSource) -> Dict[str, Dict[str, str]]:
        """
        直接从 PDF 提取结构化数据（对外接口）

        Returns:
            {chapter: {section: content}}
        """
        # 打开PDF
        if source.content is not None:
            import io
            doc = fitz.open(stream=io.BytesIO(source.content))
        elif source.path is not None:
            doc = fitz.open(source.path)
        else:
            raise ValueError("DocumentSource 既没有 path 也没有 content")

        try:
            structured_data = self._extract_from_doc(doc)

            # 验证
            if self.enable_validation:
                self.validation_results = self._validate_chapters(structured_data)
                self._log_validation_results()

            return structured_data

        finally:
            doc.close()

    def _extract_from_doc(self, doc: fitz.Document) -> Dict[str, Dict[str, str]]:
        """从 fitz Document 提取章节结构"""
        structured_data: Dict[str, Dict[str, List[str]]] = {}
        current_chapter = "未分类前言"
        current_section = "默认部分"
        in_body = False
        matched_chapters = []  # 记录匹配的章节
        first_lines = []  # 记录前100行用于诊断

        for page_num in range(len(doc)):
            page = doc.load_page(page_num)

            # 裁剪页眉页脚
            rect = page.rect
            clip_box = fitz.Rect(0, self.clip_top, rect.width, rect.height - self.clip_bottom)

            # 提取文本
            text = page.get_text("text", clip=clip_box)
            lines = text.split('\n')

            for line in lines:
                line = line.strip()

                # 记录前100行用于诊断
                if len(first_lines) < 100:
                    first_lines.append(line)

                # 跳过空行
                if not line:
                    continue

                # 过滤页眉页脚
                if self._is_header_footer(line):
                    continue

                # 跳过目录阶段
                if not in_body:
                    if self.CHAPTER_PATTERN.match(line) and not self.TOC_PATTERN.search(line):
                        in_body = True
                        logger.info(f"  检测到正文开始于第 {page_num + 1} 页: {line[:30]}...")
                    else:
                        continue

                # 跳过残余目录格式
                if self.TOC_PATTERN.search(line):
                    continue

                # 匹配章标题
                if self.CHAPTER_PATTERN.match(line):
                    # 清理章节标题中的页码和特殊字符（如 "第一章编制依据........................................ 1"）
                    current_chapter = self._clean_chapter_title(line)
                    current_section = "章节标题"
                    matched_chapters.append(current_chapter)
                    if current_chapter not in structured_data:
                        structured_data[current_chapter] = {current_section: []}
                        logger.info(f"  [章节匹配] 发现新章节: {current_chapter[:50]}")
                    continue

                # 匹配节标题
                if self.SECTION_PATTERN.match(line):
                    current_section = line
                    if current_chapter not in structured_data:
                        structured_data[current_chapter] = {}
                    if current_section not in structured_data[current_chapter]:
                        structured_data[current_chapter][current_section] = []
                    continue

                # 确保结构存在
                if current_chapter not in structured_data:
                    structured_data[current_chapter] = {current_section: []}
                if current_section not in structured_data[current_chapter]:
                    structured_data[current_chapter][current_section] = []

                # 添加内容
                structured_data[current_chapter][current_section].append(line)

        # 诊断日志：如果章节数量少于预期，输出前100行
        if len(matched_chapters) < 10:
            logger.warning(f"  [诊断] 只匹配到 {len(matched_chapters)} 个章节，预期更多")
            logger.warning(f"  [诊断] 前100行内容:")
            for i, line in enumerate(first_lines[:100]):
                # 高亮匹配到的章节标题
                if self.CHAPTER_PATTERN.match(line):
                    logger.warning(f"    [{i}] >> {line[:80]} << (匹配)")
                else:
                    logger.warning(f"    [{i}]    {line[:80]}")

        # 将列表拼接成文本
        result: Dict[str, Dict[str, str]] = {}
        for chap in structured_data:
            result[chap] = {}
            for sec in structured_data[chap]:
                result[chap][sec] = '\n'.join(structured_data[chap][sec])

        return result

    def _extract_by_pattern(self, pages_content: List[Dict[str, Any]]) -> Dict[str, Dict[str, str]]:
        """从页面内容提取章节结构（逐页处理，与原始脚本一致）"""
        structured_data: Dict[str, Dict[str, List[str]]] = {}
        current_chapter = "未分类前言"
        current_section = "默认部分"
        in_body = False
        matched_chapters = []

        # 逐页处理（与 splitter_pdf.py 一致）
        for page_info in pages_content:
            page_text = page_info.get("text", "")
            lines = page_text.split('\n')

            for line in lines:
                line = line.strip()

                # 跳过空行
                if not line:
                    continue

                # 过滤页眉页脚（与 splitter_pdf.py 完全一致）
                if self._is_header_footer(line):
                    continue

                # 跳过目录阶段
                if not in_body:
                    if self.CHAPTER_PATTERN.match(line) and not self.TOC_PATTERN.search(line):
                        in_body = True
                        logger.info(f"  检测到正文开始: {line[:50]}")
                    else:
                        continue

                # 跳过残余目录格式
                if self.TOC_PATTERN.search(line):
                    continue

                # 匹配章标题
                if self.CHAPTER_PATTERN.match(line):
                    # 清理章节标题中的页码和特殊字符
                    current_chapter = self._clean_chapter_title(line)
                    current_section = "章节标题"
                    matched_chapters.append(current_chapter)
                    if current_chapter not in structured_data:
                        structured_data[current_chapter] = {current_section: []}
                        logger.info(f"  [章节匹配] {current_chapter[:50]}")
                    continue

                # 匹配节标题
                if self.SECTION_PATTERN.match(line):
                    current_section = line
                    if current_chapter not in structured_data:
                        structured_data[current_chapter] = {}
                    if current_section not in structured_data[current_chapter]:
                        structured_data[current_chapter][current_section] = []
                    continue

                # 确保结构存在
                if current_chapter not in structured_data:
                    structured_data[current_chapter] = {current_section: []}
                if current_section not in structured_data[current_chapter]:
                    structured_data[current_chapter][current_section] = []

                # 添加内容
                structured_data[current_chapter][current_section].append(line)

        # 诊断：章节数量检查
        if len(matched_chapters) < 9:
            logger.warning(f"  [诊断] 只匹配到 {len(matched_chapters)} 个章节，预期 9+ 个")

        # 拼接文本
        result: Dict[str, Dict[str, str]] = {}
        for chap in structured_data:
            result[chap] = {}
            for sec in structured_data[chap]:
                result[chap][sec] = '\n'.join(structured_data[chap][sec])

        return result

    def _is_header_footer(self, line: str) -> bool:
        """检查是否为页眉页脚（与 splitter_pdf.py 完全一致）"""
        # 只过滤特定关键词和纯数字页码
        if "四川路桥建设集团股份有限公司" in line or "T梁运输及安装专项施工方案" in line or line.isdigit():
            return True
        return False

    def _validate_chapters(
        self,
        structured_data: Dict[str, Dict[str, str]]
    ) -> List[ChapterValidationResult]:
        """验证章节规范性"""
        results = []
        actual_chapters: Set[str] = set()

        for chapter_title, sections in structured_data.items():
            result = ChapterValidationResult(chapter_title=chapter_title, is_valid=True)
            actual_chapters.add(chapter_title)

            if chapter_title == "未分类前言":
                result.is_valid = False
                result.issues.append("存在未分类前言内容，可能缺失第一章或第一章格式不规范")
                if "默认部分" in sections:
                    preview = sections["默认部分"][:5]
                    self.uncategorized_content = preview
                    self.warnings.append(f"发现未分类内容（共{len(preview)}行），可能位于第一章之前")
            else:
                if not self.CHAPTER_PATTERN.match(chapter_title):
                    result.is_valid = False
                    result.issues.append(f"章标题格式不符合规范: {chapter_title}")
                    self.warnings.append(f"章标题格式不规范: {chapter_title[:50]}")

                result.section_count = len(sections)

                for section_title in sections.keys():
                    if section_title == "章节标题":
                        continue
                    if not self.SECTION_PATTERN.match(section_title):
                        result.invalid_sections.append(section_title)
                        result.is_valid = False

                if result.invalid_sections:
                    result.issues.append(
                        f"发现 {len(result.invalid_sections)} 个不符合规范的节标题"
                    )
                    for sec in result.invalid_sections[:3]:
                        self.warnings.append(f"节标题格式不规范: {sec[:50]}")

                total_content = sum(len(content) for content in sections.values())
                if total_content == 0:
                    result.is_valid = False
                    result.issues.append("章节内容为空")

            results.append(result)

        # 检查缺失的期望章节
        if self.expected_chapters:
            for expected in self.expected_chapters:
                found = False
                for actual in actual_chapters:
                    if expected in actual:
                        found = True
                        break
                if not found:
                    results.append(ChapterValidationResult(
                        chapter_title=f"[缺失] {expected}",
                        is_valid=False,
                        issues=[f"期望章节未找到: {expected}"],
                        invalid_sections=[],
                    ))
                    self.warnings.append(f"缺失期望章节: {expected}")

        return results

    def _log_validation_results(self) -> None:
        """输出验证结果日志"""
        if not self.validation_results:
            return

        logger.info("=" * 60)
        logger.info("章节规范检查结果:")
        logger.info("=" * 60)

        valid_count = sum(1 for r in self.validation_results if r.is_valid)
        invalid_count = len(self.validation_results) - valid_count

        logger.info(f"总章节数: {len(self.validation_results)}, 规范: {valid_count}, 异常: {invalid_count}")

        for result in self.validation_results:
            status = "✓" if result.is_valid else "✗"
            logger.info(f"  [{status}] {result.chapter_title}")

            if not result.is_valid:
                for issue in result.issues:
                    logger.warning(f"      ! {issue}")

        if self.uncategorized_content:
            logger.warning("  [!] 发现未分类内容（可能位于第一章之前）:")
            for line in self.uncategorized_content[:3]:
                logger.warning(f"      > {line[:80]}")

        logger.info("=" * 60)

    def _convert_to_chunks(
        self,
        structured_data: Dict[str, Dict[str, str]],
        classification_map: Optional[Dict[str, str]] = None
    ) -> List[Dict[str, Any]]:
        """转换为 chunk 列表"""
        chunks = []
        chunk_index = 0

        for chapter_title, sections in structured_data.items():
            for section_title, content in sections.items():
                if not content.strip():
                    continue

                if chapter_title == "未分类前言":
                    hierarchy_path = ["前言"]
                    section_label = "前言"
                else:
                    hierarchy_path = [chapter_title, section_title]
                    section_label = f"{chapter_title}->{section_title}" if section_title != "章节标题" else chapter_title

                title_number = self._extract_chapter_number(chapter_title)

                # 优先使用 LLM 分类结果，其次使用本地规则
                classification = self._get_classification(chapter_title, classification_map)

                chunk_data = {
                    "file_name": "",
                    "chunk_id": f"doc_chunk_{title_number}_{chunk_index}",
                    "section_label": section_label,
                    "project_plan_type": classification,
                    "chapter_classification": classification,
                    "hierarchy_path": hierarchy_path,
                    "element_tag": {
                        "chunk_id": f"doc_chunk_{title_number}_{chunk_index}",
                        "page": 1,
                        "serial_number": title_number if title_number else str(chunk_index + 1),
                    },
                    "review_chunk_content": content,
                    "_sort_key": chunk_index,
                    "_chapter_title": chapter_title,
                    "_section_title": section_title,
                }

                chunks.append(chunk_data)
                chunk_index += 1

        return chunks

    def _get_classification(self, chapter_title: str, classification_map: Optional[Dict[str, str]] = None) -> str:
        """获取章节分类代码（优先使用LLM分类结果）"""
        # 1. 优先使用传入的LLM分类映射
        if classification_map:
            # 精确匹配
            if chapter_title in classification_map:
                return classification_map[chapter_title]
            # 去除空格后匹配
            title_no_space = chapter_title.replace(" ", "").replace("\t", "")
            if title_no_space in classification_map:
                return classification_map[title_no_space]

        # 2. 降级使用简单规则匹配
        return self._classify_chapter_type(chapter_title)

    def _clean_chapter_title(self, line: str) -> str:
        """
        清理章节标题中的页码和特殊字符

        例如：
        - "第一章编制依据............................................................................................................... 1"
          -> "第一章 编制依据"
        - "第一章 编制依据"
          -> "第一章 编制依据" (保持不变)
        """
        import re

        # 1. 提取 "第X章" 部分
        chapter_match = re.search(r'第[一二三四五六七八九十百]+章', line)
        if not chapter_match:
            return line.strip()

        chapter_prefix = chapter_match.group(0)

        # 2. 提取章节名称（章标题后的内容，直到遇到特殊字符或页码）
        # 移除 "第X章" 后的内容
        remaining = line[chapter_match.end():]

        # 3. 清理剩余部分：
        # - 移除开头的空格和点号
        # - 移除页码（行尾的数字）
        # - 移除连续的点号和横线（目录引导符）
        # - 只保留中文字符、字母、数字
        remaining = remaining.strip()

        # 移除开头的点号和空格
        remaining = re.sub(r'^[\.\s]+', '', remaining)

        # 移除页码（行尾的纯数字，前后可能有空格）
        remaining = re.sub(r'\s+\d+\s*$', '', remaining)

        # 移除连续的点号、横线、下划线（保留原始标题中的正常标点）
        # 只清理超过3个连续的目录引导符
        remaining = re.sub(r'[\._\-]{3,}[^\u4e00-\u9fa5a-zA-Z0-9]*', '', remaining)

        # 4. 组合成清理后的标题
        if remaining:
            return f"{chapter_prefix} {remaining.strip()}"
        else:
            return chapter_prefix

    def _extract_chapter_number(self, chapter_title: str) -> str:
        """从章标题提取编号"""
        match = re.search(r'第([一二三四五六七八九十百]+)章', chapter_title)
        if match:
            return f"第{match.group(1)}章"
        return ""

    def _classify_chapter_type(self, chapter_title: str) -> str:
        """根据章节标题推断一级分类"""
        title_lower = chapter_title.lower()

        keyword_map = {
            "编制依据": "basis",
            "工程概况": "overview",
            "施工计划": "plan",
            "工艺": "technology",
            "技术": "technology",
            "安全": "safety",
            "质量": "quality",
            "环境": "environment",
            "人员": "management",
            "管理": "management",
            "组织": "management",  # 组织保证措施等
            "分工": "management",  # 施工管理及作业人员配备与分工
            "验收": "acceptance",
            "计算": "other",
            "图纸": "other",
        }

        for keyword, code in keyword_map.items():
            if keyword in title_lower:
                return code

        return "other"

    def _build_outline(self, structured_data: Dict[str, Dict[str, str]]) -> List[Dict[str, Any]]:
        """
        按照原格式构建大纲

        返回层级结构:
        [
            {
                "level": 1,
                "title": "第一章 xxx",
                "type": "chapter",
                "children": [
                    {"level": 2, "title": "一、xxx", "type": "section", "content_length": 100},
                    ...
                ]
            },
            ...
        ]
        """
        outline = []

        for chapter_title, sections in structured_data.items():
            if chapter_title == "未分类前言":
                continue

            # 章节点
            chapter_node = {
                "level": 1,
                "title": chapter_title,
                "type": "chapter",
                "is_valid": self.CHAPTER_PATTERN.match(chapter_title) is not None,
                "children": []
            }

            # 节节点
            for section_title, content in sections.items():
                if section_title == "章节标题":
                    section_node_title = "章节标题"
                else:
                    section_node_title = section_title

                section_node = {
                    "level": 2,
                    "title": section_node_title,
                    "type": "section",
                    "content_length": len(content),
                    "is_valid": section_title == "章节标题" or self.SECTION_PATTERN.match(section_title) is not None,
                }
                chapter_node["children"].append(section_node)

            chapter_node["section_count"] = len(chapter_node["children"])
            outline.append(chapter_node)

        return outline

    def get_validation_report(self, structured_data: Optional[Dict[str, Dict[str, str]]] = None) -> Dict[str, Any]:
        """获取验证报告"""
        # 构建大纲（如果提供了结构化数据）
        outline = []
        if structured_data:
            outline = self._build_outline(structured_data)

        return {
            "outline": outline,  # 新增：按原格式构建的大纲
            "results": [
                {
                    "chapter": r.chapter_title,
                    "is_valid": r.is_valid,
                    "issues": r.issues,
                    "section_count": r.section_count,
                    "invalid_sections": r.invalid_sections,
                }
                for r in self.validation_results
            ],
            "uncategorized_content": self.uncategorized_content,
            "warnings": self.warnings,
            "summary": {
                "total": len(self.validation_results),
                "valid": sum(1 for r in self.validation_results if r.is_valid),
                "invalid": sum(1 for r in self.validation_results if not r.is_valid),
            }
        }

    def clear_validation(self) -> None:
        """清除验证结果"""
        self.validation_results = []
        self.uncategorized_content = []
        self.warnings = []
