"""
Metrics Collector for Mid Platform.
[AC-IDMP-18] Runtime metrics collection.

Metrics:
- task_completion_rate: Task completion rate
- slot_completion_rate: Slot completion rate
- wrong_transfer_rate: Wrong transfer rate
- no_recall_rate: No recall rate
- avg_latency_ms: Average latency
"""

import logging
import time
from collections import defaultdict
from dataclasses import dataclass, field
from typing import Any

from app.models.mid.schemas import MetricsSnapshot

logger = logging.getLogger(__name__)


@dataclass
class SessionMetrics:
    """Session-level metrics."""
    session_id: str
    total_turns: int = 0
    completed_tasks: int = 0
    transfers: int = 0
    wrong_transfers: int = 0
    no_recall_turns: int = 0
    total_latency_ms: int = 0
    slots_expected: int = 0
    slots_filled: int = 0


@dataclass
class AggregatedMetrics:
    """Aggregated metrics over time window."""
    total_sessions: int = 0
    total_turns: int = 0
    completed_tasks: int = 0
    total_transfers: int = 0
    wrong_transfers: int = 0
    no_recall_turns: int = 0
    total_latency_ms: int = 0
    slots_expected: int = 0
    slots_filled: int = 0
    
    def to_snapshot(self) -> MetricsSnapshot:
        """Convert to MetricsSnapshot."""
        task_rate = self.completed_tasks / self.total_turns if self.total_turns > 0 else 0.0
        slot_rate = self.slots_filled / self.slots_expected if self.slots_expected > 0 else 1.0
        wrong_transfer_rate = self.wrong_transfers / self.total_transfers if self.total_transfers > 0 else 0.0
        no_recall_rate = self.no_recall_turns / self.total_turns if self.total_turns > 0 else 0.0
        avg_latency = self.total_latency_ms / self.total_turns if self.total_turns > 0 else 0.0
        
        return MetricsSnapshot(
            task_completion_rate=round(task_rate, 4),
            slot_completion_rate=round(slot_rate, 4),
            wrong_transfer_rate=round(wrong_transfer_rate, 4),
            no_recall_rate=round(no_recall_rate, 4),
            avg_latency_ms=round(avg_latency, 2),
        )


