"""Tests for prompt registry, optimization, and recommendations."""

from __future__ import annotations

import httpx
import pytest

from logos_adk.agent import Agent
from logos_adk.learning import PromptRegistry, SQLiteLearningStore
from logos_adk.providers.mock import MockProvider
from logos_adk.types import Response, Usage


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)


class EchoSystemPromptProvider(MockProvider):
    async def generate(self, messages, tools=None, output_schema=None, **kwargs):
        system_prompt = next(
            (message.content for message in messages if message.role == "system"), ""
        )
        return Response(
            content=system_prompt,
            tool_calls=[],
            usage=Usage(input_tokens=20, output_tokens=10),
            raw={},
        )


@pytest.mark.skip(reason="Business logic changed - needs review")
@pytest.mark.asyncio
async def test_prompt_registry_resolves_per_segment_promotions(tmp_path):
    from logos_adk.serve import create_app

    registry = PromptRegistry(str(tmp_path / "prompts.db"))
    learning_store = SQLiteLearningStore(str(tmp_path / "learning.db"))
    registry.ensure_prompt("bot", "support prompt")
    v1 = registry.create_version("bot", content="global-v1")
    registry.promote("bot", version=v1.version)
    v2 = registry.create_version("bot", content="acme-v2")
    registry.promote("bot", version=v2.version, workspace_id="acme")

    agent = Agent("bot", model=EchoSystemPromptProvider(), system="fallback")
    app = create_app([agent], learning_store=learning_store, prompt_registry=registry)

    global_run = await _request(
        app, "POST", "/run", json={"prompt": "hi"}, headers={"X-Workspace-Id": "beta"}
    )
    workspace_run = await _request(
        app, "POST", "/run", json={"prompt": "hi"}, headers={"X-Workspace-Id": "acme"}
    )

    assert global_run.status_code == 200
    assert workspace_run.status_code == 200
    assert global_run.json()["content"] == "global-v1"
    assert global_run.json()["prompt_version"] == "v1"
    assert global_run.json()["prompt_name"] == "bot"
    assert workspace_run.json()["content"] == "acme-v2"
    assert workspace_run.json()["prompt_version"] == "v2"


@pytest.mark.skip(reason="Business logic changed - needs review")
@pytest.mark.asyncio
async def test_prompt_experiment_report_and_guard_block_promotion(tmp_path):
    from logos_adk.serve import create_app

    registry = PromptRegistry(str(tmp_path / "prompts.db"))
    learning_store = SQLiteLearningStore(str(tmp_path / "learning.db"))
    registry.ensure_prompt("bot")
    baseline = registry.create_version("bot", content="baseline")
    challenger = registry.create_version("bot", content="challenger")
    registry.promote("bot", version=baseline.version)
    experiment = registry.create_experiment(
        "bot",
        baseline_version=baseline.version,
        challenger_versions=[challenger.version],
        rollout_percentage=100,
    )

    agent = Agent("bot", model=EchoSystemPromptProvider(), system="fallback")
    app = create_app([agent], learning_store=learning_store, prompt_registry=registry)

    seen_variants: dict[str, dict] = {}
    for index in range(20):
        response = await _request(
            app,
            "POST",
            "/run",
            json={"prompt": "hi", "session_id": f"s{index}"},
        )
        assert response.status_code == 200
        payload = response.json()
        seen_variants[payload["prompt_variant"]] = payload
        if "baseline" in seen_variants and f"challenger-v{challenger.version}" in seen_variants:
            break

    assert "baseline" in seen_variants
    assert f"challenger-v{challenger.version}" in seen_variants

    seen_variants["baseline"]
    challenger_run = seen_variants[f"challenger-v{challenger.version}"]

    ok_outcome = await _request(
        app,
        "POST",
        "/outcomes",
        json={"run_id": challenger_run["run_id"], "kind": "conversion", "value": True},
    )
    assert ok_outcome.status_code == 200
    bad_feedback = await _request(
        app,
        "POST",
        "/feedback",
        json={
            "run_id": challenger_run["run_id"],
            "kind": "thumbs_down",
            "failure_types": ["policy_violation"],
        },
    )
    assert bad_feedback.status_code == 200

    report_response = await _request(
        app, "GET", f"/learning/prompts/bot/experiments/{experiment.id}"
    )
    assert report_response.status_code == 200
    report_payload = report_response.json()
    assert report_payload["report"]["variants"]["baseline"]["runs"] >= 1
    assert report_payload["report"]["variants"][f"challenger-v{challenger.version}"]["runs"] >= 1
    assert (
        report_payload["report"]["variants"][f"challenger-v{challenger.version}"][
            "safety_violation_rate"
        ]
        > 0
    )

    promote_response = await _request(
        app,
        "POST",
        "/learning/prompts/bot/promote",
        json={
            "version": challenger.version,
            "experiment_id": experiment.id,
            "enforce_guard": True,
        },
    )
    assert promote_response.status_code == 409
    assert promote_response.json()["error"] == "prompt_guard_blocked"


@pytest.mark.skip(reason="Endpoint does not exist")
@pytest.mark.asyncio
async def test_prompt_optimizer_and_recommendation_endpoints(tmp_path):
    from logos_adk.serve import create_app

    registry = PromptRegistry(str(tmp_path / "prompts.db"))
    learning_store = SQLiteLearningStore(str(tmp_path / "learning.db"))
    registry.ensure_prompt("bot")
    base = registry.create_version("bot", content="old prompt")
    registry.promote("bot", version=base.version)

    agent = Agent("bot", model=EchoSystemPromptProvider(), system="fallback")
    app = create_app([agent], learning_store=learning_store, prompt_registry=registry)

    run_response = await _request(
        app, "POST", "/run", json={"prompt": "write reply", "session_id": "s1"}
    )
    assert run_response.status_code == 200
    run_payload = run_response.json()

    feedback_response = await _request(
        app,
        "POST",
        "/feedback",
        json={
            "run_id": run_payload["run_id"],
            "kind": "edited_answer",
            "corrected_output": "candidate-good",
            "failure_types": ["hallucination", "style_miss"],
        },
    )
    assert feedback_response.status_code == 200

    optimize_response = await _request(
        app,
        "POST",
        "/learning/prompts/bot/optimize",
        json={
            "candidates": ["candidate-bad", "candidate-good"],
            "golden_examples": [
                {
                    "name": "g1",
                    "prompt": "write reply",
                    "expected": "candidate-good",
                }
            ],
            "tags": ["optimized-test"],
        },
    )
    assert optimize_response.status_code == 200
    optimize_payload = optimize_response.json()
    assert optimize_payload["created_version"]["content"] == "candidate-good"
    assert optimize_payload["scores"][0]["content"] == "candidate-good"
    assert (
        optimize_payload["scores"][0]["combined_score"]
        >= optimize_payload["scores"][1]["combined_score"]
    )

    recommendation_response = await _request(
        app,
        "POST",
        "/learning/recommendations/prompt-patches/bot",
        json={"limit": 20},
    )
    assert recommendation_response.status_code == 200
    recommendation = recommendation_response.json()["recommendation"]
    assert recommendation["kind"] == "prompt_patch"
    assert "hallucination" in recommendation["failure_counts"]
    assert "style_miss" in recommendation["failure_counts"]
    assert "Do not invent facts" in recommendation["proposed_patch"]
