# apps/aroflo_connector_app/zones/base.py
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional
from abc import ABC, abstractmethod


@dataclass
class ZoneOperation:
    """
    Describe una operación de una zona (por ejemplo: 'get_users', 'create_user').
    """
    code: str                   # código interno: "get_users"
    label: str                  # nombre legible: "Get Users"
    description: str = ""
    http_method: str = "GET"    # GET / POST / PUT / etc. (por si variamos)
    # Parámetros por defecto (por ejemplo maxpageresults, filtros base, etc.)
    default_params: Dict[str, Any] = field(default_factory=dict)


class Zone(ABC):
    """
    Clase base para cualquier 'zona' (Users, Clients, LastUpdate, etc.).
    Cada zona conoce sus operaciones y cómo traducirlas a llamadas AroFlo.
    """

    #: Código único de la zona, por ejemplo "users", "clients", "lastupdate"
    code: str
    #: Nombre legible de la zona
    label: str
    #: Descripción corta para /zones
    description: str

    def __init__(self, client: Any) -> None:
        # client será una instancia de AroFloClient (ya existente en tu app)
        self.client = client

    # ---- Descripción / metadata ----
    @property
    @abstractmethod
    def operations(self) -> List[ZoneOperation]:
        """
        Lista de operaciones soportadas por la zona.
        Ejemplo en Users:
        - get_users
        - get_user
        - create_user
        - update_mobile
        """
        ...

    def get_operation(self, op_code: str) -> ZoneOperation:
        for op in self.operations:
            if op.code == op_code:
                return op
        raise KeyError(f"Operación '{op_code}' no encontrada en zona '{self.code}'")

    def to_dict(self) -> Dict[str, Any]:
        return {
            "code": self.code,
            "label": self.label,
            "description": self.description,
            "operations": [
                {
                    "code": op.code,
                    "label": op.label,
                    "description": op.description,
                    "http_method": op.http_method,
                    "default_params": op.default_params,
                }
                for op in self.operations
            ],
        }

    # ---- Ejecución ----
    @abstractmethod
    def execute(
        self,
        operation_code: str,
        params: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """
        Ejecuta una operación concreta de la zona.
        'params' viene directamente del body del POST /zone/<zone_code>/query.
        Cada zona se encarga de mapear a la llamada AroFlo concreta.
        """
        ...
