#/app/aroflo_connector_app/zones/trackingcentres/cli.py
from __future__ import annotations

import json
from typing import Any, Dict, List, Optional, Callable

import click


def _echo(result: Any) -> None:
    if isinstance(result, (dict, list)):
        click.echo(json.dumps(result, indent=2, ensure_ascii=False))
    else:
        click.echo(str(result))


def _available_ops(zone: Any) -> List[str]:
    ops = getattr(zone, "operations", [])
    return sorted([o.code for o in ops])


def _run(zone: Any, op_code: str, params: Dict[str, Any]) -> Any:
    available = set(_available_ops(zone))
    if op_code not in available:
        click.echo(f"❌ Operación '{op_code}' no existe en zona '{zone.code}'.")
        click.echo("Operaciones disponibles:")
        for c in _available_ops(zone):
            click.echo(f"  - {c}")
        raise SystemExit(2)
    return zone.execute(op_code, params=params)


def _add_optional(
    params: Dict[str, Any],
    *,
    pagesize: Optional[int],
    order: Optional[str],
) -> Dict[str, Any]:
    """
    AroFlo usa pageSize como parámetro de entrada para tamaño de página.
    """
    if pagesize is not None:
        params["pageSize"] = pagesize
    if order:
        params["order"] = order
    return params


def _common_list_options(fn: Callable[..., Any]) -> Callable[..., Any]:
    """
    Decorador para opciones comunes de list:
    - page, where, order, pageSize (AroFlo) y raw
    """
    fn = click.option("--page", default=1, type=int, show_default=True)(fn)
    fn = click.option(
        "--where",
        default=None,
        show_default=True,
        help="Cláusula WHERE estilo AroFlo (opcional). Si no se envía, AroFlo retorna el listado por defecto.",
    )(fn)
    fn = click.option("--order", default=None, show_default=True, help="ORDER estilo AroFlo. Ej: name|asc")(fn)
    fn = click.option(
        "--pagesize",
        type=int,
        default=None,
        show_default=True,
        help="Cantidad de registros por página (AroFlo pageSize). Ej: 5, 20, 50.",
    )(fn)
    fn = click.option("--raw", is_flag=True, help="Devuelve respuesta cruda + meta debug.")(fn)
    return fn


def register_cli(root: click.Group, zone: Any) -> None:
    @root.group(name=zone.code)
    def trackingcentres_group():
        """Operaciones de la zona trackingcentres (Tracking Centres)."""

    # -------------------------
    # BASE
    # -------------------------
    @trackingcentres_group.command("list")
    @_common_list_options
    def list_cmd(
        page: int,
        where: Optional[str],
        order: Optional[str],
        pagesize: Optional[int],
        raw: bool,
    ):
        params = _add_optional(
            {"page": page, "where": where, "raw": raw},
            pagesize=pagesize,
            order=order,
        )
        _echo(_run(zone, "list_trackingcentres", params))

    @trackingcentres_group.command("get")
    @click.option("--trackingcentreid", required=True, help="TrackingCentreID codificado (AroFlo).")
    @click.option("--raw", is_flag=True, help="Devuelve respuesta cruda + meta debug.")
    def get_cmd(trackingcentreid: str, raw: bool):
        _echo(_run(zone, "get_trackingcentre", {"trackingcentreid": trackingcentreid, "raw": raw}))

    # -------------------------
    # RESOLVE (name -> trackingcentreid)
    # -------------------------
    @trackingcentres_group.command("resolve")
    @click.option("--name", required=True, help="Nombre exacto del tracking centre.")
    @click.option("--orgid", required=False, default=None, help="OrgID para desambiguar (opcional).")
    @click.option("--raw", is_flag=True, help="Devuelve respuesta cruda + meta debug.")
    def resolve_cmd(name: str, orgid: Optional[str], raw: bool):
        params: Dict[str, Any] = {"name": name, "raw": raw}
        if orgid:
            params["orgid"] = orgid
        _echo(_run(zone, "resolve_trackingcentre_id_by_name", params))
