# apps/aroflo_connector_app/zones/users/join_customfields.py
from __future__ import annotations

from typing import Any, Dict, List
from urllib.parse import urlencode

from ..base import ZoneOperation, ParamSpec


def get_operations() -> List[ZoneOperation]:
    """
    Operaciones de la sección 'JOIN customfields' bajo Users.
    """
    return [
        ZoneOperation(
            code="get_users_with_customfields",
            label="Get Users and customfields",
            description=(
                "Devuelve usuarios activos y sus customfields usando "
                "zone=users&join=customfields."
            ),
            http_method="GET",
            side_effect="read",
            idempotent=True,
            default_params={
                "where": "and|archived|=|false",
                "page": 1,
            },
            params=[
                ParamSpec(
                    name="where",
                    type="string",
                    required=False,
                    description=(
                        "Cláusula WHERE estilo AroFlo. Por defecto "
                        "'and|archived|=|false'."
                    ),
                ),
                ParamSpec(
                    name="page",
                    type="integer",
                    required=False,
                    description="Número de página (1..N).",
                ),
            ],
        ),
        ZoneOperation(
            code="update_user_customfield",
            label="Update Users customfield",
            description=(
                "Actualiza el valor de un customfield específico de un usuario "
                "usando POSTXML en la zona 'users'."
            ),
            http_method="POST",
            side_effect="write",
            idempotent=True,
            params=[
                ParamSpec(
                    name="userid",
                    type="string",
                    required=True,
                    description="ID codificado del usuario en AroFlo.",
                ),
                ParamSpec(
                    name="fieldid",
                    type="string",
                    required=True,
                    description="ID del customfield a actualizar.",
                ),
                ParamSpec(
                    name="value",
                    type="string",
                    required=True,
                    description=(
                        "Nuevo valor del customfield. Depende del tipo "
                        "(checkbox, datefield, text, etc.)."
                    ),
                ),
                ParamSpec(
                    name="postxml",
                    type="string",
                    required=False,
                    description=(
                        "XML completo a enviar en el campo 'postxml'. Si se "
                        "envía, se usará directamente en lugar de construirlo "
                        "a partir de userid/fieldid/value."
                    ),
                ),
            ],
        ),
        ZoneOperation(
            code="create_user_with_customfields",
            label="Create User with Custom Fields",
            description=(
                "Crea un usuario (o varios) junto con sus customfields usando "
                "POSTXML en la zona 'users'."
            ),
            http_method="POST",
            side_effect="write",
            idempotent=False,
            params=[
                ParamSpec(
                    name="user",
                    type="object",
                    required=False,
                    description=(
                        "Diccionario con los datos del usuario "
                        "(givennames, surname, username, orgid, customfields, "
                        "permissiongroups, etc.). Si no se envía, se espera "
                        "que se pase 'postxml' ya construido."
                    ),
                ),
                ParamSpec(
                    name="postxml",
                    type="string",
                    required=False,
                    description=(
                        "XML completo con uno o varios <user> a crear. Si se "
                        "envía, se usará directamente en lugar de construirlo "
                        "a partir de 'user'."
                    ),
                ),
            ],
        ),
    ]


def supports(operation_code: str) -> bool:
    return any(op.code == operation_code for op in get_operations())


# ---------------------------------------------------------------------
#  Helpers XML (para futuros POST)
# ---------------------------------------------------------------------


def _build_update_customfield_postxml(userid: str, fieldid: str, value: str) -> str:
    return (
        "<users>"
        "<user>"
        f"<userid>{userid}</userid>"
        "<customfields>"
        "<customfield>"
        f"<fieldid>{fieldid}</fieldid>"
        "<value><![CDATA[ " + value + " ]]></value>"
        "</customfield>"
        "</customfields>"
        "</user>"
        "</users>"
    )


