"""Builder for ``<BaseParams>`` elements in DMSQuery XML."""
import xml.etree.ElementTree as ET
from datetime import date, datetime
from typing import Optional

from ecmind_blue_client.ecm.builder._common import (
    ArchiveStateT,
    DmsQueryFieldSchemaT,
    DmsQueryObjectSchemaT,
    LockedStateT,
)
from ecmind_blue_client.ecm.builder._dms_query_object_condition_group_or_condition_object import (
    DmsQueryUserValueT,
    _date_to_str,
    _write_user_value,
)


class DmsBaseParams:
    """
    Base class for FolderBaseParams, RegisterBaseParams, and DocumentBaseParams elements in the DMSQuery XML.

    Allows filtering by base properties such as creator, creation date range, modifier, modification date range,
    and owner. Optionally requests child objects.

    The XSD sequence for child elements is: ChildObjects → Creator → Created → Modifier → Modified → Owner.
    Methods must be called in this order to produce valid XML.
    """

    def __init__(self, parent: ET.Element, tag: str):
        self._node = ET.SubElement(parent, tag)

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        pass

    def child_objects(
        self, child_schema: DmsQueryObjectSchemaT = "DEF", export_depth: int = 0, field_schema: Optional[DmsQueryFieldSchemaT] = None
    ):
        """
        Requests child objects within the base params query. Must be called before any filter methods.

        Args:
            child_schema (DmsQueryObjectSchemaT): The schema for child objects. Defaults to "DEF".
            export_depth (int): The export depth. Defaults to 0.
            field_schema (Optional[DmsQueryFieldSchemaT]): The field schema for child objects. Defaults to None.

        Returns:
            DmsQueryChildObjects: A DmsQueryChildObjects instance.
        """
        from ecmind_blue_client.ecm.builder._dms_query_child_objects import DmsQueryChildObjects

        return DmsQueryChildObjects(self._node, child_schema, export_depth, field_schema)

    def creator(self, *values: DmsQueryUserValueT):
        """
        Adds a Creator condition to filter by the user who created the object. The XSD allows a maximum of 2 values.

        Args:
            *values (str | DmsQuerySpecialValue): Up to 2 user name values. Use DmsQuerySpecialValue.BENUTZER
                for the current user.
        """
        creator_node = ET.SubElement(self._node, "Creator")
        for value in values[:2]:
            _write_user_value(creator_node, value)

    def created(self, from_date: date | datetime | str, to_date: date | datetime | str):
        """
        Adds a Created date range condition to filter by the creation date.

        Args:
            from_date (date | datetime | str): Start of the creation date range.
                ``datetime`` → ``DD.MM.YYYY HH:MM:SS``, ``date`` → ``DD.MM.YYYY``, ``str`` unchanged.
            to_date (date | datetime | str): End of the creation date range.
        """
        created_node = ET.SubElement(self._node, "Created")
        ET.SubElement(created_node, "From").text = _date_to_str(from_date)
        ET.SubElement(created_node, "To").text = _date_to_str(to_date)

    def modifier(self, *values: DmsQueryUserValueT):
        """
        Adds a Modifier condition to filter by the user who last modified the object.

        Args:
            *values (str | DmsQuerySpecialValue): One or more user name values.
        """
        modifier_node = ET.SubElement(self._node, "Modifier")
        for value in values:
            _write_user_value(modifier_node, value)

    def modified(self, from_date: date | datetime | str, to_date: date | datetime | str):
        """
        Adds a Modified date range condition to filter by the last modification date.

        Args:
            from_date (date | datetime | str): Start of the modification date range.
                ``datetime`` → ``DD.MM.YYYY HH:MM:SS``, ``date`` → ``DD.MM.YYYY``, ``str`` unchanged.
            to_date (date | datetime | str): End of the modification date range.
        """
        modified_node = ET.SubElement(self._node, "Modified")
        ET.SubElement(modified_node, "From").text = _date_to_str(from_date)
        ET.SubElement(modified_node, "To").text = _date_to_str(to_date)

    def owner(self, *values: DmsQueryUserValueT, operator: str | None = None):
        """Adds an Owner condition to filter by the object owner.

        The boolean operator between multiple values is fixed to ``OR`` by the XSD schema.

        Args:
            *values (str | DmsQuerySpecialValue): One or more owner user name values.
            operator (str | None): Optional comparison operator applied to all values
                (e.g. ``"="`` or ``"<>"``). If ``None``, no operator attribute is written.
        """
        owner_node = ET.SubElement(self._node, "Owner")
        if operator is not None:
            owner_node.attrib["operator"] = operator
        for value in values:
            _write_user_value(owner_node, value)


class DmsFolderBaseParams(DmsBaseParams):
    """Folder search using base parameter filter elements (creator, created, modifier, modified, owner)."""

    def __init__(self, parent: ET.Element):
        super().__init__(parent, "FolderBaseParams")


class DmsRegisterBaseParams(DmsBaseParams):
    """Register search using base parameter filter elements (creator, created, modifier, modified, owner)."""

    def __init__(self, parent: ET.Element):
        super().__init__(parent, "RegisterBaseParams")


class DmsDocumentBaseParams(DmsBaseParams):
    """
    Document search using base parameter filter elements.

    Extends DmsBaseParams with archive state and lock state conditions. Per XSD sequence, archive_state() and
    locked() must be called after all base filter methods (creator, created, modifier, modified, owner).
    """

    def __init__(self, parent: ET.Element):
        super().__init__(parent, "DocumentBaseParams")

    def archive_state(self, *states: ArchiveStateT):
        """
        Adds an ArchiveState condition to filter by the archive state of documents.

        Args:
            *states (ArchiveStateT): One or more archive state values. Allowed values are:
                "ARCHIVED", "ARCHIVABLE", "NOT_ARCHIVABLE", "NO_PAGES", "PAGE_ERROR", "REFERENCE", "UNKNOWN".
        """
        archive_state_node = ET.SubElement(self._node, "ArchiveState")
        for state in states:
            ET.SubElement(archive_state_node, "ArchiveStateValue").text = state

    def locked(self, state: LockedStateT):
        """
        Adds a Locked condition to filter by the lock state of documents.

        Args:
            state (LockedStateT): The lock state value. Allowed values are:
                "UNLOCKED", "SELF", "OTHERS", "EXTERNAL".
        """
        locked_node = ET.SubElement(self._node, "Locked")
        ET.SubElement(locked_node, "LockStateValue").text = state
