"""
Model definitions and resolvers.

In sentarc-mono this is auto-generated by scripts/generate-models.ts
from models.dev + OpenRouter APIs. Here we define key models statically.
"""
from __future__ import annotations
from typing import Optional
from ..types import ModelDef

_REGISTRY: dict[str, ModelDef] = {}

def register_model(m: ModelDef) -> None:
    _REGISTRY[f"{m.provider}/{m.id}"] = m

def get_model(provider: str, model_id: str) -> Optional[ModelDef]:
    return _REGISTRY.get(f"{provider}/{model_id}")

def list_models(provider: Optional[str] = None) -> list[ModelDef]:
    # Import generated models lazily
    from .generated import GENERATED_MODELS
    
    # Merge static registry with generated models
    all_models = list(_REGISTRY.values())
    
    # Add generated models if not already present (by id)
    known_ids = {m.id for m in all_models}
    for gm in GENERATED_MODELS:
        if gm.id not in known_ids and (not provider or gm.provider == provider):
            all_models.append(gm)

    if provider:
        return [m for m in all_models if m.provider == provider]
    return all_models

# Default model per provider
DEFAULT_MODELS: dict[str, str] = {
    "anthropic": "claude-sonnet-4-6",
    "openai":    "gpt-4o",
    "google":    "gemini-2.5-flash",
    "ollama":    "llama3.2",
}

def resolve_model(provider: str, model_id: Optional[str] = None) -> ModelDef:
    """Resolve ModelDef from provider + optional id. Builds on-the-fly for unknowns."""
    mid = model_id or PROVIDER_DEFAULTS.get(provider)
    if not mid:
        raise ValueError(f"Unknown provider {provider!r}")
    m = get_model(provider, mid)
    if m:
        return m
    api = "openai" if provider in ("ollama", "openrouter") else provider
    return ModelDef(id=mid, provider=provider, api=api)


# ── Catalog ───────────────────────────────────────────────────────────────────

# Anthropic
for _m in [
    ModelDef("claude-opus-4-6",          "anthropic", "anthropic", supports_thinking=True,  input_cost_per_mtok=15.0,  output_cost_per_mtok=75.0),
    ModelDef("claude-sonnet-4-6",        "anthropic", "anthropic", supports_thinking=True,  input_cost_per_mtok=3.0,   output_cost_per_mtok=15.0),
    ModelDef("claude-haiku-4-5-20251001","anthropic", "anthropic", supports_thinking=False, input_cost_per_mtok=0.8,   output_cost_per_mtok=4.0),
]:
    register_model(_m)

# OpenAI
for _m in [
    ModelDef("gpt-4o",      "openai", "openai", context_window=128_000, max_output=16_384, input_cost_per_mtok=2.5,  output_cost_per_mtok=10.0),
    ModelDef("gpt-4o-mini", "openai", "openai", context_window=128_000, max_output=16_384, input_cost_per_mtok=0.15, output_cost_per_mtok=0.6),
    ModelDef("o3",          "openai", "openai", context_window=200_000, max_output=100_000, supports_thinking=True, input_cost_per_mtok=10.0, output_cost_per_mtok=40.0),
    ModelDef("o4-mini",     "openai", "openai", context_window=200_000, max_output=100_000, supports_thinking=True, input_cost_per_mtok=1.1,  output_cost_per_mtok=4.4),
]:
    register_model(_m)

# Google
for _m in [
    ModelDef("gemini-2.5-pro",   "google", "google", context_window=1_000_000, supports_thinking=True, input_cost_per_mtok=1.25, output_cost_per_mtok=10.0),
    ModelDef("gemini-2.5-flash", "google", "google", context_window=1_000_000, supports_thinking=True, input_cost_per_mtok=0.15, output_cost_per_mtok=0.6),
]:
    register_model(_m)

# Ollama (local, speaks OpenAI API, zero cost)
for _m in [
    ModelDef("llama3.2",      "ollama", "openai", context_window=128_000, base_url="http://localhost:11434/v1"),
    ModelDef("qwen2.5-coder", "ollama", "openai", context_window=128_000, base_url="http://localhost:11434/v1"),
    ModelDef("deepseek-r1",   "ollama", "openai", context_window=128_000, supports_thinking=True, base_url="http://localhost:11434/v1"),
]:
    register_model(_m)
