"""보조 LLM 라우터 — 저렴한 모델 자동 선택 + 다단계 fallback.

task_type 매핑:
  summarize → Haiku > Gemini Flash > GPT-4o-mini
  analyze   → Sonnet > GPT-4o > Gemini Pro
  classify  → Haiku > GPT-4o-mini > Gemini Flash
  default   → 첫 번째 사용 가능한 프로바이더

실제 API 호출 없음 — 라우팅 로직만 구현.
호출자가 반환된 ProviderConfig로 직접 호출해야 함.
"""

import os
from dataclasses import dataclass, field
from typing import List, Optional

# ---------------------------------------------------------------------------
# ProviderConfig dataclass
# ---------------------------------------------------------------------------


@dataclass
class ProviderConfig:
    """단일 LLM 프로바이더 설정."""

    name: str
    model: str
    api_key_env: str
    base_url: Optional[str] = None
    priority: int = 0


# ---------------------------------------------------------------------------
# 기본 프로바이더 정의
# ---------------------------------------------------------------------------

_DEFAULT_PROVIDERS: List[ProviderConfig] = [
    ProviderConfig(
        name="anthropic",
        model="claude-haiku-4-5",
        api_key_env="ANTHROPIC_API_KEY",
        base_url="https://api.anthropic.com/v1",
        priority=10,
    ),
    ProviderConfig(
        name="openai",
        model="gpt-4o-mini",
        api_key_env="OPENAI_API_KEY",
        base_url=None,  # openai SDK 기본값 사용
        priority=5,
    ),
    ProviderConfig(
        name="google",
        model="gemini-2.5-flash",
        api_key_env="GOOGLE_API_KEY",
        base_url="https://generativelanguage.googleapis.com/v1beta/openai",
        priority=3,
    ),
    ProviderConfig(
        name="deepseek",
        model="deepseek-chat",
        api_key_env="DEEPSEEK_API_KEY",
        base_url="https://api.deepseek.com/v1",
        priority=1,
    ),
]

# task_type별 프로바이더 이름 우선순위 체인
# 각 리스트는 선호 순서대로 provider.name을 나열.
_TASK_CHAINS: dict[str, List[str]] = {
    "summarize": ["anthropic", "google", "openai"],
    "analyze": ["anthropic", "openai", "google"],
    "classify": ["anthropic", "openai", "google"],
}

# analyze용 모델 오버라이드 (Sonnet / GPT-4o / Gemini Pro)
_ANALYZE_MODEL_OVERRIDES: dict[str, str] = {
    "anthropic": "claude-sonnet-4-6",
    "openai": "gpt-4o",
    "google": "gemini-2.5-pro",
}


# ---------------------------------------------------------------------------
# AuxRouter
# ---------------------------------------------------------------------------


class AuxRouter:
    """보조 LLM 라우터.

    Args:
        providers: 사용할 ProviderConfig 목록.
                   None이면 기본 4개 프로바이더(_DEFAULT_PROVIDERS) 사용.
    """

    def __init__(self, providers: Optional[List[ProviderConfig]] = None) -> None:
        if providers is None:
            # 기본 목록의 복사본 사용 (원본 변형 방지)
            self.providers: List[ProviderConfig] = list(_DEFAULT_PROVIDERS)
        else:
            self.providers = list(providers)

    # ------------------------------------------------------------------
    # Public API
    # ------------------------------------------------------------------

    def get_available_providers(self) -> List[ProviderConfig]:
        """API 키가 환경변수에 설정된(비어 있지 않은) 프로바이더만 반환.

        Returns:
            사용 가능한 ProviderConfig 리스트 (등록 순서 유지).
        """
        available: List[ProviderConfig] = []
        for provider in self.providers:
            key_value = os.environ.get(provider.api_key_env, "")
            if key_value:  # 빈 문자열 제외
                available.append(provider)
        return available

    def route(self, task_type: str) -> Optional[ProviderConfig]:
        """task_type에 맞는 최적 프로바이더를 선택해 반환.

        Args:
            task_type: "summarize" | "analyze" | "classify" | "default"
                       그 외 알 수 없는 값은 "default" 동작 적용.

        Returns:
            선택된 ProviderConfig, 또는 사용 가능한 프로바이더가 없으면 None.
        """
        available = self.get_available_providers()
        if not available:
            return None

        # 이름 → ProviderConfig 빠른 조회용 맵
        provider_map: dict[str, ProviderConfig] = {p.name: p for p in available}

        chain = _TASK_CHAINS.get(task_type)
        if chain:
            # fallback 체인에서 첫 번째 사용 가능한 프로바이더 선택
            for name in chain:
                if name in provider_map:
                    selected = provider_map[name]
                    # analyze의 경우 모델 오버라이드 적용 (원본 변형 방지)
                    if task_type == "analyze" and name in _ANALYZE_MODEL_OVERRIDES:
                        selected = ProviderConfig(
                            name=selected.name,
                            model=_ANALYZE_MODEL_OVERRIDES[name],
                            api_key_env=selected.api_key_env,
                            base_url=selected.base_url,
                            priority=selected.priority,
                        )
                    return selected

        # default 또는 알 수 없는 task_type → 첫 번째 사용 가능 프로바이더
        return available[0]
