"""
Subscription Manager - Manage agent subscription configurations.

Provides:
- Agent subscription registration
- Tier-based limit checking
- Usage tracking integration
- Subscription persistence
"""

import logging
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Callable, Optional

from .tiers import (
    Provider,
    SubscriptionTier,
    TierLimits,
    SubscriptionConfig,
    get_tier_limits,
    get_provider_for_tier,
)

logger = logging.getLogger(__name__)


@dataclass
class AgentSubscription:
    """Subscription information for a specific agent."""

    agent_id: str
    config: SubscriptionConfig
    registered_at: datetime = field(default_factory=datetime.now)
    last_verified_at: Optional[datetime] = None
    is_verified: bool = False
    metadata: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "agent_id": self.agent_id,
            "config": self.config.to_dict(),
            "registered_at": self.registered_at.isoformat(),
            "last_verified_at": self.last_verified_at.isoformat() if self.last_verified_at else None,
            "is_verified": self.is_verified,
        }


class SubscriptionManager:
    """
    Manage subscriptions for multiple agents.

    Provides:
    - Registration and lookup of agent subscriptions
    - Tier-based limit enforcement
    - Integration with rate limit monitoring
    - Callbacks for subscription changes

    Example:
        manager = SubscriptionManager()

        # Register an agent's subscription
        manager.register(
            agent_id="claude-code-1",
            tier=SubscriptionTier.CLAUDE_MAX,
            account_email="user@example.com",
        )

        # Check if agent can make requests
        can_request = manager.can_make_request("claude-code-1", current_usage=100)

        # Get limits for agent
        limits = manager.get_limits("claude-code-1")
    """

    def __init__(self) -> None:
        """Initialize the subscription manager."""
        self._subscriptions: dict[str, AgentSubscription] = {}
        self._on_change: list[Callable[[str, AgentSubscription], None]] = []

    def register(
        self,
        agent_id: str,
        tier: SubscriptionTier,
        account_email: str = "",
        autonomy_level: str = "assisted",
        auto_response_enabled: bool = False,
        metadata: Optional[dict[str, Any]] = None,
    ) -> AgentSubscription:
        """
        Register an agent's subscription.

        Args:
            agent_id: Unique agent identifier
            tier: Subscription tier
            account_email: Associated account email
            autonomy_level: "auto", "assisted", or "manual"
            auto_response_enabled: Enable auto-responses
            metadata: Additional metadata

        Returns:
            AgentSubscription object
        """
        config = SubscriptionConfig(
            tier=tier,
            provider=get_provider_for_tier(tier),
            limits=get_tier_limits(tier),
            account_email=account_email,
            autonomy_level=autonomy_level,
            auto_response_enabled=auto_response_enabled,
            metadata=metadata or {},
        )

        subscription = AgentSubscription(
            agent_id=agent_id,
            config=config,
        )

        self._subscriptions[agent_id] = subscription
        logger.info(f"Registered subscription for {agent_id}: {tier.value}")

        # Notify listeners
        for callback in self._on_change:
            try:
                callback(agent_id, subscription)
            except Exception as e:
                logger.warning(f"Error in subscription change callback: {e}")

        return subscription

    def update_tier(
        self,
        agent_id: str,
        tier: SubscriptionTier,
    ) -> Optional[AgentSubscription]:
        """
        Update an agent's subscription tier.

        Args:
            agent_id: Agent identifier
            tier: New subscription tier

        Returns:
            Updated subscription or None if not found
        """
        subscription = self._subscriptions.get(agent_id)
        if not subscription:
            return None

        subscription.config.tier = tier
        subscription.config.limits = get_tier_limits(tier)
        subscription.config.provider = get_provider_for_tier(tier)

        logger.info(f"Updated tier for {agent_id}: {tier.value}")

        for callback in self._on_change:
            try:
                callback(agent_id, subscription)
            except Exception as e:
                logger.warning(f"Error in subscription change callback: {e}")

        return subscription

    def unregister(self, agent_id: str) -> bool:
        """
        Unregister an agent's subscription.

        Returns True if agent was registered.
        """
        if agent_id in self._subscriptions:
            del self._subscriptions[agent_id]
            logger.info(f"Unregistered subscription for {agent_id}")
            return True
        return False

    def get_subscription(self, agent_id: str) -> Optional[AgentSubscription]:
        """Get subscription for an agent."""
        return self._subscriptions.get(agent_id)

    def get_config(self, agent_id: str) -> Optional[SubscriptionConfig]:
        """Get subscription config for an agent."""
        subscription = self._subscriptions.get(agent_id)
        return subscription.config if subscription else None

    def get_limits(self, agent_id: str) -> Optional[TierLimits]:
        """Get rate limits for an agent."""
        subscription = self._subscriptions.get(agent_id)
        return subscription.config.limits if subscription else None

    def get_tier(self, agent_id: str) -> Optional[SubscriptionTier]:
        """Get subscription tier for an agent."""
        subscription = self._subscriptions.get(agent_id)
        return subscription.config.tier if subscription else None

    def can_make_request(
        self,
        agent_id: str,
        current_usage: int,
        tokens_needed: int = 0,
    ) -> bool:
        """
        Check if an agent can make a request.

        Args:
            agent_id: Agent identifier
            current_usage: Current message count in window
            tokens_needed: Tokens needed for request (optional)

        Returns:
            True if request is allowed
        """
        limits = self.get_limits(agent_id)
        if not limits:
            return True  # No limits configured

        # Check message limit
        if current_usage >= limits.messages_per_window:
            return False

        # Check token limit if specified
        if tokens_needed > 0 and tokens_needed > limits.max_output_tokens:
            return False

        return True

    def get_remaining_requests(
        self,
        agent_id: str,
        current_usage: int,
    ) -> int:
        """
        Get remaining requests for an agent.

        Args:
            agent_id: Agent identifier
            current_usage: Current message count in window

        Returns:
            Number of remaining requests
        """
        limits = self.get_limits(agent_id)
        if not limits:
            return float("inf")

        return max(0, limits.messages_per_window - current_usage)

    def is_auto_response_enabled(self, agent_id: str) -> bool:
        """Check if auto-response is enabled for an agent."""
        config = self.get_config(agent_id)
        return config.auto_response_enabled if config else False

    def get_autonomy_level(self, agent_id: str) -> str:
        """Get autonomy level for an agent."""
        config = self.get_config(agent_id)
        return config.autonomy_level if config else "manual"

    def list_agents(self) -> list[str]:
        """List all registered agent IDs."""
        return list(self._subscriptions.keys())

    def list_agents_by_tier(self, tier: SubscriptionTier) -> list[str]:
        """List agents with a specific tier."""
        return [
            agent_id
            for agent_id, sub in self._subscriptions.items()
            if sub.config.tier == tier
        ]

    def list_agents_by_provider(self, provider: Provider) -> list[str]:
        """List agents for a specific provider."""
        return [
            agent_id
            for agent_id, sub in self._subscriptions.items()
            if sub.config.provider == provider
        ]

    def mark_verified(self, agent_id: str) -> bool:
        """Mark a subscription as verified."""
        subscription = self._subscriptions.get(agent_id)
        if subscription:
            subscription.is_verified = True
            subscription.last_verified_at = datetime.now()
            return True
        return False

    def on_change(
        self,
        callback: Callable[[str, AgentSubscription], None],
    ) -> None:
        """Register callback for subscription changes."""
        self._on_change.append(callback)

    def get_summary(self) -> dict[str, Any]:
        """Get subscription summary."""
        tier_counts: dict[str, int] = {}
        provider_counts: dict[str, int] = {}

        for sub in self._subscriptions.values():
            tier_counts[sub.config.tier.value] = tier_counts.get(sub.config.tier.value, 0) + 1
            provider_counts[sub.config.provider.value] = provider_counts.get(sub.config.provider.value, 0) + 1

        return {
            "total_agents": len(self._subscriptions),
            "by_tier": tier_counts,
            "by_provider": provider_counts,
            "verified_count": sum(1 for s in self._subscriptions.values() if s.is_verified),
        }


# Module-level manager instance
_manager: Optional[SubscriptionManager] = None


def get_subscription_manager() -> SubscriptionManager:
    """Get or create the global subscription manager."""
    global _manager
    if _manager is None:
        _manager = SubscriptionManager()
    return _manager


def set_subscription_manager(manager: Optional[SubscriptionManager]) -> None:
    """Set the global subscription manager."""
    global _manager
    _manager = manager
