"""PDF file rule implementation - PDF 文件内容规则实现."""

from __future__ import annotations

from typing import Any

try:
    import fitz  # PyMuPDF
except ImportError:
    fitz = None

try:
    import pypdf
except ImportError:
    pypdf = None

try:
    import pytesseract
    from PIL import Image
except ImportError:
    Image = None
    pytesseract = None

import pathlib

from ...models.fileinfo import FileInfo
from ._base import BaseContentRule


class PdfRule(BaseContentRule):
    """PDF 文件内容匹配规则 - 对 PDF 文件适用."""

    def __init__(self, rule_data: dict[str, Any], *, use_ocr: bool = False) -> None:
        """初始化 PDF 规则.

        Args:
            rule_data: 包含规则配置的字典
            use_ocr: 是否对 PDF 使用 OCR
        """
        super().__init__(rule_data)
        self.file_type = "pdf"
        self.use_ocr = use_ocr

    def parse_content(self, fileinfo: FileInfo) -> str:
        """从 PDF 文件中提取内容.

        Args:
            fileinfo: 文件信息对象

        Returns
        -------
            提取的文本内容
        """
        if fitz is not None:
            try:
                return self._extract_pdf_fitz(fileinfo.file_path)
            except (OSError, ValueError) as e:
                from ...models.logger import logger

                logger.warning(f"{fileinfo.file_path.name} 的 PyMuPDF 失败:{e}")

        if pypdf is not None:
            try:
                return self._extract_pdf_pypdf(fileinfo.file_path)
            except (OSError, ValueError) as e:
                from ...models.logger import logger

                logger.warning(f"{fileinfo.file_path.name} 的 pypdf 也失败:{e}")
                return ""

        from ...models.logger import logger

        logger.warning("未安装 PDF 库 (pymupdf 或 pypdf)")
        return ""

    def _extract_pdf_fitz(self, file_path: str) -> str:
        """使用 PyMuPDF 从 PDF 中提取文本."""
        if not fitz:
            return ""

        doc = None
        try:
            doc = fitz.open(file_path)
            return self._process_pdf_document(doc)
        except (OSError, ValueError):
            if doc:
                doc.close()
            raise

    def _process_pdf_document(self, doc: fitz.Document) -> str:
        """处理 PDF 文档并提取文本."""
        if doc.page_count == 0:
            from ...models.logger import logger

            logger.warning("在 PDF 中未找到页面")
            doc.close()
            return ""

        text_parts = []
        for page_num, page in enumerate(doc, 1):
            text = self._process_pdf_page(page, page_num)
            text_parts.append(text)

        doc.close()
        return "\n\n".join(text_parts) if text_parts else ""

    def _process_pdf_page(self, page: fitz.Page, page_num: int) -> str:
        """处理单个 PDF 页面."""
        if self.use_ocr and pytesseract and Image:
            import io

            pix = page.get_pixmap()
            img_data = pix.tobytes("png")
            image = Image.open(io.BytesIO(img_data))
            text = pytesseract.image_to_string(image)
        else:
            text = page.get_text()

        return f"[Page {page_num}]\n{text}"

    def _extract_pdf_pypdf(self, file_path: str) -> str:
        """使用 pypdf 从 PDF 中提取文本."""
        if not pypdf:
            return ""

        text_parts = []
        try:
            with pathlib.Path(file_path).open("rb") as f:
                pdf_reader = pypdf.PdfReader(f)

                if not pdf_reader.metadata:
                    from ...models.logger import logger

                    logger.warning("在 PDF 中未找到元数据")
                    return ""

                for page_num, page in enumerate(pdf_reader.pages, 1):
                    text = page.extract_text()
                    text_parts.append(f"[Page {page_num}]\n{text}")
        except (OSError, ValueError) as e:
            from ...models.logger import logger

            logger.warning(f"使用 pypdf 提取 PDF 时出错:{e}")
            return ""

        return "\n\n".join(text_parts) if text_parts else ""
