"""
Usage Monitor - Dashboard and reporting for CLI agent usage.

Provides:
- Real-time usage dashboard
- Usage reports and analytics
- Alert management
- Historical usage queries

Usage:
    from agent_orchestrator.budget.usage_monitor import UsageMonitor

    monitor = UsageMonitor(cli_tracker, token_audit)
    report = monitor.generate_usage_report(["claude-code", "gemini-cli"])
    print(report)
"""

import logging
from dataclasses import dataclass
from datetime import datetime, date, timedelta
from typing import Any, Optional

from .cli_usage_tracker import CLIUsageTracker
from ..observability.token_audit import TokenAuditClient

logger = logging.getLogger(__name__)


@dataclass
class AgentUsageSnapshot:
    """Snapshot of agent usage at a point in time."""

    agent_id: str
    timestamp: datetime

    # Budget metrics
    tokens_used: int
    tokens_remaining: int
    tokens_limit: int
    cost_used: float
    cost_remaining: float
    cost_limit: float

    # Rate limit metrics
    rpm_current: int
    rpm_limit: int
    tpm_current: int
    tpm_limit: int

    # Performance metrics
    request_count: int
    success_rate: float
    error_rate: float
    avg_tokens_per_request: float

    # Priority
    priority_score: float


class UsageMonitor:
    """
    Usage monitoring and reporting for CLI agents.

    Features:
    - Real-time dashboards
    - Usage reports
    - Trend analysis
    - Alerting
    """

    def __init__(
        self,
        cli_tracker: CLIUsageTracker,
        token_audit: Optional[TokenAuditClient] = None,
    ):
        """
        Initialize usage monitor.

        Args:
            cli_tracker: CLI usage tracker instance
            token_audit: Token audit client for historical data
        """
        self.cli_tracker = cli_tracker
        self.token_audit = token_audit

    def get_snapshot(self, agent_id: str) -> AgentUsageSnapshot:
        """
        Get current usage snapshot for an agent.

        Args:
            agent_id: Agent to snapshot

        Returns:
            AgentUsageSnapshot with current metrics
        """
        summary = self.cli_tracker.get_usage_summary(agent_id)
        priority = self.cli_tracker.get_agent_priority(agent_id)

        budget = summary["budget"]
        rate = summary["rate_limits"]
        usage_data = budget["usage"]
        budget_data = budget["budget"]

        # Calculate metrics
        tokens_used = usage_data["input_tokens"] + usage_data["output_tokens"]
        tokens_limit = budget_data["daily_input_tokens"] + budget_data["daily_output_tokens"]
        tokens_remaining = tokens_limit - tokens_used

        avg_tokens = tokens_used / usage_data["request_count"] if usage_data["request_count"] > 0 else 0

        success_rate = 1.0 - priority.error_rate

        return AgentUsageSnapshot(
            agent_id=agent_id,
            timestamp=datetime.now(),
            tokens_used=tokens_used,
            tokens_remaining=max(0, tokens_remaining),
            tokens_limit=tokens_limit,
            cost_used=usage_data["total_cost"],
            cost_remaining=max(0, budget["remaining"]["cost"]),
            cost_limit=budget_data["daily_cost_limit"],
            rpm_current=rate.get("rpm_current", 0),
            rpm_limit=rate.get("rpm_limit", 0),
            tpm_current=rate.get("tpm_current", 0),
            tpm_limit=rate.get("tpm_limit", 0),
            request_count=usage_data["request_count"],
            success_rate=success_rate,
            error_rate=priority.error_rate,
            avg_tokens_per_request=avg_tokens,
            priority_score=priority.priority_score,
        )

    def generate_usage_report(
        self,
        agent_ids: list[str],
        include_charts: bool = False,
    ) -> str:
        """
        Generate a formatted usage report for agents.

        Args:
            agent_ids: List of agent IDs to include
            include_charts: Whether to include ASCII charts

        Returns:
            Formatted report string
        """
        lines = []
        lines.append("=" * 80)
        lines.append(f"CLI AGENT USAGE REPORT - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        lines.append("=" * 80)
        lines.append("")

        # Get snapshots
        snapshots = [self.get_snapshot(agent_id) for agent_id in agent_ids]

        # Overall summary
        total_cost = sum(s.cost_used for s in snapshots)
        total_requests = sum(s.request_count for s in snapshots)
        avg_success_rate = sum(s.success_rate for s in snapshots) / len(snapshots) if snapshots else 0

        lines.append("OVERALL SUMMARY")
        lines.append("-" * 80)
        lines.append(f"  Total Cost:     ${total_cost:.2f}")
        lines.append(f"  Total Requests: {total_requests}")
        lines.append(f"  Avg Success:    {avg_success_rate:.1%}")
        lines.append("")

        # Per-agent details
        lines.append("AGENT DETAILS")
        lines.append("-" * 80)

        for snapshot in sorted(snapshots, key=lambda s: s.priority_score, reverse=True):
            lines.append(f"\n{snapshot.agent_id.upper()}")
            lines.append("  " + "-" * 76)

            # Budget
            budget_pct = (snapshot.cost_used / snapshot.cost_limit * 100) if snapshot.cost_limit > 0 else 0
            lines.append(f"  Budget:         ${snapshot.cost_used:.2f} / ${snapshot.cost_limit:.2f} ({budget_pct:.1f}%)")

            budget_bar = self._create_bar(budget_pct, 40)
            lines.append(f"                  {budget_bar}")

            # Tokens
            token_pct = (snapshot.tokens_used / snapshot.tokens_limit * 100) if snapshot.tokens_limit > 0 else 0
            lines.append(f"  Tokens:         {snapshot.tokens_used:,} / {snapshot.tokens_limit:,} ({token_pct:.1f}%)")

            token_bar = self._create_bar(token_pct, 40)
            lines.append(f"                  {token_bar}")

            # Rate limits
            if snapshot.rpm_limit > 0:
                rpm_pct = (snapshot.rpm_current / snapshot.rpm_limit * 100) if snapshot.rpm_limit > 0 else 0
                lines.append(f"  Rate (RPM):     {snapshot.rpm_current} / {snapshot.rpm_limit} ({rpm_pct:.1f}%)")

                rpm_bar = self._create_bar(rpm_pct, 40)
                lines.append(f"                  {rpm_bar}")

            # Performance
            lines.append(f"  Requests:       {snapshot.request_count} (success: {snapshot.success_rate:.1%})")
            lines.append(f"  Avg Tokens/Req: {snapshot.avg_tokens_per_request:.0f}")
            lines.append(f"  Priority Score: {snapshot.priority_score:.1f}/100")

        lines.append("")
        lines.append("=" * 80)

        return "\n".join(lines)

    def _create_bar(self, percentage: float, width: int = 40) -> str:
        """Create an ASCII progress bar."""
        filled = int(width * percentage / 100)
        empty = width - filled

        # Color coding (using symbols)
        if percentage >= 95:
            symbol = "█"  # Critical
        elif percentage >= 85:
            symbol = "▓"  # Warning
        else:
            symbol = "▒"  # Normal

        bar = symbol * filled + "░" * empty
        return f"[{bar}]"

    def generate_priority_report(self, agent_ids: list[str]) -> str:
        """
        Generate a priority ranking report for routing decisions.

        Args:
            agent_ids: List of agent IDs to rank

        Returns:
            Formatted priority report
        """
        priorities = self.cli_tracker.rank_agents(agent_ids)

        lines = []
        lines.append("=" * 80)
        lines.append(f"AGENT PRIORITY RANKING - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        lines.append("=" * 80)
        lines.append("")
        lines.append("Rank  Agent            Score   Budget  RateLimit  ErrorRate  Status")
        lines.append("-" * 80)

        for rank, priority in enumerate(priorities, 1):
            status = "✓ READY" if priority.priority_score > 0 else "✗ BLOCKED"

            lines.append(
                f"{rank:2d}.   {priority.agent_id:15s}  "
                f"{priority.priority_score:5.1f}   "
                f"{priority.budget_remaining_pct:6.1%}   "
                f"{priority.rate_limit_headroom:6.1%}     "
                f"{priority.error_rate:6.1%}     "
                f"{status}"
            )

            if priority.priority_score == 0:
                lines.append(f"      └─ {priority.reason}")

        lines.append("")
        lines.append("=" * 80)

        return "\n".join(lines)

    def get_historical_usage(
        self,
        agent_id: str,
        days: int = 7,
    ) -> Optional[dict[str, Any]]:
        """
        Get historical usage data for an agent.

        Args:
            agent_id: Agent to query
            days: Number of days to look back

        Returns:
            Dictionary with historical data, or None if token_audit not available
        """
        if not self.token_audit:
            return None

        end_date = datetime.now()
        start_date = end_date - timedelta(days=days)

        # Query token audit
        summary = self.token_audit.get_usage_summary(
            start_date=start_date,
            end_date=end_date,
        )

        # Filter for this agent
        agent_data = summary.by_agent.get(agent_id)
        if not agent_data:
            return None

        return {
            "agent_id": agent_id,
            "period": {
                "start": start_date.isoformat(),
                "end": end_date.isoformat(),
                "days": days,
            },
            "totals": {
                "input_tokens": agent_data.input_tokens,
                "output_tokens": agent_data.output_tokens,
                "total_cost": agent_data.total_cost_usd,
            },
            "daily_average": {
                "input_tokens": agent_data.input_tokens / days,
                "output_tokens": agent_data.output_tokens / days,
                "cost": agent_data.total_cost_usd / days,
            },
        }

    def check_anomalies(self, agent_id: str) -> list[str]:
        """
        Check for usage anomalies.

        Args:
            agent_id: Agent to check

        Returns:
            List of anomaly descriptions
        """
        anomalies = []
        snapshot = self.get_snapshot(agent_id)

        # High error rate
        if snapshot.error_rate > 0.1:  # 10%
            anomalies.append(f"High error rate: {snapshot.error_rate:.1%}")

        # Near budget limit
        budget_pct = snapshot.cost_used / snapshot.cost_limit if snapshot.cost_limit > 0 else 0
        if budget_pct > 0.9:
            anomalies.append(f"Budget critical: {budget_pct:.0%} used")

        # Near rate limit
        if snapshot.rpm_limit > 0:
            rpm_pct = snapshot.rpm_current / snapshot.rpm_limit
            if rpm_pct > 0.9:
                anomalies.append(f"Rate limit critical: {rpm_pct:.0%} of RPM")

        # Unusual avg tokens per request
        if snapshot.avg_tokens_per_request > 50_000:
            anomalies.append(f"High avg tokens: {snapshot.avg_tokens_per_request:.0f}")

        # Low priority score
        if snapshot.priority_score < 20:
            anomalies.append(f"Low priority score: {snapshot.priority_score:.1f}")

        return anomalies

    def generate_alert_summary(self, agent_ids: list[str]) -> str:
        """
        Generate summary of current alerts and anomalies.

        Args:
            agent_ids: List of agent IDs to check

        Returns:
            Formatted alert summary
        """
        lines = []
        lines.append("=" * 80)
        lines.append(f"USAGE ALERTS - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        lines.append("=" * 80)
        lines.append("")

        total_alerts = 0

        for agent_id in agent_ids:
            anomalies = self.check_anomalies(agent_id)
            if anomalies:
                total_alerts += len(anomalies)
                lines.append(f"{agent_id}:")
                for anomaly in anomalies:
                    lines.append(f"  ⚠ {anomaly}")
                lines.append("")

        if total_alerts == 0:
            lines.append("✓ No alerts - all agents operating normally")
            lines.append("")

        lines.append(f"Total Alerts: {total_alerts}")
        lines.append("=" * 80)

        return "\n".join(lines)

    def export_metrics(self, agent_ids: list[str]) -> dict[str, Any]:
        """
        Export metrics in structured format for external monitoring.

        Args:
            agent_ids: List of agent IDs to export

        Returns:
            Dictionary with metrics suitable for monitoring systems
        """
        metrics = {
            "timestamp": datetime.now().isoformat(),
            "agents": {},
        }

        for agent_id in agent_ids:
            snapshot = self.get_snapshot(agent_id)
            anomalies = self.check_anomalies(agent_id)

            metrics["agents"][agent_id] = {
                "budget": {
                    "cost_used": snapshot.cost_used,
                    "cost_limit": snapshot.cost_limit,
                    "cost_remaining": snapshot.cost_remaining,
                    "percentage": snapshot.cost_used / snapshot.cost_limit if snapshot.cost_limit > 0 else 0,
                },
                "tokens": {
                    "used": snapshot.tokens_used,
                    "limit": snapshot.tokens_limit,
                    "remaining": snapshot.tokens_remaining,
                    "percentage": snapshot.tokens_used / snapshot.tokens_limit if snapshot.tokens_limit > 0 else 0,
                },
                "rate_limits": {
                    "rpm_current": snapshot.rpm_current,
                    "rpm_limit": snapshot.rpm_limit,
                    "rpm_percentage": snapshot.rpm_current / snapshot.rpm_limit if snapshot.rpm_limit > 0 else 0,
                },
                "performance": {
                    "request_count": snapshot.request_count,
                    "success_rate": snapshot.success_rate,
                    "error_rate": snapshot.error_rate,
                    "avg_tokens_per_request": snapshot.avg_tokens_per_request,
                },
                "priority": {
                    "score": snapshot.priority_score,
                },
                "alerts": anomalies,
                "alert_count": len(anomalies),
            }

        return metrics
