"""
Router - Complete routing pipeline.

Orchestrates the 5-node routing pipeline:
- Node 1: Task Detection
- Node 2: Capability Filter
- Node 3: Cost Optimization
- Node 4: Savings Calculation
- Node 5: Response Builder
"""

from typing import Any

from robot_resources.routing.selector import (
    CAPABILITY_THRESHOLD,
    MODELS_DB,
    calculate_savings,
    get_capable_models,
    rank_capable_models,
    select_cheapest_model,
)
from robot_resources.routing.task_detection import (
    TaskType,
    analyze_prompt,
)


def route_prompt(
    prompt: str,
    models_db: list[dict] | None = None,
    threshold: float = CAPABILITY_THRESHOLD,
) -> dict[str, Any]:
    """
    Execute the complete routing pipeline.

    This is the main entry point for routing decisions.

    Args:
        prompt: The user's prompt to route
        models_db: Optional custom models database
        threshold: Minimum capability threshold (default: 0.70)

    Returns:
        Complete routing decision with model, cost, savings, and reasoning
    """
    db = models_db if models_db is not None else MODELS_DB

    # NODE 1: Detect task type
    analysis = analyze_prompt(prompt)
    task_type: TaskType = analysis["task_type"]
    confidence = analysis["confidence"]
    matched_keywords = analysis["matched_keywords"]

    # NODE 2: Get capable models
    capable_models = get_capable_models(task_type, db, threshold)

    # Fallback: if no capable models, lower threshold
    if not capable_models:
        capable_models = get_capable_models(task_type, db, threshold=0.5)

    # Final fallback: use all models
    if not capable_models:
        capable_models = db
        task_type = "general"

    # NODE 3: Select cheapest capable model
    selected_model = select_cheapest_model(capable_models)

    if selected_model is None:
        selected_model = db[0]

    # Rank all capable models for fallback (used by retry logic)
    ranked = rank_capable_models(capable_models)

    # NODE 4: Calculate savings
    savings = calculate_savings(selected_model, models_db=db)

    # NODE 5: Build response
    return _build_response(
        task_type=task_type,
        selected_model=selected_model,
        savings=savings,
        confidence=confidence,
        matched_keywords=matched_keywords,
        threshold=threshold,
        ranked_candidates=ranked,
    )


def _build_response(
    task_type: TaskType,
    selected_model: dict,
    savings: dict,
    confidence: float,
    matched_keywords: list[str],
    threshold: float,
    ranked_candidates: list[dict] | None = None,
) -> dict[str, Any]:
    """NODE 5: Build the final routing response."""
    capability = selected_model["capabilities"].get(
        task_type, selected_model["capabilities"].get("overall", 0)
    )

    # Build fallback candidates list (exclude the selected model)
    fallbacks = []
    if ranked_candidates:
        fallbacks = [
            {
                "name": m["name"],
                "provider": m["provider"],
                "cost_per_1k_input": m["cost_per_1k_input"],
            }
            for m in ranked_candidates
            if m["name"] != selected_model["name"]
        ]

    return {
        # Model selection
        "selected_model": selected_model["name"],
        "provider": selected_model["provider"],
        # Cost info
        "cost_per_1k_input": selected_model["cost_per_1k_input"],
        "cost_per_1k_output": selected_model["cost_per_1k_output"],
        # Savings vs baseline
        "baseline_model": savings["baseline_model"],
        "baseline_cost": savings["baseline_cost"],
        "savings_percent": savings["savings_percent"],
        # Task analysis
        "task_type": task_type,
        "capability_score": round(capability, 2),
        "detection_confidence": confidence,
        # Reasoning
        "reasoning": (
            f"Selected {selected_model['name']} ({selected_model['provider']}) "
            f"as cheapest model capable of '{task_type}' tasks "
            f"(capability: {capability:.2f}, threshold: {threshold}). "
            f"Saves {savings['savings_percent']}% vs {savings['baseline_model']}."
        ),
        # Metadata
        "matched_keywords": matched_keywords,
        "max_tokens": selected_model.get("max_tokens"),
        # Fallback candidates for retry logic (sorted by cost, excludes selected)
        "ranked_candidates": fallbacks,
    }
