"""Lightweight routing decision endpoint (/v1/route).

Returns the Router's model recommendation for a given prompt WITHOUT
making any upstream API calls. Designed for plugins that need the
routing decision but handle the actual LLM call themselves (e.g.,
OpenClaw subscription users whose OAuth tokens can't be forwarded).

Response: { provider, model, task_type, savings_percent, reasoning }
"""

from __future__ import annotations

import asyncio

import structlog
from fastapi import APIRouter, Request
from fastapi.responses import JSONResponse

from robot_resources.keys import get_available_provider_names
from robot_resources.routing import async_route_prompt
from robot_resources.routing.selector import MODELS_DB
from robot_resources.tracking.telemetry import get_telemetry_reporter

router = APIRouter()
logger = structlog.get_logger()


@router.post("/v1/route", response_model=None)
async def route_decision(raw_request: Request):
    """Return the optimal model for a prompt without calling the upstream provider.

    Request body:
      - prompt: str (or messages array in Anthropic format)
      - providers: list[str] (optional) — restrict to these providers
        e.g. ["anthropic"] for subscription users

    Response: { provider, model, task_type, savings_percent, reasoning }
    """
    try:
        body = await raw_request.json()
    except Exception:
        return JSONResponse(
            status_code=400,
            content={"error": "Request body must be valid JSON."},
        )

    prompt = body.get("prompt", "")
    if not prompt:
        # Try extracting from messages array (Anthropic format)
        messages = body.get("messages", [])
        user_msgs = [m.get("content", "") for m in messages if m.get("role") == "user"]
        if user_msgs:
            last = user_msgs[-1]
            if isinstance(last, list):
                prompt = " ".join(
                    b.get("text", "") for b in last if b.get("type") == "text"
                )
            else:
                prompt = str(last)

    if not prompt:
        return JSONResponse(
            status_code=400,
            content={"error": "Provide 'prompt' or 'messages' in the request body."},
        )

    # Auto-detect which providers have API keys configured
    available_providers = get_available_provider_names()
    requested_providers = body.get("providers")

    # Determine effective provider set
    if available_providers and requested_providers and isinstance(requested_providers, list):
        effective_providers = available_providers & set(requested_providers)
    elif available_providers:
        effective_providers = available_providers
    elif requested_providers and isinstance(requested_providers, list):
        effective_providers = set(requested_providers)
    else:
        # No keys detected AND no providers specified — can't give a useful
        # recommendation.  Return error instead of recommending models the
        # caller may not have access to (e.g. Gemini for Anthropic-only users).
        return JSONResponse(
            status_code=400,
            content={
                "error": (
                    "No API keys detected and no 'providers' field in request. "
                    "Either configure API keys (ANTHROPIC_API_KEY, OPENAI_API_KEY, "
                    "GOOGLE_API_KEY) or pass 'providers' in the request body "
                    '(e.g. {"providers": ["anthropic"]}).'
                ),
            },
        )

    models_db = MODELS_DB
    if effective_providers:
        models_db = [m for m in MODELS_DB if m.get("provider") in effective_providers]

    if effective_providers is not None and not models_db:
        return JSONResponse(
            status_code=400,
            content={
                "error": (
                    f"No models available. Configured providers: "
                    f"{sorted(available_providers) if available_providers else []}. "
                    f"Requested providers: {requested_providers}. "
                    "Check API keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_API_KEY)."
                ),
            },
        )

    logger.info(
        "route_decision_request",
        prompt_length=len(prompt),
        providers_requested=requested_providers,
        providers_available=sorted(available_providers) if available_providers else None,
        providers_effective=sorted(effective_providers) if effective_providers else None,
    )

    decision = await async_route_prompt(prompt, models_db=models_db or None)

    # Platform telemetry — fire-and-forget so subscription users
    # (who use /v1/route advisory, not the HTTP proxy) also get dashboard data.
    # Estimate costs from model pricing in the routing decision.
    try:
        telemetry = get_telemetry_reporter()
        if telemetry.enabled:
            est_tokens = len(prompt.split())  # rough token estimate
            cost_input = decision.get("cost_per_1k_input", 0)
            cost_output = decision.get("cost_per_1k_output", 0)
            # Estimate: input tokens from prompt, output ~2x input
            cost_actual = (est_tokens * cost_input + est_tokens * 2 * cost_output) / 1000
            baseline_cost = decision.get("baseline_cost", 0)
            # Baseline cost estimate using same token counts
            if baseline_cost:
                cost_baseline = (
                    est_tokens * baseline_cost + est_tokens * 2 * baseline_cost
                ) / 1000
            else:
                cost_baseline = cost_actual * 5
            cost_saved = max(0, cost_baseline - cost_actual)

            event = telemetry.build_event(
                selected_model=decision.get("selected_model", ""),
                provider=decision.get("provider", "anthropic"),
                task_type=decision.get("task_type", ""),
                cost_actual=round(cost_actual, 6),
                cost_baseline=round(cost_baseline, 6),
                savings_percent=decision.get("savings_percent", 0),
                cost_saved=round(cost_saved, 6),
                latency_ms=0,
                input_tokens=est_tokens,
                output_tokens=est_tokens * 2,
                savings_mode="tokens",
            )
            asyncio.create_task(telemetry.areport_safe(event))
    except Exception:
        pass  # Never let telemetry break the route response

    return JSONResponse(
        content={
            "provider": decision.get("provider", "anthropic"),
            "model": decision.get("selected_model", ""),
            "task_type": decision.get("task_type", ""),
            "confidence": decision.get("confidence", 0),
            "savings_percent": decision.get("savings_percent", 0),
            "reasoning": decision.get("reasoning", ""),
            "available_providers": sorted(available_providers) if available_providers else [],
        },
    )
