"""Extract plain text from uploaded documents.

TXT/MD are decoded directly; PDF and DOCX use optional libraries imported lazily
so they are only required when those formats are actually ingested.
"""

from __future__ import annotations

import io
import os

SUPPORTED_EXTENSIONS = {".txt", ".md", ".markdown", ".pdf", ".docx"}


class UnsupportedDocumentError(Exception):
    """Raised when a document's type cannot be parsed."""


def _ext(filename: str) -> str:
    return os.path.splitext(filename)[1].lower()


def _parse_pdf(data: bytes) -> str:
    try:
        from pypdf import PdfReader
    except ImportError as exc:  # pragma: no cover - exercised only without pypdf
        raise UnsupportedDocumentError("pypdf is required to ingest PDF files") from exc
    reader = PdfReader(io.BytesIO(data))
    return "\n\n".join((page.extract_text() or "") for page in reader.pages)


def _parse_docx(data: bytes) -> str:
    try:
        import docx
    except ImportError as exc:  # pragma: no cover - exercised only without python-docx
        raise UnsupportedDocumentError("python-docx is required to ingest DOCX files") from exc
    document = docx.Document(io.BytesIO(data))
    return "\n\n".join(p.text for p in document.paragraphs)


def extract_text(filename: str, data: bytes) -> str:
    ext = _ext(filename)
    if ext in {".txt", ".md", ".markdown"}:
        return data.decode("utf-8", errors="replace")
    if ext == ".pdf":
        return _parse_pdf(data)
    if ext == ".docx":
        return _parse_docx(data)
    raise UnsupportedDocumentError(f"unsupported document type: {ext or '(no extension)'}")
