"""PDF 文件解析器，使用 fitz (PyMuPDF) 提取文本并根据字体大小判断标题层级"""

import os
from collections import Counter
from typing import List

import fitz

from exceptions import ParseError
from parsers.base import BaseParser


class PdfParser(BaseParser):
    """PDF 文件解析器，逐页提取文本块，根据字体大小与正文众数的差值判断标题层级"""

    def supported_extensions(self) -> List[str]:
        return [".pdf"]

    def parse(self, file_path: str) -> str:
        """
        解析 PDF 文件，提取文本并根据字体大小判断标题层级，拼接为 Markdown。

        参考 MaxKB PdfSplitHandle.handle_pdf_content() 核心逻辑：
        逐页提取文本块(dict格式) → 收集所有字体大小 → 计算众数作为正文字体
        → 根据差值判断标题层级(>2 → ##, >0.5 → ###) → 拼接为 Markdown

        Args:
            file_path: 文件路径

        Returns:
            Markdown 格式的文本内容

        Raises:
            ParseError: 文件无法读取或解析失败时抛出
        """
        file_name = os.path.basename(file_path)

        try:
            doc = fitz.open(file_path)
        except Exception as e:
            raise ParseError(file_name, f"PDF 文件打开失败: {e}")

        try:
            return self._extract_content(doc)
        except ParseError:
            raise
        except Exception as e:
            raise ParseError(file_name, f"PDF 解析失败: {e}")
        finally:
            doc.close()

    @staticmethod
    def _extract_content(doc: fitz.Document) -> str:
        """
        从 PDF 文档中提取文本内容。

        第一遍遍历收集所有字体大小，计算众数作为正文字体大小。
        第二遍遍历根据字体大小差值判断标题层级，拼接为 Markdown。

        Args:
            doc: PyMuPDF 文档对象

        Returns:
            Markdown 格式的文本内容
        """
        # 第一步：收集所有字体大小
        font_sizes = []
        for page_num in range(len(doc)):
            page = doc.load_page(page_num)
            blocks = page.get_text("dict")["blocks"]
            for block in blocks:
                if block["type"] == 0:  # 文本块
                    for line in block["lines"]:
                        for span in line["spans"]:
                            if span["size"] > 0:
                                font_sizes.append(span["size"])

        # 计算正文字体大小（众数）
        if not font_sizes:
            body_font_size = 12
        else:
            body_font_size = Counter(font_sizes).most_common(1)[0][0]

        # 第二步：提取内容
        content = ""
        for page_num in range(len(doc)):
            page = doc.load_page(page_num)
            blocks = page.get_text("dict")["blocks"]

            for block in blocks:
                if block["type"] != 0:  # 跳过非文本块
                    continue

                for line in block["lines"]:
                    if not line["spans"]:
                        continue

                    text = "".join(span["text"] for span in line["spans"])
                    font_size = line["spans"][0]["size"]

                    # 根据与正文字体的差值判断标题层级
                    size_diff = font_size - body_font_size

                    if size_diff > 2:  # 明显大于正文
                        content += f"## {text}\n\n"
                    elif size_diff > 0.5:  # 略大于正文
                        content += f"### {text}\n\n"
                    else:  # 正文
                        content += f"{text}\n"

        # 清除 null 字符
        content = content.replace("\0", "")

        return content
