"""
Metrics collection and monitoring for InferenceKit.
Tracks performance, usage, and system health metrics.
"""

import asyncio
from typing import Dict, Any, List, Optional
from datetime import datetime, timedelta
from collections import defaultdict, deque


class Metrics:
    """Metrics collection and monitoring for InferenceKit."""

    def __init__(
        self,
        max_metrics_age: timedelta = timedelta(hours=1),
        max_metrics_count: int = 1000,
        sample_rate: float = 1.0,
        **config
    ):
        self.max_metrics_age = max_metrics_age
        self.max_metrics_count = max_metrics_count
        self.sample_rate = sample_rate
        self.config = config

        # Metrics storage
        self.request_metrics: deque = deque(maxlen=max_metrics_count)
        self.latency_metrics: deque = deque(maxlen=max_metrics_count)
        self.error_metrics: deque = deque(maxlen=max_metrics_count)
        self.cost_metrics: deque = deque(maxlen=max_metrics_count)
        self.resource_metrics: deque = deque(maxlen=max_metrics_count)

        # Aggregated metrics
        self.aggregated_metrics: Dict[str, Any] = {
            "total_requests": 0,
            "successful_requests": 0,
            "failed_requests": 0,
            "total_latency": 0.0,
            "total_cost": 0.0,
            "peak_concurrent_requests": 0,
        }

        # Current state
        self.active_requests: int = 0
        self.current_metrics: Dict[str, Any] = {}

    def increment_requests(self, count: int = 1) -> None:
        """Increment the total request count."""
        self.aggregated_metrics["total_requests"] += count
        self.active_requests += count
        self._update_peak_concurrent()

    def increment_failures(self, count: int = 1) -> None:
        """Increment the failure count."""
        self.aggregated_metrics["failed_requests"] += count

    def record_success(self) -> None:
        """Record a successful request."""
        self.aggregated_metrics["successful_requests"] += 1
        self.active_requests = max(0, self.active_requests - 1)

    def record_latency(self, latency: float) -> None:
        """Record request latency."""
        timestamp = datetime.utcnow()
        self.latency_metrics.append((timestamp, latency))
        self.aggregated_metrics["total_latency"] += latency

    def record_cost(self, cost: float) -> None:
        """Record request cost."""
        timestamp = datetime.utcnow()
        self.cost_metrics.append((timestamp, cost))
        self.aggregated_metrics["total_cost"] += cost

    def record_error(self, error_type: str, metadata: Optional[Dict[str, Any]] = None) -> None:
        """Record an error."""
        timestamp = datetime.utcnow()
        error_data = {
            "timestamp": timestamp,
            "error_type": error_type,
            "metadata": metadata or {},
        }
        self.error_metrics.append(error_data)

    def record_resource_usage(self, resource_type: str, usage: float) -> None:
        """Record resource usage."""
        timestamp = datetime.utcnow()
        self.resource_metrics.append((timestamp, resource_type, usage))

    def _update_peak_concurrent(self) -> None:
        """Update peak concurrent requests."""
        if self.active_requests > self.aggregated_metrics["peak_concurrent_requests"]:
            self.aggregated_metrics["peak_concurrent_requests"] = self.active_requests

    def get_metrics(self) -> Dict[str, Any]:
        """Get current metrics."""
        self._cleanup_old_metrics()

        return {
            "aggregated": self.aggregated_metrics,
            "current": self.current_metrics,
            "request_metrics": list(self.request_metrics),
            "latency_metrics": list(self.latency_metrics),
            "error_metrics": list(self.error_metrics),
            "cost_metrics": list(self.cost_metrics),
            "resource_metrics": list(self.resource_metrics),
        }

    def get_aggregated_metrics(self) -> Dict[str, Any]:
        """Get aggregated metrics only."""
        return self.aggregated_metrics.copy()

    def get_current_metrics(self) -> Dict[str, Any]:
        """Get current metrics only."""
        return self.current_metrics.copy()

    def get_request_metrics(self) -> List[Dict[str, Any]]:
        """Get request metrics."""
        return [dict(metric) for metric in self.request_metrics]

    def get_latency_metrics(self) -> List[Dict[str, Any]]:
        """Get latency metrics."""
        return [{"timestamp": ts, "latency": lat} for ts, lat in self.latency_metrics]

    def get_error_metrics(self) -> List[Dict[str, Any]]:
        """Get error metrics."""
        return [dict(metric) for metric in self.error_metrics]

    def get_cost_metrics(self) -> List[Dict[str, Any]]:
        """Get cost metrics."""
        return [{"timestamp": ts, "cost": cost} for ts, cost in self.cost_metrics]

    def get_resource_metrics(self) -> List[Dict[str, Any]]:
        """Get resource metrics."""
        return [{"timestamp": ts, "type": t, "usage": u} for ts, t, u in self.resource_metrics]

    def get_metrics_summary(self) -> Dict[str, Any]:
        """Get a summary of key metrics."""
        total_requests = self.aggregated_metrics["total_requests"]
        successful_requests = self.aggregated_metrics["successful_requests"]
        failed_requests = self.aggregated_metrics["failed_requests"]

        return {
            "requests": total_requests,
            "success_rate": successful_requests / total_requests if total_requests > 0 else 0,
            "failure_rate": failed_requests / total_requests if total_requests > 0 else 0,
            "average_latency": self.aggregated_metrics["total_latency"] / successful_requests if successful_requests > 0 else 0,
            "total_cost": self.aggregated_metrics["total_cost"],
            "peak_concurrent": self.aggregated_metrics["peak_concurrent_requests"],
        }

    def get_metrics_by_time_range(
        self,
        start_time: datetime,
        end_time: datetime
    ) -> Dict[str, Any]:
        """Get metrics within a specific time range."""
        def filter_metrics(metrics, start, end):
            return [m for m in metrics if start <= m[0] <= end]

        return {
            "requests": len(filter_metrics(self.request_metrics, start_time, end_time)),
            "latencies": [lat for ts, lat in filter_metrics(self.latency_metrics, start_time, end_time)],
            "errors": len(filter_metrics(self.error_metrics, start_time, end_time)),
            "costs": [cost for ts, cost in filter_metrics(self.cost_metrics, start_time, end_time)],
        }

    def _cleanup_old_metrics(self) -> None:
        """Clean up old metrics that exceed the age limit."""
        now = datetime.utcnow()
        cutoff_time = now - self.max_metrics_age

        def cleanup(deque_obj):
            while deque_obj and deque_obj[0][0] < cutoff_time:
                deque_obj.popleft()

        cleanup(self.request_metrics)
        cleanup(self.latency_metrics)
        cleanup(self.error_metrics)
        cleanup(self.cost_metrics)
        cleanup(self.resource_metrics)

    async def start_monitoring(self) -> None:
        """Start background monitoring tasks."""
        # Start periodic metric collection
        asyncio.create_task(self._periodic_metrics_collection())

    async def _periodic_metrics_collection(self) -> None:
        """Periodically collect system metrics."""
        while True:
            await asyncio.sleep(60)  # Collect every minute
            self._collect_system_metrics()

    def _collect_system_metrics(self) -> None:
        """Collect system-level metrics."""
        try:
            import psutil
            cpu_usage = psutil.cpu_percent()
            memory_info = psutil.virtual_memory()
            disk_usage = psutil.disk_usage('.')

            self.record_resource_usage("cpu", cpu_usage)
            self.record_resource_usage("memory", memory_info.percent)
            self.record_resource_usage("disk", disk_usage.percent)

            self.current_metrics.update({
                "cpu_usage": cpu_usage,
                "memory_usage": memory_info.percent,
                "disk_usage": disk_usage.percent,
            })
        except ImportError:
            pass
        except Exception:
            pass

    def shutdown(self) -> None:
        """Shutdown the metrics collector."""
        # Clean up any resources if needed
        pass