"""
Health check system for monitoring system components
"""

import asyncio
import threading
import time
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional

from ..config import PLAYWRIGHT_AVAILABLE, browser_instance, logger, playwright_instance
from .api_client import get_api_client
from .cache import get_response_cache
from .metrics import get_metrics_collector


@dataclass
class HealthCheckResult:
    """Result of a single health check."""

    name: str
    status: str  # "healthy", "unhealthy", "warning"
    message: str
    details: dict[str, Any]
    timestamp: float
    duration: float


class HealthChecker:
    """Health check coordinator."""

    def __init__(self):
        self.checks: dict[str, Callable[[], HealthCheckResult]] = {}
        self._lock = threading.RLock()

    def register_check(self, name: str, check_func: Callable[[], HealthCheckResult]):
        """Register a health check function."""
        with self._lock:
            self.checks[name] = check_func

    def unregister_check(self, name: str):
        """Unregister a health check."""
        with self._lock:
            self.checks.pop(name, None)

    def run_check(self, name: str) -> Optional[HealthCheckResult]:
        """Run a specific health check."""
        check_func = self.checks.get(name)
        if not check_func:
            return None

        start_time = time.time()
        try:
            result = check_func()
            # Update duration
            result.duration = time.time() - start_time
            return result
        except Exception as e:
            return HealthCheckResult(
                name=name,
                status="unhealthy",
                message=f"Health check failed: {e}",
                details={"error": str(e)},
                timestamp=time.time(),
                duration=time.time() - start_time,
            )

    def run_all_checks(self) -> dict[str, HealthCheckResult]:
        """Run all registered health checks."""
        results = {}
        with self._lock:
            checks_to_run = list(self.checks.items())

        for name, check_func in checks_to_run:
            results[name] = self.run_check(name)

        return results

    def get_summary(self) -> dict[str, Any]:
        """Get health check summary."""
        results = self.run_all_checks()

        summary = {
            "timestamp": datetime.utcnow().isoformat(),
            "overall_status": "healthy",
            "total_checks": len(results),
            "healthy": 0,
            "warning": 0,
            "unhealthy": 0,
            "results": {},
        }

        for name, result in results.items():
            summary["results"][name] = {
                "status": result.status,
                "message": result.message,
                "duration_seconds": round(result.duration, 3),
            }

            if result.status == "healthy":
                summary["healthy"] += 1
            elif result.status == "warning":
                summary["warning"] += 1
                if summary["overall_status"] == "healthy":
                    summary["overall_status"] = "warning"
            elif result.status == "unhealthy":
                summary["unhealthy"] += 1
                summary["overall_status"] = "unhealthy"

        return summary


# Global health checker instance
_health_checker = HealthChecker()


def get_health_checker() -> HealthChecker:
    """Get global health checker."""
    return _health_checker


def register_standard_checks():
    """Register standard health checks."""
    checker = get_health_checker()

    # API Client health check
    def check_api_client():
        try:
            client = get_api_client()
            info = client.get_performance_info()

            if info["cache_enabled"] and info["cache_size"] > 0:
                status = "healthy"
                message = "API client is operational with cache"
            else:
                status = "warning"
                message = "API client is operational but cache may not be configured"

            return HealthCheckResult(
                name="api_client",
                status=status,
                message=message,
                details=info,
                timestamp=time.time(),
                duration=0,
            )
        except Exception as e:
            return HealthCheckResult(
                name="api_client",
                status="unhealthy",
                message=f"API client check failed: {e}",
                details={"error": str(e)},
                timestamp=time.time(),
                duration=0,
            )

    # Cache health check
    def check_cache():
        try:
            cache = get_response_cache()
            stats = cache.get_stats()

            if stats["max_size"] > 0:
                status = "healthy"
                message = f"Cache operational: {stats['total_items']}/{stats['max_size']} items"
            else:
                status = "warning"
                message = "Cache is disabled or not configured"

            return HealthCheckResult(
                name="cache",
                status=status,
                message=message,
                details=stats,
                timestamp=time.time(),
                duration=0,
            )
        except Exception as e:
            return HealthCheckResult(
                name="cache",
                status="unhealthy",
                message=f"Cache check failed: {e}",
                details={"error": str(e)},
                timestamp=time.time(),
                duration=0,
            )

    # Playwright health check
    def check_playwright():
        try:
            if not PLAYWRIGHT_AVAILABLE:
                return HealthCheckResult(
                    name="playwright",
                    status="warning",
                    message="Playwright not available",
                    details={"available": False},
                    timestamp=time.time(),
                    duration=0,
                )

            # Check if browser can be launched
            if browser_instance and playwright_instance:
                status = "healthy"
                message = "Playwright is ready with active browser"
            else:
                status = "warning"
                message = "Playwright available but no active browser instance"

            return HealthCheckResult(
                name="playwright",
                status=status,
                message=message,
                details={
                    "available": True,
                    "browser_active": browser_instance is not None,
                    "playwright_instance": playwright_instance is not None,
                },
                timestamp=time.time(),
                duration=0,
            )
        except Exception as e:
            return HealthCheckResult(
                name="playwright",
                status="unhealthy",
                message=f"Playwright check failed: {e}",
                details={"error": str(e)},
                timestamp=time.time(),
                duration=0,
            )

    # Metrics health check
    def check_metrics():
        try:
            collector = get_metrics_collector()
            summary = collector.get_summary()

            if summary["uptime_seconds"] > 0:
                status = "healthy"
                message = f"Metrics operational, uptime: {summary['uptime_seconds']:.0f}s"
            else:
                status = "warning"
                message = "Metrics system initialized but no data collected"

            return HealthCheckResult(
                name="metrics",
                status=status,
                message=message,
                details={
                    "uptime_seconds": summary.get("uptime_seconds", 0),
                    "counters_count": len(summary.get("counters", {})),
                    "gauges_count": len(summary.get("gauges", {})),
                },
                timestamp=time.time(),
                duration=0,
            )
        except Exception as e:
            return HealthCheckResult(
                name="metrics",
                status="unhealthy",
                message=f"Metrics check failed: {e}",
                details={"error": str(e)},
                timestamp=time.time(),
                duration=0,
            )

    # Network connectivity check
    def check_network():
        try:
            import requests

            # Quick connectivity check to a reliable service
            start_time = time.time()
            response = requests.get("https://httpbin.org/status/200", timeout=5)
            duration = time.time() - start_time

            if response.status_code == 200:
                status = "healthy"
                message = f"Network connectivity OK ({duration:.2f}s)"
            else:
                status = "warning"
                message = f"Network response: {response.status_code}"

            return HealthCheckResult(
                name="network",
                status=status,
                message=message,
                details={
                    "status_code": response.status_code,
                    "response_time": duration,
                    "test_url": "https://httpbin.org/status/200",
                },
                timestamp=time.time(),
                duration=duration,
            )
        except Exception as e:
            return HealthCheckResult(
                name="network",
                status="unhealthy",
                message=f"Network check failed: {e}",
                details={"error": str(e)},
                timestamp=time.time(),
                duration=0,
            )

    # Register all checks
    checker.register_check("api_client", check_api_client)
    checker.register_check("cache", check_cache)
    checker.register_check("playwright", check_playwright)
    checker.register_check("metrics", check_metrics)
    checker.register_check("network", check_network)


