# apps/aroflo_connector_app/zones/users/base.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 principales de la zona Users (sin JOIN).
    """
    return [
        ZoneOperation(
            code="get_users",
            label="Get Users",
            description=(
                "Devuelve una lista paginada de usuarios usando la zona 'users' "
                "de AroFlo. Soporta filtros vía cláusula WHERE."
            ),
            http_method="GET",
            side_effect="read",
            idempotent=True,
            default_params={
                "where": "and|createdutc|>|2001-01-01",
                "page": 1,
            },
            params=[
                ParamSpec(
                    name="where",
                    type="string",
                    required=False,
                    description=(
                        "Cláusula WHERE estilo AroFlo, por ejemplo "
                        "'and|archived|=|false'. Si no se envía, se usa el "
                        "valor por defecto configurado."
                    ),
                ),
                ParamSpec(
                    name="page",
                    type="integer",
                    required=False,
                    description="Número de página (1..N) para paginación.",
                ),
            ],
        ),
        ZoneOperation(
            code="get_users_with_position",
            label="Get Users with set position",
            description=(
                "Devuelve usuarios filtrados por 'position' u otros criterios "
                "vía cláusula WHERE."
            ),
            http_method="GET",
            side_effect="read",
            idempotent=True,
            default_params={
                "page": 1,
            },
            params=[
                ParamSpec(
                    name="position",
                    type="string",
                    required=False,
                    description=(
                        "Valor del campo 'position' para filtrar usuarios. "
                        "Si se envía, se combinará en la cláusula WHERE."
                    ),
                ),
                ParamSpec(
                    name="where",
                    type="string",
                    required=False,
                    description=(
                        "Cláusula WHERE base. Si se incluye 'position', se "
                        "insertará automáticamente la condición sobre ese campo."
                    ),
                ),
                ParamSpec(
                    name="page",
                    type="integer",
                    required=False,
                    description="Número de página (1..N) para paginación.",
                ),
            ],
        ),
        ZoneOperation(
            code="get_user",
            label="Get a specific User",
            description=(
                "Obtiene un usuario específico filtrando por 'userid' usando "
                "la zona 'users' de AroFlo."
            ),
            http_method="GET",
            side_effect="read",
            idempotent=True,
            params=[
                ParamSpec(
                    name="userid",
                    type="string",
                    required=True,
                    description="ID codificado del usuario en AroFlo.",
                ),
            ],
        ),
        ZoneOperation(
            code="create_user",
            label="Create User",
            description=(
                "Crea uno o varios usuarios en AroFlo usando POSTXML con la "
                "estructura <users><user>...</user></users>."
            ),
            http_method="POST",
            side_effect="write",
            idempotent=False,
            params=[
                ParamSpec(
                    name="postxml",
                    type="string",
                    required=True,
                    description=(
                        "XML completo con la definición de uno o varios "
                        "usuarios a crear, según la documentación de AroFlo."
                    ),
                ),
            ],
        ),
        ZoneOperation(
            code="update_mobile",
            label="Update Users mobile number",
            description=(
                "Actualiza el número de móvil de un usuario usando POSTXML "
                "en la zona 'users'."
            ),
            http_method="POST",
            side_effect="write",
            idempotent=True,
            params=[
                ParamSpec(
                    name="postxml",
                    type="string",
                    required=True,
                    description=(
                        "XML con la estructura necesaria para actualizar el "
                        "móvil (userid + mobile)."
                    ),
                ),
            ],
        ),
    ]


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


def _request_with_params(client: Any, params_list: List[tuple]) -> Any:
    """
    Helper para construir var_string + params y llamar client.request()
    de forma consistente (igual que el ping / users-raw).
    """
    from urllib.parse import urlencode as _urlencode

    var_string = _urlencode(params_list)
    query_params = dict(params_list)

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


def execute(operation_code: str, client: Any, params: Dict[str, Any]) -> Any:
    """
    Implementación de las operaciones base de Users.

    Por ahora solo implementamos las operaciones de lectura (GET).
    Las operaciones de escritura (POST) quedan como NotImplemented
    hasta que definamos bien el XML/postxml.
    """
    # ---------------------- GET: get_users ---------------------- #
    if operation_code == "get_users":
        where = params.get("where", "and|createdutc|>|2001-01-01")
        page = params.get("page", 1)

        params_list = [
            ("zone", "users"),
            ("where", where),
            ("page", str(page)),
        ]
        return _request_with_params(client, params_list)

    # --------------- GET: get_users_with_position --------------- #
    if operation_code == "get_users_with_position":
        where = params.get("where")
        position = params.get("position")
        page = params.get("page", 1)

        # Si no viene WHERE, usamos uno base
        if not where:
            where = "and|archived|=|false"

        # Si viene position, la agregamos a la cláusula WHERE
        if position:
            # Esto asume que la convención es: and|position|=|VALUE
            where = f"{where};and|position|=|{position}"

        params_list = [
            ("zone", "users"),
            ("where", where),
            ("page", str(page)),
        ]
        return _request_with_params(client, params_list)

    # ---------------------- GET: get_user ------------------------ #
    if operation_code == "get_user":
        userid = params["userid"]

        where = f"and|userid|=|{userid}"
        params_list = [
            ("zone", "users"),
            ("where", where),
            ("page", "1"),
        ]
        return _request_with_params(client, params_list)

    # -------------------- POST: create_user ---------------------- #
    if operation_code == "create_user":
        # Aquí podríamos construir el XML a partir de un dict,
        # pero para la Fase 1 preferimos que el caller pase `postxml` directo.
        raise NotImplementedError(
            "[Users.base] 'create_user' aún no implementado (requiere postxml)."
        )

    # ------------------- POST: update_mobile --------------------- #
    if operation_code == "update_mobile":
        raise NotImplementedError(
            "[Users.base] 'update_mobile' aún no implementado (requiere postxml)."
        )

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

