"""Abstract base class for platform-specific CRDT builders.

This module defines the BaseCRDTBuilder ABC that constructs pycrdt Doc
objects from parsed document models.
"""

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Any

from pycrdt import Doc, XmlElement, XmlFragment, XmlText

from marqetive.utils.crdt.models import ParsedDocument


class BaseCRDTBuilder[T: ParsedDocument](ABC):
    """Abstract base class for building CRDT documents from parsed models.

    Type Parameters:
        T: The parsed document type this builder handles.
    """

    @property
    @abstractmethod
    def platform_name(self) -> str:
        """Return the platform name for this builder."""
        ...

    @property
    @abstractmethod
    def root_node_type(self) -> str:
        """Return the root node type this builder creates."""
        ...

    @abstractmethod
    def build_document(self, parsed: T, fragment_name: str = "default") -> Doc[Any]:
        """Build a pycrdt Doc from a parsed document model.

        Args:
            parsed: The parsed document model to convert.
            fragment_name: Name of the XML fragment in the Doc.

        Returns:
            A pycrdt Doc containing the built CRDT structure.
        """
        ...

    def _build_text_paragraphs(self, text: str) -> list[XmlElement]:
        """Split text on newlines, create one paragraph per line.

        Args:
            text: The text content to split into paragraphs.

        Returns:
            List of XmlElement paragraph nodes.
        """
        if not text:
            return [XmlElement("paragraph")]
        lines = text.split("\n")
        paragraphs: list[XmlElement] = []
        for line in lines:
            if line:
                paragraphs.append(XmlElement("paragraph", contents=[XmlText(line)]))
            else:
                paragraphs.append(XmlElement("paragraph"))
        return paragraphs

    def _build_media_attribute(self, media: list[str]) -> str:
        """Join media URLs with spaces matching parser expectation.

        Args:
            media: List of media URL strings.

        Returns:
            Space-separated URL string.
        """
        return " ".join(media)

    def _create_doc_with_fragment(
        self, fragment_name: str, children: list[XmlElement]
    ) -> Doc[Any]:
        """Create a Doc with a named XmlFragment containing children.

        Args:
            fragment_name: Name for the fragment in the Doc.
            children: XmlElement nodes to include.

        Returns:
            A pycrdt Doc with the fragment set.
        """
        doc: Doc[Any] = Doc()
        doc[fragment_name] = XmlFragment(init=children)
        return doc
