"""
AI Observer Integration - Real-time dashboard and alerting.

AI Observer provides:
- Real-time metrics dashboard
- Alert configuration and routing
- Cost threshold monitoring
- Agent health visualization

This is a placeholder for Phase 7 implementation.
"""

from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional, Dict, List, Any
import logging

logger = logging.getLogger(__name__)


@dataclass
class MetricPoint:
    """Single metric data point."""

    name: str
    value: float
    timestamp: datetime = field(default_factory=datetime.now)
    tags: Dict[str, str] = field(default_factory=dict)


@dataclass
class AlertRule:
    """Alert rule configuration."""

    name: str
    metric: str
    condition: str  # gt, lt, eq, gte, lte
    threshold: float
    severity: str = "warning"  # info, warning, error, critical
    enabled: bool = True

    # Notification settings
    notify_channels: List[str] = field(default_factory=list)
    cooldown_seconds: int = 300  # Don't re-alert for 5 min


@dataclass
class Alert:
    """Triggered alert."""

    rule_name: str
    metric: str
    current_value: float
    threshold: float
    severity: str
    message: str
    timestamp: datetime = field(default_factory=datetime.now)
    acknowledged: bool = False


class AIObserverClient:
    """
    Client for AI Observer integration.

    Note: Full implementation in Phase 7.
    This provides the basic interface and local metric collection.
    """

    def __init__(
        self,
        endpoint: Optional[str] = None,
        api_key: Optional[str] = None,
        config: Optional[Dict[str, Any]] = None,
    ):
        """
        Initialize AI Observer client.

        Args:
            endpoint: AI Observer API endpoint
            api_key: API key for authentication
            config: Additional configuration
        """
        self.endpoint = endpoint
        self.api_key = api_key
        self.config = config or {}

        # Local state
        self._metrics: List[MetricPoint] = []
        self._alert_rules: Dict[str, AlertRule] = {}
        self._alerts: List[Alert] = []
        self._alert_callbacks: List[callable] = []

        # Connection state
        self._connected = False

    async def connect(self) -> bool:
        """
        Connect to AI Observer service.

        Returns:
            True if connected successfully
        """
        if not self.endpoint:
            logger.warning("No AI Observer endpoint configured")
            return False

        # TODO: Implement actual connection in Phase 7
        logger.info(f"AI Observer connection to {self.endpoint} (placeholder)")
        self._connected = True
        return True

    async def disconnect(self) -> None:
        """Disconnect from AI Observer service."""
        self._connected = False
        logger.info("Disconnected from AI Observer")

    def record_metric(
        self,
        name: str,
        value: float,
        tags: Optional[Dict[str, str]] = None,
    ) -> None:
        """
        Record a metric data point.

        Args:
            name: Metric name
            value: Metric value
            tags: Additional tags
        """
        point = MetricPoint(
            name=name,
            value=value,
            tags=tags or {},
        )

        self._metrics.append(point)

        # Check alert rules
        self._check_alerts(point)

        # Trim old metrics (keep last 1000)
        if len(self._metrics) > 1000:
            self._metrics = self._metrics[-1000:]

    def add_alert_rule(self, rule: AlertRule) -> None:
        """
        Add an alert rule.

        Args:
            rule: AlertRule to add
        """
        self._alert_rules[rule.name] = rule
        logger.info(f"Added alert rule: {rule.name}")

    def remove_alert_rule(self, rule_name: str) -> bool:
        """
        Remove an alert rule.

        Args:
            rule_name: Name of rule to remove

        Returns:
            True if rule was removed
        """
        if rule_name in self._alert_rules:
            del self._alert_rules[rule_name]
            return True
        return False

    def _check_alerts(self, point: MetricPoint) -> None:
        """Check if a metric triggers any alerts."""
        for rule in self._alert_rules.values():
            if not rule.enabled:
                continue

            if rule.metric != point.name:
                continue

            triggered = False
            if rule.condition == "gt" and point.value > rule.threshold:
                triggered = True
            elif rule.condition == "lt" and point.value < rule.threshold:
                triggered = True
            elif rule.condition == "eq" and point.value == rule.threshold:
                triggered = True
            elif rule.condition == "gte" and point.value >= rule.threshold:
                triggered = True
            elif rule.condition == "lte" and point.value <= rule.threshold:
                triggered = True

            if triggered:
                self._fire_alert(rule, point)

    def _fire_alert(self, rule: AlertRule, point: MetricPoint) -> None:
        """Fire an alert."""
        alert = Alert(
            rule_name=rule.name,
            metric=point.name,
            current_value=point.value,
            threshold=rule.threshold,
            severity=rule.severity,
            message=f"Alert: {rule.name} - {point.name}={point.value} (threshold: {rule.threshold})",
        )

        self._alerts.append(alert)

        # Fire callbacks
        for callback in self._alert_callbacks:
            try:
                callback(alert)
            except Exception as e:
                logger.error(f"Alert callback failed: {e}")

        logger.warning(alert.message)

    def on_alert(self, callback: callable) -> None:
        """
        Register callback for alerts.

        Args:
            callback: Function to call with Alert
        """
        self._alert_callbacks.append(callback)

    def get_alerts(
        self,
        severity: Optional[str] = None,
        acknowledged: Optional[bool] = None,
    ) -> List[Alert]:
        """
        Get alerts with optional filtering.

        Args:
            severity: Filter by severity
            acknowledged: Filter by acknowledgement status

        Returns:
            List of Alert objects
        """
        alerts = self._alerts

        if severity:
            alerts = [a for a in alerts if a.severity == severity]

        if acknowledged is not None:
            alerts = [a for a in alerts if a.acknowledged == acknowledged]

        return alerts

    def acknowledge_alert(self, index: int) -> bool:
        """
        Acknowledge an alert.

        Args:
            index: Alert index

        Returns:
            True if acknowledged successfully
        """
        if 0 <= index < len(self._alerts):
            self._alerts[index].acknowledged = True
            return True
        return False

    def get_metrics(
        self,
        name: Optional[str] = None,
        limit: int = 100,
    ) -> List[MetricPoint]:
        """
        Get recorded metrics.

        Args:
            name: Filter by metric name
            limit: Maximum metrics to return

        Returns:
            List of MetricPoint objects
        """
        metrics = self._metrics

        if name:
            metrics = [m for m in metrics if m.name == name]

        return metrics[-limit:]

    # Standard metrics to record
    def record_request_cost(self, cost: float, agent_id: str) -> None:
        """Record cost of a request."""
        self.record_metric("request_cost", cost, {"agent": agent_id})

    def record_token_usage(
        self,
        input_tokens: int,
        output_tokens: int,
        agent_id: str,
    ) -> None:
        """Record token usage."""
        self.record_metric("input_tokens", float(input_tokens), {"agent": agent_id})
        self.record_metric("output_tokens", float(output_tokens), {"agent": agent_id})

    def record_request_latency(self, latency_ms: float, agent_id: str) -> None:
        """Record request latency."""
        self.record_metric("request_latency_ms", latency_ms, {"agent": agent_id})

    def record_agent_health(self, agent_id: str, health_score: float) -> None:
        """Record agent health score (0-1)."""
        self.record_metric("agent_health", health_score, {"agent": agent_id})

    def record_stuck_detection(self, agent_id: str, is_stuck: bool) -> None:
        """Record stuck detection result."""
        self.record_metric("agent_stuck", 1.0 if is_stuck else 0.0, {"agent": agent_id})


# Singleton instance
_ai_observer_client: Optional[AIObserverClient] = None


def get_ai_observer_client() -> Optional[AIObserverClient]:
    """Get the global AI Observer client instance."""
    return _ai_observer_client


def set_ai_observer_client(client: AIObserverClient) -> None:
    """Set the global AI Observer client instance."""
    global _ai_observer_client
    _ai_observer_client = client
