"""
Model tier classification for LLM cost optimization insights.

Maps model names to tiers: ``"fast"``, ``"standard"``, ``"reasoning"``.
The lookup table is maintained separately from core tracking logic so it
can be updated as providers release new models without touching event code.

User-provided ``model_tier`` always takes precedence over auto-inference.
Unknown models default to ``"standard"``.
"""

from __future__ import annotations

# ---------------------------------------------------------------------------
# Tier definitions
# ---------------------------------------------------------------------------
TIER_FAST = "fast"
TIER_STANDARD = "standard"
TIER_REASONING = "reasoning"

# ---------------------------------------------------------------------------
# Lookup table: lowercase substring → tier
#
# Order matters: more specific substrings should come first so that e.g.
# "gpt-4o-mini" matches before "gpt-4o".  The first match wins.
# ---------------------------------------------------------------------------
_MODEL_TIER_RULES: list[tuple[str, str]] = [
    # OpenAI -- fast
    ("gpt-4o-mini", TIER_FAST),
    ("gpt-4.1-mini", TIER_FAST),
    ("gpt-4.1-nano", TIER_FAST),
    ("gpt-3.5", TIER_FAST),
    # OpenAI -- reasoning
    ("o1-mini", TIER_FAST),
    ("o3-mini", TIER_FAST),
    ("o4-mini", TIER_FAST),
    ("o1-pro", TIER_REASONING),
    ("o1-preview", TIER_REASONING),
    ("o1", TIER_REASONING),
    ("o3", TIER_REASONING),
    ("o4", TIER_REASONING),
    # OpenAI -- standard
    ("gpt-4o", TIER_STANDARD),
    ("gpt-4.1", TIER_STANDARD),
    ("gpt-4-turbo", TIER_STANDARD),
    ("gpt-4", TIER_STANDARD),

    # Anthropic -- fast
    ("claude-3-haiku", TIER_FAST),
    ("claude-3.5-haiku", TIER_FAST),
    ("claude-haiku", TIER_FAST),
    # Anthropic -- reasoning
    ("claude-3-opus", TIER_FAST),  # Opus is expensive but not a reasoning model
    ("claude-opus", TIER_STANDARD),
    # Anthropic -- standard
    ("claude-sonnet", TIER_STANDARD),
    ("claude-3.5-sonnet", TIER_STANDARD),
    ("claude-3-sonnet", TIER_STANDARD),
    ("claude-4", TIER_STANDARD),

    # Google -- fast
    ("gemini-2.0-flash", TIER_FAST),
    ("gemini-1.5-flash", TIER_FAST),
    ("gemini-flash", TIER_FAST),
    # Google -- reasoning
    ("gemini-2.0-pro", TIER_STANDARD),
    ("gemini-1.5-pro", TIER_STANDARD),
    ("gemini-pro", TIER_STANDARD),
    ("gemini-ultra", TIER_REASONING),

    # Mistral -- fast
    ("mistral-small", TIER_FAST),
    ("mistral-tiny", TIER_FAST),
    ("pixtral", TIER_FAST),
    # Mistral -- standard
    ("mistral-large", TIER_STANDARD),
    ("mistral-medium", TIER_STANDARD),
    ("mixtral", TIER_STANDARD),
    ("mistral-nemo", TIER_STANDARD),

    # AWS Bedrock / Meta
    ("llama-3.3", TIER_STANDARD),
    ("llama-3.2", TIER_FAST),
    ("llama-3.1-405b", TIER_STANDARD),
    ("llama-3.1-70b", TIER_STANDARD),
    ("llama-3.1-8b", TIER_FAST),
    ("llama-3-70b", TIER_STANDARD),
    ("llama-3-8b", TIER_FAST),
    ("llama", TIER_STANDARD),

    # Cohere
    ("command-r-plus", TIER_STANDARD),
    ("command-r", TIER_FAST),
    ("command-light", TIER_FAST),
    ("command", TIER_STANDARD),

    # DeepSeek
    ("deepseek-r1", TIER_REASONING),
    ("deepseek-v3", TIER_STANDARD),
    ("deepseek-chat", TIER_STANDARD),
    ("deepseek-coder", TIER_STANDARD),
    ("deepseek", TIER_STANDARD),
]

# Pre-compiled for O(1) exact lookups on common model names.
_EXACT_TIER_MAP: dict[str, str] = {
    rule[0]: rule[1] for rule in _MODEL_TIER_RULES
}


def infer_model_tier(model_name: str) -> str:
    """Infer a tier for *model_name* using substring matching.

    Returns ``"fast"``, ``"standard"``, or ``"reasoning"``.
    Unknown models default to ``"standard"``.
    """
    lower = model_name.lower()

    # Strip provider prefix (e.g., "openai:gpt-4o" → "gpt-4o")
    if ":" in lower:
        lower = lower.split(":", 1)[1]

    # Try exact match first (fast path)
    tier = _EXACT_TIER_MAP.get(lower)
    if tier is not None:
        return tier

    # Substring matching (order-dependent)
    for pattern, tier in _MODEL_TIER_RULES:
        if pattern in lower:
            return tier

    return TIER_STANDARD