def _build_create_user_postxml_from_dict(user: Dict[str, Any]) -> str:
    from typing import List as _List

    simple_fields = [
        "givennames",
        "surname",
        "username",
        "password",
        "email",
        "email2",
        "phone",
        "fax",
        "mobile",
        "accesstype",
    ]

    xml_parts: _List[str] = []
    xml_parts.append("<users><user>")

    # Campos simples
    for key in simple_fields:
        value = user.get(key)
        if value not in (None, ""):
            xml_parts.append(f"<{key}>{value}</{key}>")

    # Org
    orgid = user.get("orgid")
    if orgid:
        xml_parts.append("<org>")
        xml_parts.append(f"<orgid>{orgid}</orgid>")
        xml_parts.append("</org>")

    # Permission Groups
    perm_groups = user.get("permissiongroups") or []
    if perm_groups:
        xml_parts.append("<permissiongroups>")
        for pg in perm_groups:
            groupid = pg.get("groupid")
            if not groupid:
                continue
            xml_parts.append("<permissiongroup>")
            xml_parts.append(f"<groupid>{groupid}</groupid>")
            xml_parts.append("</permissiongroup>")
        xml_parts.append("</permissiongroups>")

    # Customfields
    customfields = user.get("customfields") or []
    if customfields:
        xml_parts.append("<customfields>")
        for cf in customfields:
            fieldid = cf.get("fieldid")
            name = cf.get("name")
            ctype = cf.get("type")
            value = cf.get("value", "")

            xml_parts.append("<customfield>")
            if fieldid:
                xml_parts.append(f"<fieldid>{fieldid}</fieldid>")
            if name:
                xml_parts.append(f"<name>{name}</name>")
            if ctype:
                xml_parts.append(f"<type>{ctype}</type>")
            xml_parts.append("<value><![CDATA[ " + str(value) + " ]]></value>")
            xml_parts.append("</customfield>")
        xml_parts.append("</customfields>")

    xml_parts.append("</user></users>")
    return "".join(xml_parts)


# ---------------------------------------------------------------------
#  Ejecutor sección
# ---------------------------------------------------------------------


def execute(operation_code: str, client: Any, params: Dict[str, Any]) -> Any:
    """
    Implementa las llamadas reales a AroFlo para JOIN customfields.

    Por ahora solo está implementado el GET (Get Users and customfields),
    que ya probamos con la CLI. Los POST se pueden activar en una fase
    siguiente.
    """
    # ---------- GET: Get Users and customfields ----------
    if operation_code == "get_users_with_customfields":
        where = params.get("where", "and|archived|=|false")
        page = params.get("page", 1)

        params_list = [
            ("zone", "users"),
            ("where", where),
            ("join", "customfields"),
            ("page", str(page)),
        ]
        var_string = urlencode(params_list)
        query_params = dict(params_list)

        return client.request(
            "",
            method="GET",
            params=query_params,
            var_string=var_string,
        )

    # ---------- POST: Update Users customfield ----------
    if operation_code == "update_user_customfield":
        # Por ahora no lo activamos para no mezclar muchas cosas.
        # Cuando lo vayamos a usar, solo descomentamos y probamos con CLI.
        raise NotImplementedError(
            "[Users.join_customfields] 'update_user_customfield' aún no implementado."
        )

        # Ejemplo de implementación futura:
        # if "postxml" in params:
        #     postxml = params["postxml"]
        # else:
        #     userid = params["userid"]
        #     fieldid = params["fieldid"]
        #     value = params["value"]
        #     postxml = _build_update_customfield_postxml(userid, fieldid, value)
        #
        # form_data = {
        #     "zone": "users",
        #     "postxml": postxml,
        # }
        # return client.request(
        #     "",
        #     method="POST",
        #     data=form_data,
        # )

    # ---------- POST: Create User with Custom Fields ----------
    if operation_code == "create_user_with_customfields":
        raise NotImplementedError(
            "[Users.join_customfields] 'create_user_with_customfields' aún no implementado."
        )

        # Ejemplo futuro:
        # if "postxml" in params:
        #     postxml = params["postxml"]
        # else:
        #     user_data = params["user"]
        #     postxml = _build_create_user_postxml_from_dict(user_data)
        #
        # form_data = {
        #     "zone": "users",
        #     "postxml": postxml,
        # }
        # return client.request(
        #     "",
        #     method="POST",
        #     data=form_data,
        # )

    raise ValueError(f"[Users.join_customfields] Operación no soportada: {operation_code}")
