"""Health aggregation for heartbeat reporting."""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import UTC, datetime
from typing import TYPE_CHECKING, Any

import structlog

from curadise_agent.models.api.heartbeat import ComponentHealth, HealthStatus

if TYPE_CHECKING:
    from curadise_agent.collectors.manager import CollectionManager
    from curadise_agent.executor.runner import CommandRunner
    from curadise_agent.state.manager import StateManager
    from curadise_agent.transport.buffer import RingBuffer
    from curadise_agent.transport.client import TransportClient

log = structlog.get_logger(__name__)


@dataclass
class HealthChecker:
    """
    Aggregates health status from all agent components.

    Provides a unified health view for heartbeat reporting.
    """

    state_manager: StateManager | None = None
    transport: TransportClient | None = None
    buffer: RingBuffer[Any] | None = None
    collection_manager: CollectionManager | None = None
    command_runner: CommandRunner | None = None
    _last_check: datetime = field(default_factory=lambda: datetime.now(UTC), init=False)

    def check(self) -> HealthStatus:
        """
        Check health of all components.

        Returns:
            Aggregated HealthStatus
        """
        components: dict[str, ComponentHealth] = {}

        # Check state manager
        if self.state_manager:
            components["state"] = self._check_state()

        # Check transport
        if self.transport:
            components["transport"] = self._check_transport()

        # Check buffer
        if self.buffer:
            components["buffer"] = self._check_buffer()

        # Check collectors
        if self.collection_manager:
            components["collectors"] = self._check_collectors()

        # Check executor
        if self.command_runner:
            components["executor"] = self._check_executor()

        # Determine overall health
        healthy = all(comp.healthy for comp in components.values())
        state = "healthy" if healthy else "degraded"

        self._last_check = datetime.now(UTC)

        return HealthStatus(
            healthy=healthy,
            state=state,
            components=components,
            last_check=self._last_check,
        )

    def _check_state(self) -> ComponentHealth:
        """Check state manager health."""
        assert self.state_manager is not None

        healthy = self.state_manager.is_running
        message = None

        if not self.state_manager.is_registered:
            message = "Agent not registered"
        elif not self.state_manager.is_authenticated:
            message = "Agent not authenticated"

        return ComponentHealth(
            name="state",
            healthy=healthy,
            message=message,
            details={
                "state": self.state_manager.state.value,
                "registered": self.state_manager.is_registered,
                "authenticated": self.state_manager.is_authenticated,
            },
        )

    def _check_transport(self) -> ComponentHealth:
        """Check transport health."""
        assert self.transport is not None

        # Consider transport healthy if circuit is closed
        circuit_state = self.transport.circuit_state
        healthy = circuit_state == "closed"

        message = None
        if circuit_state == "open":
            message = "Circuit breaker open - server unreachable"
        elif circuit_state == "half_open":
            message = "Circuit breaker testing recovery"

        stats = self.transport.stats
        return ComponentHealth(
            name="transport",
            healthy=healthy,
            message=message,
            details={
                "circuit_state": circuit_state,
                "requests_sent": stats.requests_sent,
                "requests_failed": stats.requests_failed,
                "last_success": (
                    stats.last_success_time.isoformat() if stats.last_success_time else None
                ),
            },
        )

    def _check_buffer(self) -> ComponentHealth:
        """Check buffer health."""
        assert self.buffer is not None

        stats = self.buffer.stats()

        # Consider buffer unhealthy if > 90% full
        healthy = stats.utilization < 90.0
        message = None

        if stats.utilization >= 95.0:
            message = f"Buffer critical: {stats.utilization:.1f}% full"
        elif stats.utilization >= 90.0:
            message = f"Buffer warning: {stats.utilization:.1f}% full"

        return ComponentHealth(
            name="buffer",
            healthy=healthy,
            message=message,
            details={
                "current_size": stats.current_size,
                "max_size": stats.max_size,
                "utilization": stats.utilization,
                "total_dropped": stats.total_dropped,
            },
        )

    def _check_collectors(self) -> ComponentHealth:
        """Check collectors health."""
        assert self.collection_manager is not None

        status = self.collection_manager.get_status()
        stats = status.get("stats", {})

        total_runs = stats.get("total_runs", 0)
        failed_runs = stats.get("failed_runs", 0)

        # Consider unhealthy if > 50% failure rate (with minimum runs)
        if total_runs >= 5:
            failure_rate = failed_runs / total_runs if total_runs > 0 else 0
            healthy = failure_rate < 0.5
        else:
            healthy = True

        message = None
        if not healthy:
            message = f"High failure rate: {failed_runs}/{total_runs} collections failed"

        return ComponentHealth(
            name="collectors",
            healthy=healthy,
            message=message,
            details={
                "running": status.get("running", False),
                "total_runs": total_runs,
                "failed_runs": failed_runs,
                "total_metrics": stats.get("total_metrics", 0),
            },
        )

    def _check_executor(self) -> ComponentHealth:
        """Check executor health."""
        assert self.command_runner is not None

        status = self.command_runner.get_status()
        stats = status.get("stats", {})

        # Executor is healthy if enabled and not having high rejection rate
        enabled = status.get("enabled", False)
        rejected = stats.get("rejected", 0)
        total = stats.get("total_executed", 0)

        healthy = enabled
        message = None

        if not enabled:
            message = "Command executor disabled"
        elif total > 0 and rejected / total > 0.5:
            message = f"High rejection rate: {rejected}/{total}"
            # Still consider healthy if just rejections (security working)

        return ComponentHealth(
            name="executor",
            healthy=healthy,
            message=message,
            details={
                "enabled": enabled,
                "running_commands": status.get("running_commands", 0),
                **stats,
            },
        )

    def get_summary(self) -> dict[str, Any]:
        """
        Get a summary suitable for heartbeat.

        Returns:
            Summary dictionary
        """
        health = self.check()

        return {
            "healthy": health.healthy,
            "state": health.state,
            "components": {
                name: {
                    "healthy": comp.healthy,
                    "message": comp.message,
                }
                for name, comp in health.components.items()
            },
            "last_check": health.last_check.isoformat(),
        }
