r"""
Чтение PDF — с извлечением текста через PyMuPDF и распознаванием
сканированных страниц без текстового слоя через Tesseract OCR.

Аудит v3 (закрытие вопросов отчёта по отладке):
    * Устранена опечатка `ocr_use` -> `ocr_used` (устраняет NameError).
    * Автодетект Tesseract в `_ocr_pages`: если путь не прописан в JSON и
      не в PATH, вызывается `autodetect_external_programs()`, находящий
      Tesseract в стандартных папках Windows (`C:\Program Files\Tesseract-OCR`
      и т.п.).
    * Надежная обработка языковых пакетов (traineddata): сначала пытаемся
      распознать как `rus+eng`, при сбое (нет одного из пакетов) делаем
      каскадный fallback на `rus`, а затем на `eng`.
    * Логирование и обработка "тихих" ошибок OCR: если при распознавании
      возникло исключение (ошибка Tesseract, сбой PIL и т.д.), оно
      фиксируется и возвращается в `ReaderOutcome.warning` / `error`.
"""
from __future__ import annotations

import logging
from pathlib import Path
from typing import Optional, Tuple

from app.readers.base import BaseReader, ReaderOutcome
from app.settings_store import load_settings, autodetect_external_programs

logger = logging.getLogger("dspscanner")


class PdfReader(BaseReader):
    name = "pdf"

    def extract_text(self, path: Path, use_ocr: bool = True) -> ReaderOutcome:
        if not self.is_file_accessible(path):
            return ReaderOutcome(locked=True, error="Файл заблокирован")

        try:
            import fitz  # PyMuPDF
        except ImportError:
            return ReaderOutcome(error="Библиотека PyMuPDF (fitz) не установлена")

        try:
            text_parts = []
            empty_pages = []
            with fitz.open(str(path)) as document:
                if document.is_encrypted:
                    if not document.authenticate(""):
                        return ReaderOutcome(error="PDF защищён паролем")

                for page_index, page in enumerate(document):
                    page_text = page.get_text("text") or ""
                    if page_text.strip():
                        text_parts.append(page_text)
                    else:
                        empty_pages.append(page_index)

                ocr_used = False
                ocr_error: Optional[str] = None

                if empty_pages and use_ocr:
                    ocr_text, ocr_used, ocr_error = self._ocr_pages(document, empty_pages, path.name)
                    if ocr_text:
                        text_parts.append(ocr_text)

            full_text = "\n\n".join(text_parts).strip()
            if not full_text:
                warning = "PDF не содержит текста и OCR не дал результатов."
                if ocr_error:
                    warning += f" Ошибка OCR: {ocr_error}"
                elif not use_ocr:
                    warning = "PDF не содержит текстового слоя (скан). Включите OCR в настройках."
                return ReaderOutcome(text=None, warning=warning)

            method = "pymupdf+ocr" if ocr_used else "pymupdf"
            warning_msg = f"Ошибки при OCR сканированных страниц: {ocr_error}" if ocr_error else None
            return ReaderOutcome(text=full_text, warning=warning_msg, method_used=method)

        except Exception as exc:  # noqa: BLE001
            return ReaderOutcome(error=f"Ошибка чтения PDF: {exc}")

    # ------------------------------------------------------------------ #
    @staticmethod
    def _ocr_pages(document, page_indices: list[int], doc_name: str) -> Tuple[Optional[str], bool, Optional[str]]:
        """Возвращает (текст, ocr_used, сообщение_об_ошибке)."""
        s = load_settings()
        tesseract_bin = s.tesseract_path

        # Если путь не задан или неверный — запускаем автодетект
        if not tesseract_bin or not Path(tesseract_bin).exists():
            _, ts_auto = autodetect_external_programs()
            if ts_auto:
                tesseract_bin = ts_auto

        if not tesseract_bin:
            return None, False, "Исполняемый файл Tesseract (tesseract.exe) не найден в системе"

        try:
            import pytesseract
            from PIL import Image
            import io
            pytesseract.pytesseract.tesseract_cmd = tesseract_bin
        except ImportError:
            return None, False, "Библиотеки pytesseract или Pillow не установлены"

        results = []
        last_error = None
        pages_ok = 0

        for idx in page_indices:
            try:
                page = document[idx]
                pixmap = page.get_pixmap(dpi=250)  # 250 DPI оптимально по качеству и скорости
                image = Image.open(io.BytesIO(pixmap.tobytes("png")))

                # Каскадная попытка языков: rus+eng > rus > eng
                ocr_text = ""
                _ocr_cascade_errors = []
                for lang in ("rus+eng", "rus", "eng"):
                    try:
                        ocr_text = pytesseract.image_to_string(image, lang=lang)
                        if ocr_text.strip():
                            break
                    except Exception as e:
                        _ocr_cascade_errors.append(f"{lang}: {e}")
                        continue
                if not ocr_text.strip() and _ocr_cascade_errors:
                    # Все три попытки упали — формируем суммарную ошибку
                    raise RuntimeError(
                        "Ошибка OCR для всех языковых пакетов: "
                        + "; ".join(_ocr_cascade_errors)
                    )

                if ocr_text.strip():
                    results.append(ocr_text)
                    pages_ok += 1

            except Exception as exc:  # noqa: BLE001
                last_error = str(exc)
                logger.debug("Сбой OCR на странице %d файла %s: %s", idx + 1, doc_name, exc)
                continue

        final_text = "\n\n".join(results) if results else None
        err_msg = last_error if (not pages_ok and len(page_indices) > 0) else None
        return final_text, pages_ok > 0, err_msg
