"""Operator-facing HTTP/CLI surface for true improvement mechanisms."""

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,
    ReflectionMemory,
    RetrievalLearningEngine,
    SQLiteLearningStore,
    ToolWorkflowLearningEngine,
)
from logos_adk.learning.models import FeedbackRecord, OutcomeRecord, RunRecord
from logos_adk.learning.improvement.models import ReflectionLesson
from logos_adk.providers.mock import MockProvider
from logos_adk.rag import Chunk, KnowledgeBase
from logos_adk.rag.vector_store import InMemoryVectorStore


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)


def _embed(text: str) -> list[float]:
    base = float(sum(ord(char) for char in text) % 17)
    return [base, base / 10.0, len(text) / 100.0]


def _seed_learning_state(
    learning_store: SQLiteLearningStore,
    retrieval: RetrievalLearningEngine,
    routing: ModelRoutingLearningEngine,
    tool_workflow: ToolWorkflowLearningEngine,
) -> None:
    for index in range(2):
        run = RunRecord(
            id=f"run-{index}",
            trace_id=f"trace-{index}",
            request_id=f"req-{index}",
            agent_name="bot",
            input_text="Answer from the refund policy",
            output_text="rough answer",
            session_id="session-1",
            workspace_id="acme",
            prompt_version="v1",
            model="gpt-4o-mini",
            config_fingerprint="cfg-v1",
            usage={"input_tokens": 1000, "output_tokens": 250},
            metadata={
                "task_type": "support",
                "user_segment": "vip",
                "latency_ms": 320,
            },
        )
        learning_store.create_run(run)
        learning_store.create_feedback(
            FeedbackRecord(
                id=f"fb-{index}",
                kind="edited_answer",
                run_id=run.id,
                trace_id=run.trace_id,
                workspace_id="acme",
                agent_name="bot",
                prompt_version="v1",
                model="gpt-4o-mini",
                corrected_output="approved refund policy answer",
                expected_output="approved refund policy answer",
                failure_types=["bad_retrieval"],
            )
        )
        learning_store.create_outcome(
            OutcomeRecord(
                id=f"out-{index}",
                kind="resolution",
                run_id=run.id,
                trace_id=run.trace_id,
                workspace_id="acme",
                agent_name="bot",
                prompt_version="v1",
                model="gpt-4o-mini",
                value=True,
            )
        )

    retrieval.record_retrieval(
        trace_id="trace-0",
        session_id="session-1",
        workspace_id="acme",
        task_type="support",
        user_segment="vip",
        prompt_name="bot",
        prompt_version="v1",
        original_query="refund policy",
        effective_query="approved refund policy",
        limit=3,
        filter={"category": "policy"},
        chunks=[
            Chunk(
                content="Approved refund policy details.",
                metadata={"source_key": "docs://refund-policy"},
                document_id="doc-1",
            )
        ],
    )
    retrieval.sync_trace("trace-0", learning_store)

    for _ in range(3):
        routing.record_route(
            model_key="MockProvider:strong",
            success=True,
            latency_ms=45,
            cost_usd=0.002,
            confidence_tier="low",
            workspace_id="acme",
            task_type="support",
            quality_score=0.92,
        )
        routing.record_route(
            model_key="MockProvider:cheap",
            success=False,
            latency_ms=22,
            cost_usd=0.0002,
            confidence_tier="low",
            workspace_id="acme",
            task_type="support",
            quality_score=0.15,
        )
    tool_workflow.record_tool_call(
        tool_name="policy_lookup",
        success=True,
        duration_ms=11,
        task_type="support",
        workspace_id="acme",
    )
    tool_workflow.record_fallback(
        provider_key="MockProvider:backup-fast",
        success=True,
        duration_ms=18,
        task_type="support",
        workspace_id="acme",
    )


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

    learning_store = SQLiteLearningStore(str(tmp_path / "learning.db"))
    retrieval = RetrievalLearningEngine(path=str(tmp_path / "retrieval.db"))
    routing = ModelRoutingLearningEngine(path=str(tmp_path / "routing.db"))
    tool_workflow = ToolWorkflowLearningEngine(path=str(tmp_path / "tool_workflow.db"))
    _seed_learning_state(learning_store, retrieval, routing, tool_workflow)

    reflection_path = tmp_path / "reflection.db"
    reflection_memory = ReflectionMemory(str(reflection_path))
    reflection_memory.save_lesson(
        ReflectionLesson(
            id="lesson-1",
            workspace_id="acme",
            agent_name="bot",
            category="retrieval_policy",
            lesson="Recurring retrieval misses on refund questions.",
            rationale="Repeated edited answers indicate low-context quality.",
            suggested_action="Increase retrieval grounding and prefer the refund policy source.",
            confidence=0.8,
            source_run_ids=["run-0", "run-1"],
        )
    )
    monkeypatch.setenv("LOGOS_ADK_REFLECTION_DB_PATH", str(reflection_path))

    kb = KnowledgeBase(store=InMemoryVectorStore(), embed_fn=_embed, retrieval_learning=retrieval)
    agent = (
        Agent("bot", model=MockProvider(responses=["ok"]))
        .knowledge(kb, mode="memory", limit=2)
        .tool_workflow_learning(tool_workflow)
        .model_routing_learning(routing)
    )
    app = create_app([agent], learning_store=learning_store)

    reward_scores = await _request(
        app,
        "GET",
        "/learning/improvement/reward-scores?workspace_id=acme&agent_name=bot&limit=10",
    )
    policy = await _request(
        app,
        "GET",
        "/learning/improvement/policy?workspace_id=acme&task_type=support&user_segment=vip&confidence_tier=low",
    )
    training_export = await _request(
        app,
        "GET",
        "/learning/improvement/training-export?kind=dpo&workspace_id=acme&agent_name=bot&limit=10",
    )
    reward_trends = await _request(
        app,
        "GET",
        "/learning/improvement/reward-trends?workspace_id=acme&agent_name=bot&bucket=day&limit=10",
    )
    lessons = await _request(
        app,
        "GET",
        "/learning/improvement/reflection-lessons?workspace_id=acme&agent_name=bot&limit=10",
    )
    mine_lessons = await _request(
        app,
        "POST",
        "/learning/improvement/reflection-lessons/mine",
        json={"workspace_id": "acme", "agent_name": "bot", "limit": 10, "min_occurrences": 2},
    )
    patterns = await _request(
        app,
        "GET",
        "/learning/improvement/failure-patterns?workspace_id=acme&agent_name=bot&limit=10&min_occurrences=2",
    )
    root_cause_report = await _request(
        app,
        "GET",
        "/learning/improvement/root-cause-report?workspace_id=acme&agent_name=bot&limit=10&min_occurrences=2",
    )
    policy_export = await _request(
        app,
        "POST",
        "/learning/improvement/policy/export",
        json={
            "workspace_id": "acme",
            "task_type": "support",
            "user_segment": "vip",
            "confidence_tier": "low",
            "environment": "prod",
        },
    )
    critic_reviser = await _request(
        app,
        "POST",
        "/learning/improvement/critic-reviser/run",
        json={
            "prompt": "How should I answer the refund question?",
            "answer": "Use the docs.",
            "reference": "Answer with the approved refund policy details.",
            "failure_types": ["bad_retrieval"],
        },
    )

    assert reward_scores.status_code == 200
    assert policy.status_code == 200
    assert training_export.status_code == 200
    assert reward_trends.status_code == 200
    assert lessons.status_code == 200
    assert mine_lessons.status_code == 200
    assert patterns.status_code == 200
    assert root_cause_report.status_code == 200
    assert policy_export.status_code == 200
    assert critic_reviser.status_code == 200

    reward_payload = reward_scores.json()
    policy_payload = policy.json()["policy"]
    export_payload = training_export.json()["export"]
    trends_payload = reward_trends.json()
    lessons_payload = lessons.json()
    mined_lessons_payload = mine_lessons.json()
    patterns_payload = patterns.json()
    root_cause_payload = root_cause_report.json()["report"]
    policy_export_payload = policy_export.json()["export"]
    critic_reviser_payload = critic_reviser.json()["result"]

    assert reward_payload["summary"]["count"] == 2
    assert reward_payload["summary"]["average_reward"] > 0.0
    assert policy_payload["model_key"] == "MockProvider:strong"
    assert policy_payload["retrieval_limit"] == 3
    assert policy_payload["preferred_tools"][0] == "policy_lookup"
    assert export_payload["kind"] == "dpo"
    assert export_payload["records"][0]["chosen"] == "approved refund policy answer"
    assert trends_payload["summary"]["count"] >= 1
    assert trends_payload["items"][0]["average_reward"] > 0.0
    assert lessons_payload["items"][0]["category"] == "retrieval_policy"
    assert mined_lessons_payload["summary"]["created"] >= 1
    assert patterns_payload["items"][0]["signature"] == "bad_retrieval"
    assert root_cause_payload["sample_size"] == 2
    assert root_cause_payload["hypotheses"]
    assert root_cause_payload["correlations"]["segment"][0]["value"] == "support:vip"
    assert policy_export_payload["kind"] == "policy_export"
    assert policy_export_payload["config_patch"]["routing"]["model_key"] == "MockProvider:strong"
    assert critic_reviser_payload["review"]["should_revise"] is True
    assert (
        critic_reviser_payload["revision"]["improved_answer"]
        == "Answer with the approved refund policy details."
    )

    runner = CliRunner()
    reward_cli = runner.invoke(
        cli,
        [
            "improvement",
            "reward-scores",
            "--db-path",
            str(tmp_path / "learning.db"),
            "--workspace-id",
            "acme",
            "--agent-name",
            "bot",
        ],
    )
    policy_cli = runner.invoke(
        cli,
        [
            "improvement",
            "policy",
            "--db-path",
            str(tmp_path / "learning.db"),
            "--model-routing-db-path",
            str(tmp_path / "routing.db"),
            "--retrieval-db-path",
            str(tmp_path / "retrieval.db"),
            "--tool-workflow-db-path",
            str(tmp_path / "tool_workflow.db"),
            "--workspace-id",
            "acme",
            "--task-type",
            "support",
            "--user-segment",
            "vip",
            "--confidence-tier",
            "low",
        ],
    )
    export_cli = runner.invoke(
        cli,
        [
            "improvement",
            "training-export",
            "--db-path",
            str(tmp_path / "learning.db"),
            "--kind",
            "dpo",
            "--workspace-id",
            "acme",
            "--agent-name",
            "bot",
        ],
    )
    trends_cli = runner.invoke(
        cli,
        [
            "improvement",
            "reward-trends",
            "--db-path",
            str(tmp_path / "learning.db"),
            "--workspace-id",
            "acme",
            "--agent-name",
            "bot",
            "--bucket",
            "day",
        ],
    )
    lessons_cli = runner.invoke(
        cli,
        [
            "improvement",
            "reflection-lessons",
            "--reflection-db-path",
            str(reflection_path),
            "--workspace-id",
            "acme",
            "--agent-name",
            "bot",
        ],
    )
    mine_lessons_cli = runner.invoke(
        cli,
        [
            "improvement",
            "mine-reflection-lessons",
            "--db-path",
            str(tmp_path / "learning.db"),
            "--reflection-db-path",
            str(reflection_path),
            "--workspace-id",
            "acme",
            "--agent-name",
            "bot",
            "--min-occurrences",
            "2",
        ],
    )
    patterns_cli = runner.invoke(
        cli,
        [
            "improvement",
            "failure-patterns",
            "--db-path",
            str(tmp_path / "learning.db"),
            "--workspace-id",
            "acme",
            "--agent-name",
            "bot",
            "--min-occurrences",
            "2",
        ],
    )
    root_cause_cli = runner.invoke(
        cli,
        [
            "improvement",
            "root-cause-report",
            "--db-path",
            str(tmp_path / "learning.db"),
            "--workspace-id",
            "acme",
            "--agent-name",
            "bot",
            "--min-occurrences",
            "2",
        ],
    )
    export_policy_cli = runner.invoke(
        cli,
        [
            "improvement",
            "export-policy",
            "--db-path",
            str(tmp_path / "learning.db"),
            "--model-routing-db-path",
            str(tmp_path / "routing.db"),
            "--retrieval-db-path",
            str(tmp_path / "retrieval.db"),
            "--tool-workflow-db-path",
            str(tmp_path / "tool_workflow.db"),
            "--workspace-id",
            "acme",
            "--task-type",
            "support",
            "--user-segment",
            "vip",
            "--confidence-tier",
            "low",
            "--environment",
            "prod",
        ],
    )
    critic_reviser_cli = runner.invoke(
        cli,
        [
            "improvement",
            "critic-reviser",
            "--prompt",
            "How should I answer the refund question?",
            "--answer",
            "Use the docs.",
            "--reference",
            "Answer with the approved refund policy details.",
            "--failure-type",
            "bad_retrieval",
        ],
    )

    assert reward_cli.exit_code == 0
    assert "avg_reward=" in reward_cli.output
    assert policy_cli.exit_code == 0
    assert "model=MockProvider:strong" in policy_cli.output
    assert export_cli.exit_code == 0
    assert "kind=dpo" in export_cli.output
    assert trends_cli.exit_code == 0
    assert "latest_avg_reward=" in trends_cli.output
    assert lessons_cli.exit_code == 0
    assert "retrieval_policy" in lessons_cli.output
    assert mine_lessons_cli.exit_code == 0
    assert "created=" in mine_lessons_cli.output
    assert patterns_cli.exit_code == 0
    assert "bad_retrieval" in patterns_cli.output
    assert root_cause_cli.exit_code == 0
    assert "sample_size=2" in root_cause_cli.output
    assert export_policy_cli.exit_code == 0
    assert "environment=prod" in export_policy_cli.output
    assert critic_reviser_cli.exit_code == 0
    assert "revised=True" in critic_reviser_cli.output
