from __future__ import annotations

"""Optional DOCX (Word) parser.

This parser uses the :mod:`python-docx` package *if available* to extract
headings and paragraphs from ``.docx`` files.

It is designed as an optional enhancement; if ``python-docx`` is not
installed, using this parser will raise a clear :class:`ParseError`.
"""

from pathlib import Path
from typing import List

from ..core.models import DocumentNode, DocumentTree, NodeType, RawDocument, SourceType
from .base import BaseParser, ParseError


class DocxParser(BaseParser):
    """DOCX parser backed by :mod:`python-docx` when available."""

    def supports(self, raw: RawDocument) -> bool:
        if raw.source_type is not SourceType.FILE:
            return False
        path = str(raw.metadata.get("path", "")).lower()
        return path.endswith(".docx")

    def parse(self, raw: RawDocument) -> DocumentTree:
        path_str = raw.metadata.get("path")
        if not path_str:
            raise ParseError("DOCX parser requires 'path' in raw.metadata")

        try:  # local import to keep dependency optional
            import docx  # type: ignore[import-not-found]
        except Exception as exc:  # pragma: no cover - environment-specific
            raise ParseError(
                "DOCX support requires the 'python-docx' package. "
                "Install it (e.g. `pip install python-docx`) or skip DOCX parsing."
            ) from exc

        doc_path = Path(path_str)
        try:
            document = docx.Document(str(doc_path))
        except Exception as exc:  # pragma: no cover - depends on test files
            raise ParseError(f"Failed to open DOCX file {doc_path!r}: {exc}") from exc

        root = DocumentNode(
            id=f"{raw.id}#root",
            node_type=NodeType.DOCUMENT,
            text=None,
            metadata={"parser": "docx"},
        )

        current_section = root
        counter = 0

        for para in document.paragraphs:
            text = (para.text or "").strip()
            if not text:
                continue

            style_name = (getattr(para.style, "name", "") or "").lower()
            if style_name.startswith("heading"):
                counter += 1
                section = DocumentNode(
                    id=f"{raw.id}#s{counter}",
                    node_type=NodeType.SECTION,
                    text=text,
                    metadata={"style": style_name},
                )
                root.children.append(section)
                current_section = section
            else:
                counter += 1
                parent = current_section or root
                node = DocumentNode(
                    id=f"{raw.id}#p{counter}",
                    node_type=NodeType.PARAGRAPH,
                    text=text,
                    metadata={"style": style_name},
                )
                parent.children.append(node)

        return DocumentTree(root=root, metadata={"source_id": raw.id, "parser": "docx"})

