from dataclasses import dataclass
from typing import Any

_CANONICAL_LEVELS = ("off", "low", "medium", "high", "xhigh")
_LEVEL_ALIASES: dict[str, str] = {
    "none": "off",
    "off": "off",
    "disabled": "off",
    "disable": "off",
    "on": "on",
    "enabled": "on",
    "enable": "on",
    "minimal": "low",
    "low": "low",
    "med": "medium",
    "medium": "medium",
    "default": "medium",
    "high": "high",
    "xhigh": "xhigh",
    "x-high": "xhigh",
    "x_high": "xhigh",
}


@dataclass(frozen=True)
class ThinkingCapabilities:
    enabled: bool
    levels: tuple[str, ...]
    supports_reasoning_effort: bool
    supports_thinking_param: bool


def normalize_thinking_level(value: str | None) -> str | None:
    if value is None:
        return None
    normalized = value.strip().lower()
    if not normalized:
        return None
    if normalized in _CANONICAL_LEVELS:
        return normalized
    return _LEVEL_ALIASES.get(normalized)


def get_thinking_capabilities(model: str) -> ThinkingCapabilities:
    info = _get_model_info(model)
    params = {str(item).strip().lower() for item in info.get("supported_openai_params", [])}
    supports_reasoning_effort = "reasoning_effort" in params
    supports_thinking_param = "thinking" in params
    supports_reasoning = bool(info.get("supports_reasoning"))

    enabled = supports_reasoning or supports_reasoning_effort or supports_thinking_param
    if not enabled:
        return ThinkingCapabilities(
            enabled=False,
            levels=("off",),
            supports_reasoning_effort=False,
            supports_thinking_param=False,
        )

    if supports_reasoning_effort:
        levels = (
            ("off", "low", "medium", "high", "xhigh")
            if _supports_xhigh(model)
            else ("off", "low", "medium", "high")
        )
    elif supports_thinking_param:
        levels = ("off", "on")
    else:
        levels = ("off",)

    return ThinkingCapabilities(
        enabled=True,
        levels=levels,
        supports_reasoning_effort=supports_reasoning_effort,
        supports_thinking_param=supports_thinking_param,
    )


def reasoning_effort_for_model(model: str, level: str | None) -> str | None:
    normalized = normalize_thinking_level(level)
    if normalized is None:
        return None

    caps = get_thinking_capabilities(model)
    if not caps.enabled or not caps.supports_reasoning_effort:
        return None

    if normalized == "on":
        normalized = "medium"

    if normalized not in caps.levels:
        if normalized == "xhigh" and "high" in caps.levels:
            normalized = "high"
        else:
            return None

    if normalized == "off":
        return "none"

    return normalized


def _supports_xhigh(model: str) -> bool:
    model_lower = model.strip().lower()
    if model_lower.startswith("codex/"):
        return True
    if model_lower.startswith("openai/") and "gpt-5" in model_lower:
        return True

    litellm_model = _to_litellm_model(model_lower)
    return litellm_model.startswith("gpt-5")


def _to_litellm_model(model: str) -> str:
    return model.split("/", 1)[-1] if "/" in model else model


def _get_model_info(model: str) -> dict[str, Any]:
    try:
        import litellm
    except Exception:
        return {}

    litellm_model = _to_litellm_model(model)
    try:
        info = litellm.get_model_info(litellm_model)
    except Exception:
        return {}

    return info if isinstance(info, dict) else {}
