"""
Subscription Detection - Auto-detect subscription tiers from CLI state.

Provides:
- Heuristic-based tier detection
- Rate limit analysis
- Model availability detection
"""

import logging
from typing import Optional

from ..tracking import CLIStateReader, get_reader_for_agent, RateLimitState
from .tiers import (
    Provider,
    SubscriptionTier,
    TierLimits,
    TIER_CONFIGURATIONS,
    get_provider_for_tier,
)

logger = logging.getLogger(__name__)


class TierDetector:
    """
    Detect subscription tier from CLI state and behavior.

    Uses heuristics based on:
    - Rate limits observed
    - Model availability
    - Feature access
    - Error messages
    """

    def __init__(self) -> None:
        """Initialize the tier detector."""
        self._detected_tiers: dict[str, SubscriptionTier] = {}
        self._confidence: dict[str, float] = {}

    def detect_tier(
        self,
        agent_type: str,
        rate_limit: Optional[RateLimitState] = None,
        available_models: Optional[list[str]] = None,
        has_computer_use: bool = False,
    ) -> tuple[SubscriptionTier, float]:
        """
        Detect subscription tier from available information.

        Args:
            agent_type: Type of agent ("claude", "codex", "gemini")
            rate_limit: Current rate limit state if available
            available_models: List of available models if known
            has_computer_use: Whether computer use is available

        Returns:
            Tuple of (detected_tier, confidence)
        """
        agent_type = agent_type.lower()

        if agent_type.startswith("claude"):
            return self._detect_claude_tier(rate_limit, available_models, has_computer_use)
        elif agent_type.startswith("codex") or agent_type.startswith("chatgpt"):
            return self._detect_openai_tier(rate_limit, available_models)
        elif agent_type.startswith("gemini"):
            return self._detect_gemini_tier(rate_limit, available_models)

        return SubscriptionTier.UNKNOWN, 0.0

    def _detect_claude_tier(
        self,
        rate_limit: Optional[RateLimitState],
        available_models: Optional[list[str]],
        has_computer_use: bool,
    ) -> tuple[SubscriptionTier, float]:
        """Detect Claude subscription tier."""
        confidence = 0.0
        tier = SubscriptionTier.CLAUDE_PRO  # Default assumption

        # Check rate limits
        if rate_limit:
            limit = rate_limit.requests_limit

            if limit >= 200:
                tier = SubscriptionTier.CLAUDE_MAX
                confidence = 0.9
            elif limit >= 40:
                tier = SubscriptionTier.CLAUDE_PRO
                confidence = 0.8
            elif limit <= 10:
                tier = SubscriptionTier.CLAUDE_FREE
                confidence = 0.85
            else:
                confidence = 0.5

        # Check model availability
        if available_models:
            has_opus = any("opus" in m.lower() for m in available_models)
            if has_opus:
                if tier != SubscriptionTier.CLAUDE_MAX:
                    tier = SubscriptionTier.CLAUDE_PRO
                confidence = max(confidence, 0.7)

        # Check computer use
        if has_computer_use:
            if tier == SubscriptionTier.CLAUDE_FREE:
                tier = SubscriptionTier.CLAUDE_PRO
            confidence = max(confidence, 0.75)

        return tier, confidence

    def _detect_openai_tier(
        self,
        rate_limit: Optional[RateLimitState],
        available_models: Optional[list[str]],
    ) -> tuple[SubscriptionTier, float]:
        """Detect ChatGPT/Codex subscription tier."""
        confidence = 0.0
        tier = SubscriptionTier.CHATGPT_PLUS  # Default assumption

        # Check rate limits
        if rate_limit:
            limit = rate_limit.requests_limit

            if limit >= 150:
                tier = SubscriptionTier.CHATGPT_PRO
                confidence = 0.9
            elif limit >= 50:
                tier = SubscriptionTier.CHATGPT_PLUS
                confidence = 0.8
            elif limit <= 15:
                tier = SubscriptionTier.CHATGPT_FREE
                confidence = 0.85
            else:
                confidence = 0.5

        # Check model availability
        if available_models:
            has_o1_pro = any("o1-pro" in m.lower() for m in available_models)
            has_o1 = any("o1" in m.lower() and "mini" not in m.lower() for m in available_models)

            if has_o1_pro:
                tier = SubscriptionTier.CHATGPT_PRO
                confidence = max(confidence, 0.95)
            elif has_o1:
                if tier == SubscriptionTier.CHATGPT_FREE:
                    tier = SubscriptionTier.CHATGPT_PLUS
                confidence = max(confidence, 0.8)

        return tier, confidence

    def _detect_gemini_tier(
        self,
        rate_limit: Optional[RateLimitState],
        available_models: Optional[list[str]],
    ) -> tuple[SubscriptionTier, float]:
        """Detect Gemini subscription tier."""
        confidence = 0.0
        tier = SubscriptionTier.GEMINI_PRO  # Default assumption

        # Check rate limits
        if rate_limit:
            limit = rate_limit.requests_limit

            if limit >= 1500:
                tier = SubscriptionTier.GEMINI_ULTRA
                confidence = 0.9
            elif limit >= 500:
                tier = SubscriptionTier.GEMINI_PRO
                confidence = 0.8
            elif limit <= 100:
                tier = SubscriptionTier.GEMINI_FREE
                confidence = 0.85
            else:
                confidence = 0.5

        # Check model availability
        if available_models:
            has_ultra = any("ultra" in m.lower() for m in available_models)
            has_pro = any("pro" in m.lower() for m in available_models)

            if has_ultra:
                tier = SubscriptionTier.GEMINI_ULTRA
                confidence = max(confidence, 0.95)
            elif has_pro:
                if tier == SubscriptionTier.GEMINI_FREE:
                    tier = SubscriptionTier.GEMINI_PRO
                confidence = max(confidence, 0.8)

        return tier, confidence

    def detect_from_cli_state(self, agent_type: str) -> tuple[SubscriptionTier, float]:
        """
        Detect tier by reading CLI state files.

        Args:
            agent_type: Type of agent ("claude", "codex", "gemini")

        Returns:
            Tuple of (detected_tier, confidence)
        """
        reader = get_reader_for_agent(agent_type)
        if not reader or not reader.exists():
            return SubscriptionTier.UNKNOWN, 0.0

        snapshot = reader.get_snapshot()
        return self.detect_tier(
            agent_type=agent_type,
            rate_limit=snapshot.rate_limit,
        )

    def get_cached_tier(self, agent_id: str) -> Optional[SubscriptionTier]:
        """Get previously detected tier for an agent."""
        return self._detected_tiers.get(agent_id)

    def cache_detection(
        self,
        agent_id: str,
        tier: SubscriptionTier,
        confidence: float,
    ) -> None:
        """Cache a tier detection result."""
        self._detected_tiers[agent_id] = tier
        self._confidence[agent_id] = confidence

    def clear_cache(self, agent_id: Optional[str] = None) -> None:
        """Clear detection cache."""
        if agent_id:
            self._detected_tiers.pop(agent_id, None)
            self._confidence.pop(agent_id, None)
        else:
            self._detected_tiers.clear()
            self._confidence.clear()


def detect_tier_from_error(error_message: str) -> Optional[SubscriptionTier]:
    """
    Attempt to detect tier from an error message.

    Common error patterns:
    - "rate limit exceeded" with specific limits
    - "model not available" for tier-restricted models
    - "upgrade required" messages

    Args:
        error_message: Error message string

    Returns:
        Detected tier or None
    """
    error_lower = error_message.lower()

    # Check for upgrade prompts
    if "upgrade to pro" in error_lower or "upgrade to plus" in error_lower:
        return SubscriptionTier.CLAUDE_FREE if "claude" in error_lower else SubscriptionTier.CHATGPT_FREE

    # Check for specific model access errors
    if "opus not available" in error_lower:
        return SubscriptionTier.CLAUDE_FREE

    if "o1-pro not available" in error_lower:
        return SubscriptionTier.CHATGPT_PLUS

    return None


# Module-level detector instance
_detector: Optional[TierDetector] = None


def get_tier_detector() -> TierDetector:
    """Get or create the global tier detector."""
    global _detector
    if _detector is None:
        _detector = TierDetector()
    return _detector