# Async health check functions
async def run_async_health_check(name: str) -> Optional[HealthCheckResult]:
    """Run a health check asynchronously."""
    checker = get_health_checker()
    return checker.run_check(name)


async def run_all_async_health_checks() -> dict[str, HealthCheckResult]:
    """Run all health checks asynchronously."""
    checker = get_health_checker()
    results = {}

    # Run checks concurrently
    tasks = []
    check_names = list(checker.checks.keys())

    for name in check_names:
        task = asyncio.create_task(run_async_health_check(name))
        tasks.append((name, task))

    # Wait for all tasks to complete
    for name, task in tasks:
        try:
            result = await task
            results[name] = result
        except Exception as e:
            results[name] = HealthCheckResult(
                name=name,
                status="unhealthy",
                message=f"Async health check failed: {e}",
                details={"error": str(e)},
                timestamp=time.time(),
                duration=0,
            )

    return results


# Initialize standard checks
register_standard_checks()


def get_system_health() -> dict[str, Any]:
    """Get comprehensive system health report."""
    checker = get_health_checker()
    summary = checker.get_summary()

    # Add additional system information
    summary["system_info"] = {
        "python_version": f"{__import__('sys').version_info.major}.{__import__('sys').version_info.minor}",
        "platform": __import__("platform").platform(),
        "timestamp": datetime.utcnow().isoformat(),
    }

    return summary


async def get_system_health_async() -> dict[str, Any]:
    """Get comprehensive system health report asynchronously."""
    checker = get_health_checker()

    # Run health checks concurrently
    results = await run_all_async_health_checks()

    # Build summary
    summary = {
        "timestamp": datetime.utcnow().isoformat(),
        "overall_status": "healthy",
        "total_checks": len(results),
        "healthy": 0,
        "warning": 0,
        "unhealthy": 0,
        "results": {},
    }

    for name, result in results.items():
        summary["results"][name] = {
            "status": result.status,
            "message": result.message,
            "duration_seconds": round(result.duration, 3),
        }

        if result.status == "healthy":
            summary["healthy"] += 1
        elif result.status == "warning":
            summary["warning"] += 1
            if summary["overall_status"] == "healthy":
                summary["overall_status"] = "warning"
        elif result.status == "unhealthy":
            summary["unhealthy"] += 1
            summary["overall_status"] = "unhealthy"

    # Add system info
    summary["system_info"] = {
        "python_version": f"{__import__('sys').version_info.major}.{__import__('sys').version_info.minor}",
        "platform": __import__("platform").platform(),
        "async_mode": True,
    }

    return summary


# Quick health check functions for tools
def quick_health_check() -> dict[str, str]:
    """Quick health check returning status for each component."""
    checker = get_health_checker()
    results = checker.run_all_checks()

    return {name: result.status for name, result in results.items()}


def is_system_healthy() -> bool:
    """Check if overall system is healthy."""
    summary = get_system_health()
    return summary["overall_status"] == "healthy"
