"""
Model Selector - Capability filtering and cost optimization.

Implements nodes 2-4 of the routing pipeline:
- Node 2: Filter models by capability threshold
- Node 3: Select cheapest capable model
- Node 4: Calculate savings vs baseline
"""

import json
from pathlib import Path
from typing import Any

from robot_resources.routing.task_detection import TaskType

# Load models database
_DB_PATH = Path(__file__).parent / "models_db.json"


def load_models_db() -> list[dict]:
    """Load the models capability database."""
    with open(_DB_PATH) as f:
        return json.load(f)


# Singleton DB instance
MODELS_DB: list[dict] = load_models_db()

# Default baseline model for savings comparison
DEFAULT_BASELINE = "gpt-4o"

# Minimum capability threshold for model selection
CAPABILITY_THRESHOLD = 0.70


def get_capable_models(
    task_type: TaskType,
    models_db: list[dict] | None = None,
    threshold: float = CAPABILITY_THRESHOLD,
) -> list[dict]:
    """
    NODE 2: Filter models by capability threshold for a task type.

    Args:
        task_type: The detected task type
        models_db: Optional custom models database
        threshold: Minimum capability score (default: 0.70)

    Returns:
        List of models that meet the capability threshold
    """
    db = models_db if models_db is not None else MODELS_DB

    capable = []
    for model in db:
        capability = model["capabilities"].get(task_type)
        if capability is None:
            capability = model["capabilities"].get("overall", 0)

        if capability >= threshold:
            capable.append(model)

    return capable


def select_cheapest_model(models: list[dict]) -> dict | None:
    """
    NODE 3: Select the cheapest model from a list.

    Args:
        models: List of capable models

    Returns:
        The cheapest model, or None if list is empty
    """
    if not models:
        return None

    return min(models, key=lambda m: m["cost_per_1k_input"])


def calculate_savings(
    selected_model: dict,
    baseline_model: dict | None = None,
    models_db: list[dict] | None = None,
) -> dict[str, Any]:
    """
    NODE 4: Calculate cost savings vs baseline.

    Args:
        selected_model: The model we're routing to
        baseline_model: Optional baseline for comparison
        models_db: Optional custom models database

    Returns:
        Dict with savings metrics
    """
    db = models_db if models_db is not None else MODELS_DB

    if baseline_model is None:
        baseline_model = next((m for m in db if m["name"] == DEFAULT_BASELINE), db[0])

    baseline_cost = baseline_model["cost_per_1k_input"]
    selected_cost = selected_model["cost_per_1k_input"]

    if baseline_cost > 0:
        savings_percent = ((baseline_cost - selected_cost) / baseline_cost) * 100
    else:
        savings_percent = 0.0

    return {
        "baseline_model": baseline_model["name"],
        "selected_model": selected_model["name"],
        "baseline_cost": baseline_cost,
        "selected_cost": selected_cost,
        "savings_percent": round(savings_percent, 1),
        "savings_per_1k_tokens": round(baseline_cost - selected_cost, 6),
    }


def rank_capable_models(models: list[dict]) -> list[dict]:
    """Rank capable models by cost (cheapest first).

    Returns all models sorted by ``cost_per_1k_input`` ascending.
    Used by retry logic to fall back to next-cheapest model from a
    different provider.
    """
    if not models:
        return []
    return sorted(models, key=lambda m: m["cost_per_1k_input"])


def get_model_by_name(name: str, models_db: list[dict] | None = None) -> dict | None:
    """Get a model by name from the database."""
    db = models_db if models_db is not None else MODELS_DB
    return next((m for m in db if m["name"] == name), None)
