"""Operator-facing HTTP/CLI surface and observability for model routing."""

from __future__ import annotations

import httpx
from click.testing import CliRunner
import pytest

from logos_adk.agent import Agent
from logos_adk.cli import cli
from logos_adk.learning import ModelRoutingLearningEngine, SQLiteLearningStore
from logos_adk.observe import get_observability_store
from logos_adk.providers.mock import MockProvider


async def _request(app, method: str, path: str, **kwargs):
    transport = httpx.ASGITransport(app=app)
    async with httpx.AsyncClient(transport=transport, base_url="http://testserver") as client:
        return await client.request(method, path, **kwargs)


@pytest.mark.asyncio
async def test_model_routing_http_cli_and_observability_surface(tmp_path):
    from logos_adk.serve import create_app

    get_observability_store().reset()

    engine = ModelRoutingLearningEngine(path=str(tmp_path / "model_routing.db"))
    engine.set_budget(workspace_id="acme", task_type="support", soft_limit_usd=0.01, threshold_ratio=0.5)
    engine.register_canary(
        model_key="MockProvider:canary-model",
        rollout_percentage=100,
        workspace_id="acme",
        task_type="support",
    )
    engine.record_route(
        model_key="MockProvider:baseline-model",
        success=True,
        latency_ms=20,
        cost_usd=0.0002,
        confidence_tier="low",
        workspace_id="acme",
        task_type="support",
        quality_score=0.2,
    )
    engine.record_route(
        model_key="MockProvider:canary-model",
        success=True,
        latency_ms=18,
        cost_usd=0.0003,
        confidence_tier="low",
        workspace_id="acme",
        task_type="support",
        quality_score=0.8,
        was_canary=True,
    )

    baseline = MockProvider(responses=["baseline"])
    baseline.model_name = "baseline-model"
    canary = MockProvider(responses=["canary"])
    canary.model_name = "canary-model"
    agent = Agent("router").model(baseline).fallback(canary).model_routing_learning(engine)

    learning_store = SQLiteLearningStore(str(tmp_path / "learning.db"))
    app = create_app([agent], learning_store=learning_store)

    run_response = await _request(
        app,
        "POST",
        "/run",
        json={"prompt": "Need a short support reply", "session_id": "lead-1"},
        headers={
            "X-Workspace-Id": "acme",
            "X-Task-Type": "support",
            "X-Trace-Id": "trace-routing-1",
        },
    )
    assert run_response.status_code == 200
    assert run_response.json()["content"] == "canary"

    feedback_response = await _request(
        app,
        "POST",
        "/feedback",
        json={"trace_id": "trace-routing-1", "kind": "thumbs_up"},
        headers={"X-Workspace-Id": "acme"},
    )
    outcome_response = await _request(
        app,
        "POST",
        "/outcomes",
        json={"trace_id": "trace-routing-1", "kind": "conversion", "value": True},
        headers={"X-Workspace-Id": "acme"},
    )
    assert feedback_response.status_code == 200
    assert outcome_response.status_code == 200

    leaderboard = await _request(
        app,
        "GET",
        "/learning/model-routing/leaderboard?workspace_id=acme&task_type=support&confidence_tier=low",
    )
    budget = await _request(
        app,
        "GET",
        "/learning/model-routing/budget-status?workspace_id=acme&task_type=support",
    )
    canaries = await _request(
        app,
        "GET",
        "/learning/model-routing/canaries?workspace_id=acme&task_type=support&status=active",
    )
    decision = await _request(
        app,
        "GET",
        "/learning/model-routing/decision?workspace_id=acme&task_type=support&assignment_key=session-1&prompt=Need+a+short+support+reply&model_key=MockProvider:baseline-model&model_key=MockProvider:canary-model",
    )

    assert leaderboard.status_code == 200
    assert budget.status_code == 200
    assert canaries.status_code == 200
    assert decision.status_code == 200

    leaderboard_payload = leaderboard.json()
    budget_payload = budget.json()
    canaries_payload = canaries.json()
    decision_payload = decision.json()

    assert leaderboard_payload["items"][0]["model_key"] == "MockProvider:canary-model"
    assert budget_payload["workspace_id"] == "acme"
    assert "ratio" in budget_payload
    assert canaries_payload["items"][0]["model_key"] == "MockProvider:canary-model"
    assert decision_payload["decision"]["selected_model_key"] == "MockProvider:canary-model"
    assert decision_payload["decision"]["used_canary"] is True

    routing_metrics = await _request(app, "GET", "/observability/metrics?name=adk_model_routing_win_rate")
    budget_metrics = await _request(app, "GET", "/observability/metrics?name=adk_model_routing_budget_pressure")
    canary_delta_metrics = await _request(
        app,
        "GET",
        "/observability/metrics?name=adk_model_routing_canary_outcome_delta",
    )
    dashboard = await _request(app, "GET", "/observability/grafana/dashboard")
    summary = await _request(app, "GET", "/observability/summary")

    assert routing_metrics.status_code == 200
    assert budget_metrics.status_code == 200
    assert canary_delta_metrics.status_code == 200
    assert dashboard.status_code == 200
    assert summary.status_code == 200
    assert any(item["name"] == "adk_model_routing_win_rate" for item in routing_metrics.json()["items"])
    assert any(item["name"] == "adk_model_routing_budget_pressure" for item in budget_metrics.json()["items"])
    assert any(
        item["name"] == "adk_model_routing_canary_outcome_delta"
        for item in canary_delta_metrics.json()["items"]
    )
    assert any(panel["title"] == "Model Routing Win Rate" for panel in dashboard.json()["panels"])
    assert any(panel["title"] == "Model Routing Budget Pressure" for panel in dashboard.json()["panels"])
    assert any(panel["title"] == "Canary Outcome Delta" for panel in dashboard.json()["panels"])
    assert "avg_model_routing_win_rate" in summary.json()["totals"]
    assert "model_routing_budget_pressure" in summary.json()["totals"]
    assert "model_routing_canary_outcome_delta" in summary.json()["totals"]

    runner = CliRunner()
    leaderboard_cli = runner.invoke(
        cli,
        [
            "model-routing",
            "leaderboard",
            "--db-path",
            str(tmp_path / "model_routing.db"),
            "--workspace-id",
            "acme",
            "--task-type",
            "support",
            "--confidence-tier",
            "low",
        ],
    )
    budget_cli = runner.invoke(
        cli,
        [
            "model-routing",
            "budget-status",
            "--db-path",
            str(tmp_path / "model_routing.db"),
            "--workspace-id",
            "acme",
            "--task-type",
            "support",
        ],
    )
    canaries_cli = runner.invoke(
        cli,
        [
            "model-routing",
            "canaries",
            "--db-path",
            str(tmp_path / "model_routing.db"),
            "--workspace-id",
            "acme",
            "--task-type",
            "support",
        ],
    )
    decision_cli = runner.invoke(
        cli,
        [
            "model-routing",
            "decision",
            "--db-path",
            str(tmp_path / "model_routing.db"),
            "--workspace-id",
            "acme",
            "--task-type",
            "support",
            "--assignment-key",
            "session-1",
            "--prompt",
            "Need a short support reply",
            "--model-key",
            "MockProvider:baseline-model",
            "--model-key",
            "MockProvider:canary-model",
        ],
    )

    assert leaderboard_cli.exit_code == 0
    assert "MockProvider:canary-model" in leaderboard_cli.output
    assert budget_cli.exit_code == 0
    assert "spent_usd=" in budget_cli.output
    assert canaries_cli.exit_code == 0
    assert "canary-model" in canaries_cli.output
    assert decision_cli.exit_code == 0
    assert "selected=MockProvider:canary-model" in decision_cli.output
