""" 服务 Health Check and Monitoring Module
""" 
import asyncio
import time
import logging
from typing import Dict, Optional, List
from datetime import datetime, timedelta
from dataclasses import dataclass, field
from enum import Enum

logger = logging.getLogger(__name__)


class HealthStatus(str, Enum):
    """ 服务 health status"""
    HEALTHY = "healthy"
    UNHEALTHY = "unhealthy"
    DEGRADED = "degraded"
    UNKNOWN = "unknown"


@dataclass
class HealthCheckResult:
    """ 健康检查 result""" 
    status: HealthStatus
    latency_ms: float
    timestamp: datetime
    error: Optional[str] = None
    metadata: Dict = field(default_factory=dict)


@dataclass
class ServiceHealth:
    """ 服务 health tracking""" 
    service_id: str
    status: HealthStatus = HealthStatus.UNKNOWN
    last_check: Optional[datetime] = None
    last_success: Optional[datetime] = None
    last_failure: Optional[datetime] = None
    consecutive_failures: int = 0
    consecutive_successes: int = 0
    total_checks: int = 0
    total_failures: int = 0
    avg_latency_ms: float = 0.0
    history: List[HealthCheckResult] = field(default_factory=list)
    
    def update(self, result: HealthCheckResult):
        """ 更新 health status with new check result"""
        self.last_check = result.timestamp
        self.total_checks += 1
        
        # 更新 latency average
        self.avg_latency_ms = (
            (self.avg_latency_ms * (self.total_checks - 1) + result.latency_ms) 
            / self.total_checks
        )
        
        if result.status == HealthStatus.HEALTHY:
            self.status = HealthStatus.HEALTHY
            self.last_success = result.timestamp
            self.consecutive_successes += 1
            self.consecutive_failures = 0
        else:
            self.last_failure = result.timestamp
            self.consecutive_failures += 1
            self.consecutive_successes = 0
            self.total_failures += 1
            
            # Determine if degraded or unhealthy
            if self.consecutive_failures >= 3:
                self.status = HealthStatus.UNHEALTHY
            else:
                self.status = HealthStatus.DEGRADED
        
        # Keep last 10 results
        self.history.append(result)
        if len(self.history) > 10:
            self.history.pop(0)
    
    def get_success_rate(self) -> float:
        """Calculate success rate"""
        if self.total_checks == 0:
            return 0.0
        return (self.total_checks - self.total_failures) / self.total_checks * 100
    
    def should_circuit_break(self, threshold: int = 5) -> bool:
        """Check if circuit breaker should trip""" 
        return self.consecutive_failures >= threshold


class HealthMonitor:
    """
    Centralized health monitoring for all services.
    Tracks health status, performs periodic checks, and manages circuit breakers.
    """
    
    def __init__(self, check_interval: int = 60):
        """ 初始化 health monitor.
        
        Args:
            check_interval: Interval between health checks in seconds
        """
        self.check_interval = check_interval
        self._health_status: Dict[str, ServiceHealth] = {}
        self._monitoring_task: Optional[asyncio.Task] = None
        self._running = False
    
    def register_service(self, service_id: str):
        """Register a service for health monitoring"""
        if service_id not in self._health_status:
            self._health_status[service_id] = ServiceHealth(service_id=service_id)
            logger.info(f"Registered service for health monitoring: {service_id}")
    
    def get_health(self, service_id: str) -> Optional[ServiceHealth]:
        """ 获取 health status for a service""" 
        return self._health_status.get(service_id)
    
    def get_all_health(self) -> Dict[str, ServiceHealth]:
        """ 获取 health status for all services""" 
        return self._health_status.copy()
    
    async def check_service_health(self, service_id: str, service) -> HealthCheckResult:
        """
        Perform health check on a service.
        
        Args:
            service_id: Service identifier
            service: Service instance
            
        Returns:
            HealthCheckResult
        """ 
        start_time = time.time()
        
        try:
            # Call service health check
            is_healthy = await service.health_check()
            latency_ms = (time.time() - start_time) * 1000
            
            status = HealthStatus.HEALTHY if is_healthy else HealthStatus.UNHEALTHY
            
            return HealthCheckResult(
                status=status,
                latency_ms=latency_ms,
                timestamp=datetime.now(),
                metadata={"service_id": service_id}
            )
        except Exception as e:
            latency_ms = (time.time() - start_time) * 1000
            logger.error(f"Health check failed for {service_id}: {e}")
            
            return HealthCheckResult(
                status=HealthStatus.UNHEALTHY,
                latency_ms=latency_ms,
                timestamp=datetime.now(),
                error=str(e),
                metadata={"service_id": service_id}
            )
    
    def update_health(self, service_id: str, result: HealthCheckResult):
        """ 更新 health status for a service"""
        if service_id not in self._health_status:
            self.register_service(service_id)
        
        self._health_status[service_id].update(result)
        
        # 日志 status changes
        health = self._health_status[service_id]
        if health.consecutive_failures == 1:
            logger.warning(f"Service {service_id} health check failed")
        elif health.consecutive_failures == 3:
            logger.error(f"Service {service_id} is DEGRADED (3 consecutive failures)")
        elif health.consecutive_failures == 5:
            logger.critical(f"Service {service_id} is UNHEALTHY (5 consecutive failures)")
        elif health.consecutive_successes == 1 and health.total_failures > 0:
            logger.info(f"Service {service_id} recovered")
    
    async def start_monitoring(self):
        """ 启动 background health monitoring"""
        if self._running:
            logger.warning("Health monitoring already running")
            return
        
        self._running = True
        logger.info(f"Starting health monitoring (interval: {self.check_interval}s)")
        
        while self._running:
            try:
                await asyncio.sleep(self.check_interval)
                # 监控 logic would go here
                # For now, we'll rely on manual checks
            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error(f"Error in health monitoring loop: {e}")
    
    async def stop_monitoring(self):
        """ 停止 background health monitoring"""
        self._running = False
        if self._monitoring_task:
            self._monitoring_task.cancel()
            try:
                await self._monitoring_task
            except asyncio.CancelledError:
                pass
        logger.info("Health monitoring stopped")
    
    def get_unhealthy_services(self) -> List[str]:
        """ 获取 list of unhealthy service IDs""" 
        return [
            service_id 
            for service_id, health in self._health_status.items()
            if health.status == HealthStatus.UNHEALTHY
        ]
    
    def get_degraded_services(self) -> List[str]:
        """ 获取 list of degraded service IDs""" 
        return [
            service_id 
            for service_id, health in self._health_status.items()
            if health.status == HealthStatus.DEGRADED
        ]
    
    def get_health_summary(self) -> Dict:
        """ 获取 summary of all service health"""
        total = len(self._health_status)
        healthy = sum(1 for h in self._health_status.values() if h.status == HealthStatus.HEALTHY)
        degraded = sum(1 for h in self._health_status.values() if h.status == HealthStatus.DEGRADED)
        unhealthy = sum(1 for h in self._health_status.values() if h.status == HealthStatus.UNHEALTHY)
        unknown = sum(1 for h in self._health_status.values() if h.status == HealthStatus.UNKNOWN)
        
        return {
            "total": total,
            "healthy": healthy,
            "degraded": degraded,
            "unhealthy": unhealthy,
            "unknown": unknown,
            "health_percentage": (healthy / total * 100) if total > 0 else 0
        }


# 全局的 health monitor instance
health_monitor = HealthMonitor()
