"""Abstract base class for parsed ``<ObjectType>`` elements in DMSContent responses."""
import xml.etree.ElementTree as ET
from abc import ABC

from ecmind_blue_client.ecm.parser._dms_content_archive import DmsContentArchive
from ecmind_blue_client.ecm.parser._dms_content_statistics import DmsContentStatistics


class DmsContentObjectType(ABC):
    """Abstract base class representing an ``<ObjectType>`` element in a DMSContent response.

    An object type groups objects (HOL) or rows (LOL) that share the same archive schema.
    Subclasses ``DmsContentObjectTypeHol`` and ``DmsContentObjectTypeLol`` provide the
    concrete iteration methods for their respective response formats.
    """

    def __init__(self, node: ET.Element, archive: ET.Element):
        self._node = node
        self._archive = archive

    @property
    def name(self) -> str:
        """Display name of the object type."""
        return self._node.get("name", "")

    @property
    def id(self) -> int:
        """Numeric ID of the object type."""
        return int(self._node.get("id", "-1"))

    @property
    def cotype(self) -> int:
        """Numeric co-type identifier (sub-classification within a main type)."""
        return int(self._node.get("cotype", "-1"))

    @property
    def osguid(self) -> str:
        """Object storage GUID of the object type."""
        return self._node.get("osguid", "")

    @property
    def internal_name(self) -> str:
        """Internal (programmatic) name of the object type."""
        return self._node.get("internal_name", "")

    @property
    def type(self) -> str:
        """Type string of the object type as returned by the server."""
        return self._node.get("type", "")

    @property
    def modul(self) -> str:
        """Document module identifier associated with this object type."""
        return self._node.get("modul", "")

    @property
    def table(self) -> str:
        """Database table name backing this object type."""
        return self._node.get("table", "")

    @property
    def maintype(self) -> int:
        """Numeric main type of the object type (folder, register, document)."""
        return int(self._node.get("maintype", "-1"))

    @property
    def encrypted(self) -> int:
        """Encryption flag: ``1`` if the object type stores encrypted data, ``0`` otherwise."""
        return int(self._node.get("encrypted", "0"))

    @property
    def alias(self) -> str:
        """Optional alias name for the object type."""
        return self._node.get("alias", "")

    @property
    def fulltext(self) -> int:
        """Fulltext flag: ``1`` if fulltext indexing is enabled for this object type."""
        return int(self._node.get("fulltext", "0"))

    @property
    def archive(self) -> DmsContentArchive:
        """The ``<Archive>`` (cabinet) that contains this object type."""
        return DmsContentArchive(
            self._archive.get("name", ""),
            int(self._archive.get("id", "-1")),
            self._archive.get("osguid", ""),
            self._archive.get("internal_name", ""),
        )

    @property
    def statistics(self) -> DmsContentStatistics:
        """Pagination statistics for this object type's result set.

        Raises:
            ValueError: If the ``<Statistics>`` element is absent.
        """
        statistics = self._node.find("Statistics")
        if statistics is None:
            raise ValueError("<Statistics> tag in <ObjectTpye> not found")
        return DmsContentStatistics(
            int(statistics.attrib["startpos"]), int(statistics.attrib["pagesize"]), int(statistics.attrib["total_hits"])
        )

    @property
    def sql_select(self) -> str:
        """The raw SQL SELECT statement for this query (requires ``sql=True`` in the query).

        Raises:
            ValueError: If the ``<SQL>/<Select>`` element is absent or empty.
        """
        sql_select = self._node.find("SQL/Select")
        if sql_select is None or not sql_select.text:
            raise ValueError("SQL Select is only available if sql=True is set")

        return sql_select.text
