"""Builder for ``<Fields>`` and ``<Field>`` elements controlling which fields are returned."""
import xml.etree.ElementTree as ET
from typing import Literal

from ecmind_blue_client import SystemFields
from ecmind_blue_client.ecm.builder._common import DmsQueryFieldSchemaT


class DmsQueryFields:
    """Represents the ``<Fields>`` element, defining which index fields are returned in the result set.

    When used as a context manager, ``field_schema`` is automatically set to ``DEF`` on exit if
    at least one field was added and no schema was explicitly provided.
    """

    def __init__(self, parent: ET.Element, field_schema: DmsQueryFieldSchemaT | None) -> None:
        """
        Args:
            parent (ET.Element): The parent XML element (e.g. ``<ObjectType>``).
            field_schema (DmsQueryFieldSchemaT | None): Explicit field schema
                (``DEF``, ``ALL``, ``ALLREL``, ``MIN``). Pass ``None`` to let the context
                manager auto-set ``DEF`` when fields are added.
        """
        self._parent_node = parent
        self._field_schema = field_schema
        self._field_count = 0

        self._fields_node = ET.SubElement(self._parent_node, "Fields")
        if self._field_schema:
            self._fields_node.attrib["field_schema"] = self._field_schema

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        if self._field_schema is None and self._field_count > 0:
            self._fields_node.attrib["field_schema"] = "DEF"

    def field(
        self,
        internal_name: str | SystemFields,
        sortpos: int = 0,
        sortorder: Literal["ASC", "DESC"] = "ASC",
        link_name: str | None = None,
        dbname: str | None = None,
        osguid: str | None = None,
    ):
        """Adds a ``<Field>`` element to the result field list.

        Args:
            internal_name (str | SystemFields): Internal field name or a ``SystemFields`` enum member.
                System fields (``SystemFields``) automatically set the ``system="1"`` attribute.
            sortpos (int): Sort position. 0 means no sorting on this field. Defaults to 0.
            sortorder (Literal["ASC", "DESC"]): Sort direction. Only used when ``sortpos > 0``.
                Defaults to ``"ASC"``.
            link_name (str | None): Optional link name making this field's value available as
                input for external object conditions (``LinkedValue`` references). Defaults to ``None``.
            dbname (str | None): Database column name — alternative identifier to ``internal_name``.
                Prefer ``internal_name`` whenever possible. Defaults to ``None``.
            osguid (str | None): GUID — alternative identifier to ``internal_name``.
                Prefer ``internal_name`` whenever possible. Defaults to ``None``.
        """
        system = "1" if isinstance(internal_name, SystemFields) else "0"
        internal_name = internal_name.name if isinstance(internal_name, SystemFields) else internal_name

        field_node = ET.SubElement(self._fields_node, "Field", {"internal_name": internal_name, "system": system})
        if sortpos > 0:
            field_node.attrib["sortpos"] = str(sortpos)
            field_node.attrib["sortorder"] = sortorder

        if link_name is not None:
            field_node.attrib["link_name"] = link_name
        if dbname is not None:
            field_node.attrib["dbname"] = dbname
        if osguid is not None:
            field_node.attrib["osguid"] = osguid

        self._field_count += 1
