#/app/aroflo_connector_app/zones/users/join_by_email.py
from __future__ import annotations

from typing import Any, Dict, List, Optional, Tuple

from ..base import ZoneOperation, ParamSpec
from ._join_utils import request, raw_wrap, coerce_page_size, coerce_order, build_list_params

OP_CODE = "get_user_by_email"


def get_operations() -> List[ZoneOperation]:
    return [
        ZoneOperation(
            code=OP_CODE,
            label="Get User by Email",
            description=(
                "Busca un usuario por email/email2 haciendo paginación por la API (zone=users) y filtrando en Python. "
                "Útil cuando AroFlo ignora where con |=| o no soporta |like|."
            ),
            http_method="GET",
            side_effect="read",
            idempotent=True,
            default_params={
                "email": None,
                "where": "and|createdutc|>|2001-01-01",
                "order": None,
                "page": 1,
                "pageSize": None,
                "max_pages": 50,
                "return_all": False,
                "raw": False,
            },
            params=[
                ParamSpec("email", "string", True, "Correo a buscar (match exacto, case-insensitive)."),
                ParamSpec("where", "string", False, "WHERE base para paginar (no se usa para filtrar email)."),
                ParamSpec("order", "string", False, "ORDER estilo AroFlo. Ej: createdutc|desc"),
                ParamSpec("page", "integer", False, "Página inicial (default 1)."),
                ParamSpec("pageSize", "integer", False, "Tamaño de página (AroFlo pageSize)."),
                ParamSpec("max_pages", "integer", False, "Límite de páginas a recorrer para evitar loops."),
                ParamSpec("return_all", "boolean", False, "Si true, devuelve todos los matches (no solo el primero)."),
                ParamSpec("raw", "boolean", False, "Si true, incluye meta debug + páginas consultadas."),
            ],
            category="users",
            use_cases=["Buscar usuario por email cuando WHERE no funciona", "Resolver userid desde email"],
            risk_level="low",
            requires_confirmation=False,
        )
    ]


def supports(operation_code: str) -> bool:
    return operation_code == OP_CODE


def _norm_email(v: Any) -> str:
    return str(v or "").strip().lower()


def _extract_users(resp: Any) -> List[Dict[str, Any]]:
    """
    Intenta extraer la lista de users de respuestas típicas de AroFlo.
    Soporta:
      - resp["zoneresponse"]["users"]
      - resp["data"]["zoneresponse"]["users"] (si alguien ya wrappeó)
    """
    if not isinstance(resp, dict):
        return []

    zr = None
    if isinstance(resp.get("zoneresponse"), dict):
        zr = resp["zoneresponse"]
    elif isinstance(resp.get("data"), dict) and isinstance(resp["data"].get("zoneresponse"), dict):
        zr = resp["data"]["zoneresponse"]

    if not zr:
        return []

    users = zr.get("users")
    if isinstance(users, list):
        return [u for u in users if isinstance(u, dict)]
    return []


def execute(operation_code: str, client: Any, params: Dict[str, Any]) -> Any:
    if operation_code != OP_CODE:
        raise ValueError(f"[Users.join_by_email] Operación no soportada: {operation_code}")

    raw = bool(params.get("raw", False))
    email = _norm_email(params.get("email"))
    if not email:
        raise ValueError("email es requerido.")

    where = str(params.get("where") or "and|createdutc|>|2001-01-01")
    order = coerce_order(params)
    page_size = coerce_page_size(params)

    page = int(params.get("page", 1))
    if page < 1:
        raise ValueError("page debe ser >= 1.")

    max_pages = int(params.get("max_pages", 50))
    if max_pages < 1:
        raise ValueError("max_pages debe ser >= 1.")

    return_all = bool(params.get("return_all", False))

    pages_visited: List[int] = []
    matches: List[Dict[str, Any]] = []

    # Paginación defensiva: recorremos hasta max_pages, o hasta que no haya users.
    for i in range(max_pages):
        current_page = page + i
        pages_visited.append(current_page)

        params_list = build_list_params(
            zone="users",
            where=where,
            join=None,
            order=order,
            page=current_page,
            pageSize=page_size,
        )

        resp = request(client, "GET", params_list)

        users = _extract_users(resp)
        if not users:
            break

        for u in users:
            e1 = _norm_email(u.get("email"))
            e2 = _norm_email(u.get("email2"))
            if email and (email == e1 or email == e2):
                matches.append(u)
                if not return_all:
                    # Salida temprana
                    result = {
                        "match": u,
                        "matches": 1,
                        "email": email,
                        "pages_visited": pages_visited,
                    }
                    return raw_wrap(result, [("op", OP_CODE), ("email", email)]) if raw else result

    result = {
        "match": (matches[0] if matches else None),
        "matches": len(matches),
        "all_matches": matches if return_all else None,
        "email": email,
        "pages_visited": pages_visited,
    }
    return raw_wrap(result, [("op", OP_CODE), ("email", email)]) if raw else result
