"""스마트 모델 라우팅 유틸리티 (M-03).

작업 텍스트의 길이와 복잡도 키워드를 분석하여 적합한 Claude 모델을 선택한다.

- 단순 질문 (짧고 복잡 키워드 없음) → haiku
- 중간 길이 (복잡 키워드 없음)      → sonnet
- 복잡 키워드 포함                  → opus

config_loader에서 모델명 오버라이드를 읽을 수 있으며, 없으면 기본 상수를 사용한다.

Usage:
    from utils.model_router import route_model

    model = route_model("What is the weather?")           # → haiku
    model = route_model("Analyze and refactor this code") # → opus
    model = route_model("Explain this paragraph in detail") # → opus
"""

from __future__ import annotations

from typing import Any

# ---------------------------------------------------------------------------
# 모델명 상수
# ---------------------------------------------------------------------------
MODEL_HAIKU: str = "claude-haiku-4-5-20251001"
MODEL_SONNET: str = "claude-sonnet-4-6"
MODEL_OPUS: str = "claude-opus-4-6"

# ---------------------------------------------------------------------------
# 라우팅 임계값
# ---------------------------------------------------------------------------
_MAX_SIMPLE_CHARS: int = 160
_MAX_SIMPLE_WORDS: int = 28

# ---------------------------------------------------------------------------
# 복잡도 키워드 셋
# ---------------------------------------------------------------------------
_COMPLEX_KEYWORDS: frozenset[str] = frozenset(
    {
        "analyze",
        "implement",
        "debug",
        "refactor",
        "architecture",
        "design",
        "explain",
        "compare",
        "review",
        "optimize",
        "migrate",
        "integrate",
        "orchestrate",
        "diagnose",
        "security",
        "performance",
        "scalability",
    }
)

# ---------------------------------------------------------------------------
# Config 키
# ---------------------------------------------------------------------------
_CFG_KEY_HAIKU: str = "models.router.haiku"
_CFG_KEY_SONNET: str = "models.router.sonnet"
_CFG_KEY_OPUS: str = "models.router.opus"


def _resolve_models(cfg: Any) -> tuple[str, str, str]:
    """cfg에서 모델명을 읽어 (haiku, sonnet, opus) 튜플을 반환한다.

    cfg가 None이거나 키가 없으면 기본 상수를 사용한다.
    """
    if cfg is None:
        return MODEL_HAIKU, MODEL_SONNET, MODEL_OPUS

    haiku = cfg.get(_CFG_KEY_HAIKU, MODEL_HAIKU) or MODEL_HAIKU
    sonnet = cfg.get(_CFG_KEY_SONNET, MODEL_SONNET) or MODEL_SONNET
    opus = cfg.get(_CFG_KEY_OPUS, MODEL_OPUS) or MODEL_OPUS
    return str(haiku), str(sonnet), str(opus)


def _has_complex_keyword(task_lower: str) -> bool:
    """작업 텍스트(소문자)에 복잡 키워드가 포함되어 있으면 True."""
    words = task_lower.split()
    for word in words:
        # 구두점 제거 후 비교
        clean = word.strip(".,!?;:\"'()")
        if clean in _COMPLEX_KEYWORDS:
            return True
    return False


def route_model(task: str, cfg: Any = None) -> str:
    """작업 텍스트를 분석하여 최적 Claude 모델명을 반환한다.

    판단 순서:
    1. 복잡 키워드 포함 → opus
    2. 길이 ≤ 160자 AND 단어 수 ≤ 28 → haiku
    3. 그 외 → sonnet

    Args:
        task: 라우팅할 작업 텍스트.
        cfg:  Config 인스턴스 (config_loader.Config). None이면 기본 상수 사용.

    Returns:
        선택된 모델명 문자열.
    """
    haiku_model, sonnet_model, opus_model = _resolve_models(cfg)

    task_lower = task.lower()

    # 복잡 키워드 우선 검사
    if _has_complex_keyword(task_lower):
        return opus_model

    # 길이 기반 판단
    char_count = len(task)
    word_count = len(task.split())

    if char_count <= _MAX_SIMPLE_CHARS and word_count <= _MAX_SIMPLE_WORDS:
        return haiku_model

    return sonnet_model