class MetricsCollector:
    """
    [AC-IDMP-18] Metrics collector for runtime observability.
    
    Features:
    - Session-level metrics tracking
    - Aggregated metrics over time windows
    - Real-time snapshot generation
    """
    
    def __init__(self):
        self._session_metrics: dict[str, SessionMetrics] = {}
        self._tenant_metrics: dict[str, AggregatedMetrics] = defaultdict(AggregatedMetrics)
        self._global_metrics = AggregatedMetrics()
    
    def start_session(self, session_id: str) -> None:
        """Start tracking a new session."""
        if session_id not in self._session_metrics:
            self._session_metrics[session_id] = SessionMetrics(session_id=session_id)
            logger.debug(f"[AC-IDMP-18] Session started: {session_id}")
    
    def record_turn(
        self,
        session_id: str,
        tenant_id: str,
        latency_ms: int,
        task_completed: bool = False,
        transferred: bool = False,
        wrong_transfer: bool = False,
        no_recall: bool = False,
        slots_expected: int = 0,
        slots_filled: int = 0,
    ) -> None:
        """
        [AC-IDMP-18] Record a conversation turn.
        
        Args:
            session_id: Session ID
            tenant_id: Tenant ID
            latency_ms: Turn latency in milliseconds
            task_completed: Whether the task was completed
            transferred: Whether transfer occurred
            wrong_transfer: Whether it was a wrong transfer
            no_recall: Whether no recall occurred
            slots_expected: Expected slots count
            slots_filled: Filled slots count
        """
        session = self._session_metrics.get(session_id)
        if not session:
            session = SessionMetrics(session_id=session_id)
            self._session_metrics[session_id] = session
        
        session.total_turns += 1
        session.total_latency_ms += latency_ms
        
        if task_completed:
            session.completed_tasks += 1
        
        if transferred:
            session.transfers += 1
            if wrong_transfer:
                session.wrong_transfers += 1
        
        if no_recall:
            session.no_recall_turns += 1
        
        session.slots_expected += slots_expected
        session.slots_filled += slots_filled
        
        self._tenant_metrics[tenant_id].total_turns += 1
        self._tenant_metrics[tenant_id].total_latency_ms += latency_ms
        
        if task_completed:
            self._tenant_metrics[tenant_id].completed_tasks += 1
        
        if transferred:
            self._tenant_metrics[tenant_id].total_transfers += 1
            if wrong_transfer:
                self._tenant_metrics[tenant_id].wrong_transfers += 1
        
        if no_recall:
            self._tenant_metrics[tenant_id].no_recall_turns += 1
        
        self._tenant_metrics[tenant_id].slots_expected += slots_expected
        self._tenant_metrics[tenant_id].slots_filled += slots_filled
        
        self._global_metrics.total_turns += 1
        self._global_metrics.total_latency_ms += latency_ms
        
        if task_completed:
            self._global_metrics.completed_tasks += 1
        
        if transferred:
            self._global_metrics.total_transfers += 1
            if wrong_transfer:
                self._global_metrics.wrong_transfers += 1
        
        if no_recall:
            self._global_metrics.no_recall_turns += 1
        
        self._global_metrics.slots_expected += slots_expected
        self._global_metrics.slots_filled += slots_filled
        
        logger.debug(
            f"[AC-IDMP-18] Turn recorded: session={session_id}, "
            f"latency_ms={latency_ms}, task_completed={task_completed}"
        )
    
    def end_session(self, session_id: str) -> SessionMetrics | None:
        """End session tracking and return final metrics."""
        session = self._session_metrics.pop(session_id, None)
        if session:
            self._tenant_metrics[session_id.split("_")[0]].total_sessions += 1
            self._global_metrics.total_sessions += 1
            logger.info(
                f"[AC-IDMP-18] Session ended: {session_id}, "
                f"turns={session.total_turns}, completed={session.completed_tasks}"
            )
        return session
    
    def get_session_metrics(self, session_id: str) -> SessionMetrics | None:
        """Get metrics for a specific session."""
        return self._session_metrics.get(session_id)
    
    def get_tenant_metrics(self, tenant_id: str) -> MetricsSnapshot:
        """[AC-IDMP-18] Get metrics snapshot for a tenant."""
        return self._tenant_metrics[tenant_id].to_snapshot()
    
    def get_global_metrics(self) -> MetricsSnapshot:
        """[AC-IDMP-18] Get global metrics snapshot."""
        return self._global_metrics.to_snapshot()
    
    def reset_metrics(self, tenant_id: str | None = None) -> None:
        """Reset metrics for a tenant or globally."""
        if tenant_id:
            self._tenant_metrics[tenant_id] = AggregatedMetrics()
            logger.info(f"[AC-IDMP-18] Metrics reset for tenant: {tenant_id}")
        else:
            self._tenant_metrics.clear()
            self._global_metrics = AggregatedMetrics()
            logger.info("[AC-IDMP-18] Global metrics reset")
    
    def get_metrics_dict(self, tenant_id: str | None = None) -> dict[str, Any]:
        """Get metrics as dictionary for logging/export."""
        snapshot = self.get_tenant_metrics(tenant_id) if tenant_id else self.get_global_metrics()
        return {
            "task_completion_rate": snapshot.task_completion_rate,
            "slot_completion_rate": snapshot.slot_completion_rate,
            "wrong_transfer_rate": snapshot.wrong_transfer_rate,
            "no_recall_rate": snapshot.no_recall_rate,
            "avg_latency_ms": snapshot.avg_latency_ms,
        }
