"""
PDF 全文提取实现
"""

from __future__ import annotations

import io
from typing import Any, Dict, List, Tuple

import fitz  # PyMuPDF

from ..config.provider import default_config_provider
from ..interfaces import DocumentSource, FullTextExtractor


class PdfFullTextExtractor(FullTextExtractor):
    """按页提取 PDF 全文内容。"""

    def __init__(self) -> None:
        self._cfg = default_config_provider

    def extract_full_text(self, source: DocumentSource) -> List[Dict[str, Any]]:
        if source.content is not None:
            doc = fitz.open(stream=io.BytesIO(source.content))
            source_file = "bytes_stream"
        elif source.path is not None:
            doc = fitz.open(source.path)
            source_file = str(source.path)
        else:
            raise ValueError("DocumentSource 既没有 path 也没有 content")

        pages: List[Dict[str, Any]] = []
        current_pos = 0
        try:
            for page_num in range(len(doc)):
                page = doc[page_num]
                # # 提取文本，表格部分用 <表格></表格> 标签替换
                text = self._extract_text_with_table_placeholders(page)
                # 过滤页眉页脚
                text = self._filter_header_footer(text)
                pages.append(
                    {
                        "page_num": page_num + 1,
                        "text": text,
                        "start_pos": current_pos,
                        "end_pos": current_pos + len(text),
                        "source_file": source_file,
                    }
                )
                current_pos += len(text)
        finally:
            doc.close()

        return pages

    def _filter_header_footer(self, text: str) -> str:
        """
        过滤页眉页脚
        
        过滤规则：
        1. 页眉：检测连续空格，检测到就删掉这行
        2. 页脚：每页的最后一行，删掉每页的最后一行
        """
        # 获取配置
        header_space_threshold = self._cfg.get(
            "header_footer_filter.header_space_threshold", 20
        )

        lines = text.split("\n")
        
        # 如果只有一行或没有行，直接返回
        if len(lines) <= 1:
            return text
        
        # 第一步：过滤页眉（连续空格超过阈值的行）
        filtered_lines: List[str] = []
        for line in lines:
            # 统计连续空格的最大长度
            max_consecutive_spaces = 0
            current_spaces = 0
            for char in line:
                if char == " ":
                    current_spaces += 1
                    max_consecutive_spaces = max(max_consecutive_spaces, current_spaces)
                else:
                    current_spaces = 0
            
            # 如果连续空格数超过阈值，认为是页眉行，跳过
            if max_consecutive_spaces >= header_space_threshold:
                continue
            
            # 保留非页眉行
            filtered_lines.append(line)
        
        # 第二步：过滤页脚（删除最后一行）
        if len(filtered_lines) > 0:
            filtered_lines.pop()  # 删除最后一行

        return "\n".join(filtered_lines)

    def _count_chinese_chars(self, text: str) -> int:
        """
        统计文本中的中文字符数（不含转义字符）
        
        中文字符范围：\u4e00-\u9fff
        """
        count = 0
        for char in text:
            # 判断是否是中文字符
            if "\u4e00" <= char <= "\u9fff":
                count += 1
        return count

    def _get_table_bboxes(self, page: fitz.Page) -> List[Tuple[float, float, float, float]]:
        """
        获取页面中所有表格的边界框。
        
        Args:
            page: PyMuPDF 页面对象
        
        Returns:
            表格边界框列表，每个边界框为 (x0, y0, x1, y1)
        """
        table_bboxes = []
        
        try:
            tables = page.find_tables()
            for table in tables:
                # 获取表格的边界框
                bbox = table.bbox
                table_bboxes.append(bbox)
        except AttributeError:
            # 如果 find_tables 方法不存在，说明 PyMuPDF 版本太低
            # 这种情况下不提取表格，只返回空列表
            pass
        except Exception:
            # 表格识别失败，静默处理，继续提取文本
            pass
        
        return table_bboxes

    def _point_in_bbox(
        self, point: Tuple[float, float], bbox: Tuple[float, float, float, float]
    ) -> bool:
        """
        判断点是否在边界框内。
        
        Args:
            point: (x, y) 坐标
            bbox: (x0, y0, x1, y1) 边界框
        
        Returns:
            如果点在边界框内返回 True，否则返回 False
        """
        x, y = point
        x0, y0, x1, y1 = bbox
        return x0 <= x <= x1 and y0 <= y <= y1

    def _is_in_table_region(
        self,
        bbox: Tuple[float, float, float, float],
        table_bboxes: List[Tuple[float, float, float, float]],
        overlap_threshold: float = 0.5,
    ) -> bool:
        """
        判断文本块是否在表格区域内。
        
        Args:
            bbox: 文本块的边界框 (x0, y0, x1, y1)
            table_bboxes: 表格边界框列表
            overlap_threshold: 重叠阈值，如果文本块与表格的重叠面积超过这个比例，认为在表格内
        
        Returns:
            如果文本块在表格区域内返回 True，否则返回 False
        """
        x0, y0, x1, y1 = bbox
        text_area = (x1 - x0) * (y1 - y0)

        for table_bbox in table_bboxes:
            tx0, ty0, tx1, ty1 = table_bbox

            # 计算重叠区域
            overlap_x0 = max(x0, tx0)
            overlap_y0 = max(y0, ty0)
            overlap_x1 = min(x1, tx1)
            overlap_y1 = min(y1, ty1)

            if overlap_x0 < overlap_x1 and overlap_y0 < overlap_y1:
                # 有重叠
                overlap_area = (overlap_x1 - overlap_x0) * (overlap_y1 - overlap_y0)
                overlap_ratio = overlap_area / text_area if text_area > 0 else 0

                # 如果重叠比例超过阈值，或者文本块的中心点在表格内，认为在表格区域
                if overlap_ratio >= overlap_threshold:
                    return True

                # 检查文本块中心点是否在表格内
                center_x = (x0 + x1) / 2
                center_y = (y0 + y1) / 2
                if self._point_in_bbox((center_x, center_y), table_bbox):
                    return True

        return False

    def _extract_text_with_table_placeholders(self, page: fitz.Page) -> str:
        """
        提取页面文本，将表格部分用 <表格></表格> 标签替换。
        
        Args:
            page: PyMuPDF 页面对象
        
        Returns:
            提取的文本内容，表格部分用 <表格></表格> 标签替换
        """
        # 获取页面中所有表格的边界框
        table_bboxes = self._get_table_bboxes(page)

        # 如果没有表格，直接使用普通文本提取
        if not table_bboxes:
            return page.get_text()

        # 获取带位置信息的文本
        text_dict = page.get_text("dict")

        # 收集所有元素（文本块和表格），按 y 坐标排序
        elements = []

        # 添加表格标记
        for table_bbox in table_bboxes:
            elements.append(
                {
                    "type": "table",
                    "y": table_bbox[1],  # 使用 y0 作为排序依据
                    "bbox": table_bbox,
                }
            )

        # 处理文本块
        for block in text_dict.get("blocks", []):
            if "lines" not in block:  # 跳过非文本块（如图片）
                continue

            # 获取文本块的边界框
            block_bbox = block["bbox"]

            # 检查是否在表格区域内
            if not self._is_in_table_region(block_bbox, table_bboxes):
                # 不在表格区域内，提取文本
                block_text = ""
                for line in block["lines"]:
                    line_text = ""
                    for span in line["spans"]:
                        line_text += span["text"]
                    if line_text.strip():
                        block_text += line_text + "\n"

                if block_text.strip():
                    elements.append(
                        {
                            "type": "text",
                            "y": block_bbox[1],
                            "text": block_text.strip(),
                        }
                    )

        # 按 y 坐标排序
        elements.sort(key=lambda x: x["y"])

        # 构建页面文本
        page_text_parts = []
        last_was_table = False

        for element in elements:
            if element["type"] == "table":
                if not last_was_table:
                    page_text_parts.append("<表格></表格>")
                    last_was_table = True
            else:
                page_text_parts.append(element["text"])
                last_was_table = False

        return "\n".join(page_text_parts).strip()



