"""Document parsers for multi-format ingestion."""

from __future__ import annotations

import logging
from pathlib import Path
from typing import Any

logger = logging.getLogger(__name__)


class DocumentParser:
    """Parse PDF, DOCX, PPTX, HTML, and Markdown files to text."""

    SUPPORTED_EXTENSIONS = {".pdf", ".docx", ".pptx", ".html", ".md"}
    MAX_FILE_SIZE = 50 * 1024 * 1024

    def can_parse(self, path: str | Path) -> bool:
        return Path(path).suffix.lower() in self.SUPPORTED_EXTENSIONS

    def parse(self, path: str | Path) -> dict[str, Any]:
        """Parse a document file to text + metadata."""
        path = Path(path)
        if not path.exists():
            return {"text": "", "error": "File not found"}
        if path.stat().st_size > self.MAX_FILE_SIZE:
            return {"text": "", "error": "File too large"}

        ext = path.suffix.lower()
        try:
            if ext == ".pdf":
                return self._parse_pdf(path)
            if ext == ".docx":
                return self._parse_docx(path)
            if ext == ".pptx":
                return self._parse_pptx(path)
            if ext == ".html":
                return self._parse_html(path)
            if ext == ".md":
                return {
                    "text": path.read_text(errors="replace"),
                    "format": "markdown",
                    "pages": 1,
                }
        except ImportError as exc:
            return {"text": "", "error": f"Missing dependency: {exc}"}
        except Exception as exc:
            logger.warning("Failed to parse %s: %s", path, exc)
            return {"text": "", "error": str(exc)}

        return {"text": "", "error": "Unsupported format"}

    def _parse_pdf(self, path: Path) -> dict[str, Any]:
        from pypdf import PdfReader

        reader = PdfReader(str(path))
        pages: list[str] = []
        for page in reader.pages:
            text = page.extract_text() or ""
            if text.strip():
                pages.append(text)

        meta = dict(reader.metadata) if reader.metadata else {}
        return {
            "text": "\n\n---\n\n".join(pages),
            "format": "pdf",
            "pages": len(reader.pages),
            "metadata": meta,
        }

    def _parse_docx(self, path: Path) -> dict[str, Any]:
        from docx import Document

        doc = Document(str(path))
        paragraphs = [p.text for p in doc.paragraphs if p.text.strip()]
        return {
            "text": "\n\n".join(paragraphs),
            "format": "docx",
            "pages": max(1, len(paragraphs) // 25),
            "paragraph_count": len(paragraphs),
        }

    def _parse_pptx(self, path: Path) -> dict[str, Any]:
        from pptx import Presentation

        prs = Presentation(str(path))
        slides_text: list[str] = []
        for i, slide in enumerate(prs.slides):
            texts: list[str] = []
            for shape in slide.shapes:
                text = getattr(shape, "text", "")
                if isinstance(text, str) and text.strip():
                    texts.append(text)
            if texts:
                slides_text.append(f"[Slide {i + 1}]\n" + "\n".join(texts))

        return {
            "text": "\n\n---\n\n".join(slides_text),
            "format": "pptx",
            "pages": len(prs.slides),
            "slide_count": len(prs.slides),
        }

    def _parse_html(self, path: Path) -> dict[str, Any]:
        import re

        html = path.read_text(errors="replace")
        text = re.sub(r"<script[^>]*>.*?</script>", "", html, flags=re.DOTALL)
        text = re.sub(r"<style[^>]*>.*?</style>", "", text, flags=re.DOTALL)
        text = re.sub(r"<[^>]+>", " ", text)
        text = re.sub(r"\s+", " ", text).strip()
        return {"text": text, "format": "html", "pages": 1}
