from pydantic import BaseModel, Field from typing import Optional, List, Dict, Any from datetime import datetime from enum import Enum class EstadoSincronizacion(str, Enum): """Estados posibles de sincronización""" ACTUALIZADA = "Actualizada" ATENCION = "Atención" ERROR = "Error" RECIBIDO = "Recibido" PROCESANDO = "Procesando" class NodeStatus(BaseModel): """Estado de un nodo específico""" nodo_sub_nodo: str = Field(..., description="Nombre del nodo") estado_sincronizacion: EstadoSincronizacion = Field(..., description="Estado actual de sincronización") ultima_sincronizacion: Optional[datetime] = Field(None, description="Timestamp de la última sincronización") total_clientes: int = Field(0, description="Total de clientes en el nodo") clientes_activos: int = Field(0, description="Número de clientes activos") clientes_inactivos: int = Field(0, description="Número de clientes inactivos") tiempo_desde_ultima_sync: Optional[str] = Field(None, description="Tiempo transcurrido desde última sincronización") class Config: json_encoders = { datetime: lambda v: v.isoformat() if v else None } class NodeSummary(BaseModel): """Resumen básico de un nodo para listados""" nodo_sub_nodo: str = Field(..., description="Nombre del nodo") estado_sincronizacion: EstadoSincronizacion = Field(..., description="Estado actual") ultima_sincronizacion: Optional[datetime] = Field(None, description="Última sincronización") total_clientes: int = Field(0, description="Total de clientes") clientes_activos: int = Field(0, description="Clientes activos") class NodesList(BaseModel): """Lista de todos los nodos""" nodes: List[NodeSummary] = Field(default_factory=list, description="Lista de nodos") total_nodes: int = Field(0, description="Número total de nodos") nodes_by_status: Dict[str, int] = Field(default_factory=dict, description="Conteo por estado") last_updated: datetime = Field(default_factory=datetime.now, description="Timestamp de la consulta") class BackupInfo(BaseModel): """Información de respaldos de un nodo""" nodo_sub_nodo: str = Field(..., description="Nombre del nodo") ultimo_backup: Optional[datetime] = Field(None, description="Fecha del último respaldo") tipo_backup: Optional[str] = Field(None, description="Tipo de respaldo (Full, Differential, Log)") tamano_backup: Optional[str] = Field(None, description="Tamaño del respaldo") estado_backup: Optional[str] = Field(None, description="Estado del respaldo") ruta_backup: Optional[str] = Field(None, description="Ruta donde se almacena el respaldo") dias_desde_backup: Optional[int] = Field(None, description="Días desde el último respaldo") class HealthCheck(BaseModel): """Estado general del sistema""" status: str = Field(..., description="Estado general (healthy, degraded, unhealthy)") database_status: str = Field(..., description="Estado de la base de datos") total_nodes: int = Field(0, description="Total de nodos monitoreados") nodes_healthy: int = Field(0, description="Nodos en estado saludable") nodes_attention: int = Field(0, description="Nodos que requieren atención") nodes_error: int = Field(0, description="Nodos con errores") last_check: datetime = Field(default_factory=datetime.now, description="Timestamp del chequeo") uptime: Optional[str] = Field(None, description="Tiempo de actividad del servicio") version: str = Field("1.0.0", description="Versión de la API") class ErrorResponse(BaseModel): """Respuesta de error estándar""" error: str = Field(..., description="Mensaje de error") detail: Optional[str] = Field(None, description="Detalle adicional del error") timestamp: datetime = Field(default_factory=datetime.now, description="Timestamp del error") path: Optional[str] = Field(None, description="Ruta que causó el error") class SuccessResponse(BaseModel): """Respuesta exitosa estándar""" message: str = Field(..., description="Mensaje de éxito") data: Optional[Dict[str, Any]] = Field(None, description="Datos adicionales") timestamp: datetime = Field(default_factory=datetime.now, description="Timestamp de la respuesta")