"""Operator-facing cross-agent knowledge transfer surface."""

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,
    PromptRegistry,
    ReflectionMemory,
    RetrievalLearningEngine,
    SQLiteLearningStore,
    ToolWorkflowLearningEngine,
)
from logos_adk.learning.models import FeedbackRecord, OutcomeRecord, RunRecord
from logos_adk.learning.improvement.models import ReflectionLesson
from logos_adk.learning.prompt_registry import PromptRecommendation
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) % 13)
    return [base, base / 10.0, len(text) / 100.0]


def _seed_transfer_state(
    learning_store: SQLiteLearningStore,
    prompt_registry: PromptRegistry,
    reflection_memory: ReflectionMemory,
    retrieval: RetrievalLearningEngine,
    tool_workflow: ToolWorkflowLearningEngine,
    routing: ModelRoutingLearningEngine,
) -> None:
    reflection_memory.save_lesson(
        ReflectionLesson(
            id="lesson-transfer-1",
            workspace_id="acme",
            agent_name="source-bot",
            category="retrieval_policy",
            lesson="Prefer the refund policy source.",
            rationale="Repeated corrections show the policy source resolves the issue.",
            suggested_action="Use the refund policy source and increase grounding.",
            confidence=0.9,
            metadata={"scope": "shared", "task_type": "support", "user_segment": "vip"},
        )
    )
    prompt_registry.ensure_prompt("source-bot")
    prompt_registry.save_recommendation(
        PromptRecommendation(
            id="rec-source",
            prompt_name="source-bot",
            kind="prompt_patch",
            title="Transferred support patch",
            summary="Use explicit grounded refund-policy wording.",
            proposed_patch="+ Answer only from the approved refund policy.",
            metadata={"scope": "shared", "task_type": "support", "user_segment": "vip"},
        )
    )
    retrieval.record_retrieval(
        trace_id="trace-source",
        session_id="session-source",
        workspace_id="acme",
        task_type="support",
        user_segment="vip",
        prompt_name="source-bot",
        prompt_version="v1",
        original_query="refund policy",
        effective_query="approved refund policy source",
        limit=4,
        filter={"category": "policy"},
        chunks=[
            Chunk(
                content="Approved refund policy details.",
                metadata={"source_key": "docs://refund-policy"},
                document_id="doc-1",
            )
        ],
    )
    learning_store.create_feedback(
        FeedbackRecord(
            id="fb-source-transfer",
            kind="thumbs_up",
            trace_id="trace-source",
            workspace_id="acme",
            agent_name="source-bot",
            prompt_version="v1",
            model="MockProvider:strong",
            metadata={"accepted_contexts": ["doc-1"]},
        )
    )
    learning_store.create_outcome(
        OutcomeRecord(
            id="out-source-transfer",
            kind="resolution",
            trace_id="trace-source",
            workspace_id="acme",
            agent_name="source-bot",
            prompt_version="v1",
            model="MockProvider:strong",
            value=True,
        )
    )
    retrieval.sync_trace("trace-source", learning_store)
    for _ in range(3):
        tool_workflow.record_tool_call(
            tool_name="policy_lookup",
            success=True,
            duration_ms=12,
            task_type="support",
            workspace_id="acme",
        )
        routing.record_route(
            model_key="MockProvider:strong",
            success=True,
            latency_ms=40,
            cost_usd=0.0015,
            confidence_tier="low",
            workspace_id="acme",
            task_type="support",
            quality_score=0.9,
        )

    learning_store.create_run(
        RunRecord(
            id="run-target-local",
            trace_id="trace-target-local",
            request_id="req-target-local",
            agent_name="target-bot",
            input_text="How do refunds work?",
            output_text="rough answer",
            workspace_id="acme",
            session_id="session-1",
            prompt_version="v1",
            model="gpt-4o-mini",
            config_fingerprint="cfg-v1",
            usage={"input_tokens": 800, "output_tokens": 150},
            metadata={"task_type": "support", "user_segment": "vip", "latency_ms": 400},
        )
    )
    learning_store.create_feedback(
        FeedbackRecord(
            id="fb-target-local",
            kind="thumbs_down",
            run_id="run-target-local",
            trace_id="trace-target-local",
            workspace_id="acme",
            agent_name="target-bot",
            prompt_version="v1",
            model="gpt-4o-mini",
            failure_types=["style_miss"],
        )
    )

    learning_store.create_run(
        RunRecord(
            id="run-target-transfer",
            trace_id="trace-target-transfer",
            request_id="req-target-transfer",
            agent_name="target-bot",
            input_text="How do refunds work?",
            output_text="approved refund answer",
            workspace_id="acme",
            session_id="session-2",
            prompt_version="v2",
            model="gpt-4o-mini",
            config_fingerprint="cfg-v2",
            usage={"input_tokens": 700, "output_tokens": 120},
            metadata={
                "task_type": "support",
                "user_segment": "vip",
                "latency_ms": 220,
                "transfer_source_agent": "source-bot",
            },
        )
    )
    learning_store.create_feedback(
        FeedbackRecord(
            id="fb-target-transfer",
            kind="thumbs_up",
            run_id="run-target-transfer",
            trace_id="trace-target-transfer",
            workspace_id="acme",
            agent_name="target-bot",
            prompt_version="v2",
            model="gpt-4o-mini",
        )
    )
    learning_store.create_outcome(
        OutcomeRecord(
            id="out-target-transfer",
            kind="conversion",
            run_id="run-target-transfer",
            trace_id="trace-target-transfer",
            workspace_id="acme",
            agent_name="target-bot",
            prompt_version="v2",
            model="gpt-4o-mini",
            value=True,
        )
    )


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

    learning_store = SQLiteLearningStore(str(tmp_path / "learning.db"))
    prompt_registry = PromptRegistry(str(tmp_path / "prompts.db"))
    reflection_path = tmp_path / "reflection.db"
    reflection_memory = ReflectionMemory(str(reflection_path))
    retrieval = RetrievalLearningEngine(path=str(tmp_path / "retrieval.db"))
    tool_workflow = ToolWorkflowLearningEngine(path=str(tmp_path / "tool_workflow.db"))
    routing = ModelRoutingLearningEngine(path=str(tmp_path / "routing.db"))
    _seed_transfer_state(
        learning_store, prompt_registry, reflection_memory, retrieval, tool_workflow, routing
    )
    monkeypatch.setenv("LOGOS_ADK_REFLECTION_DB_PATH", str(reflection_path))

    kb = KnowledgeBase(store=InMemoryVectorStore(), embed_fn=_embed, retrieval_learning=retrieval)
    agent = (
        Agent("source-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, prompt_registry=prompt_registry)

    artifacts = await _request(
        app,
        "GET",
        "/learning/transfer/artifacts?source_agent_name=source-bot&workspace_id=acme&task_type=support&user_segment=vip&limit=20",
    )
    recommend = await _request(
        app,
        "POST",
        "/learning/transfer/recommend",
        json={
            "source_agent_name": "source-bot",
            "target_agent_name": "target-bot",
            "workspace_id": "acme",
            "task_type": "support",
            "user_segment": "vip",
            "safe_apply": True,
            "limit": 20,
        },
    )
    apply_result = await _request(
        app,
        "POST",
        "/learning/transfer/apply",
        json={
            "source_agent_name": "source-bot",
            "target_agent_name": "target-bot",
            "workspace_id": "acme",
            "task_type": "support",
            "user_segment": "vip",
            "safe_apply": False,
            "limit": 20,
        },
    )
    uplift = await _request(
        app,
        "GET",
        "/learning/transfer/uplift?target_agent_name=target-bot&workspace_id=acme&limit=20",
    )

    assert artifacts.status_code == 200
    assert recommend.status_code == 200
    assert apply_result.status_code == 200
    assert uplift.status_code == 200

    artifacts_payload = artifacts.json()["items"]
    recommend_payload = recommend.json()["items"]
    apply_payload = apply_result.json()["result"]
    uplift_payload = uplift.json()["report"]

    assert any(item["kind"] == "reflection_lesson" for item in artifacts_payload)
    assert any(item["kind"] == "prompt_patch" for item in artifacts_payload)
    assert any(item["kind"] == "retrieval_profile" for item in artifacts_payload)
    assert any(item["kind"] == "tool_preference" for item in artifacts_payload)
    assert any(item["kind"] == "routing_policy" for item in artifacts_payload)
    assert recommend_payload
    assert recommend_payload[0]["status"] == "recommended"
    assert apply_payload["applied"] >= 1
    assert uplift_payload["transferred_runs"] == 1
    assert uplift_payload["local_runs"] == 1
    assert uplift_payload["delta"] > 0.0

    runner = CliRunner()
    artifacts_cli = runner.invoke(
        cli,
        [
            "transfer",
            "artifacts",
            "--db-path",
            str(tmp_path / "learning.db"),
            "--reflection-db-path",
            str(reflection_path),
            "--prompt-registry-path",
            str(tmp_path / "prompts.db"),
            "--retrieval-db-path",
            str(tmp_path / "retrieval.db"),
            "--tool-workflow-db-path",
            str(tmp_path / "tool_workflow.db"),
            "--model-routing-db-path",
            str(tmp_path / "routing.db"),
            "--source-agent-name",
            "source-bot",
            "--workspace-id",
            "acme",
            "--task-type",
            "support",
            "--user-segment",
            "vip",
        ],
    )
    recommend_cli = runner.invoke(
        cli,
        [
            "transfer",
            "recommend",
            "--db-path",
            str(tmp_path / "learning.db"),
            "--reflection-db-path",
            str(reflection_path),
            "--prompt-registry-path",
            str(tmp_path / "prompts.db"),
            "--retrieval-db-path",
            str(tmp_path / "retrieval.db"),
            "--tool-workflow-db-path",
            str(tmp_path / "tool_workflow.db"),
            "--model-routing-db-path",
            str(tmp_path / "routing.db"),
            "--source-agent-name",
            "source-bot",
            "--target-agent-name",
            "target-bot",
            "--workspace-id",
            "acme",
            "--task-type",
            "support",
            "--user-segment",
            "vip",
        ],
    )
    apply_cli = runner.invoke(
        cli,
        [
            "transfer",
            "apply",
            "--db-path",
            str(tmp_path / "learning.db"),
            "--reflection-db-path",
            str(reflection_path),
            "--prompt-registry-path",
            str(tmp_path / "prompts.db"),
            "--retrieval-db-path",
            str(tmp_path / "retrieval.db"),
            "--tool-workflow-db-path",
            str(tmp_path / "tool_workflow.db"),
            "--model-routing-db-path",
            str(tmp_path / "routing.db"),
            "--source-agent-name",
            "source-bot",
            "--target-agent-name",
            "target-bot",
            "--workspace-id",
            "acme",
            "--task-type",
            "support",
            "--user-segment",
            "vip",
            "--apply",
        ],
    )
    uplift_cli = runner.invoke(
        cli,
        [
            "transfer",
            "uplift",
            "--db-path",
            str(tmp_path / "learning.db"),
            "--reflection-db-path",
            str(reflection_path),
            "--prompt-registry-path",
            str(tmp_path / "prompts.db"),
            "--retrieval-db-path",
            str(tmp_path / "retrieval.db"),
            "--tool-workflow-db-path",
            str(tmp_path / "tool_workflow.db"),
            "--model-routing-db-path",
            str(tmp_path / "routing.db"),
            "--target-agent-name",
            "target-bot",
            "--workspace-id",
            "acme",
        ],
    )

    assert artifacts_cli.exit_code == 0
    assert "source_agent=source-bot artifacts=" in artifacts_cli.output
    assert recommend_cli.exit_code == 0
    assert "recommendations=" in recommend_cli.output
    assert apply_cli.exit_code == 0
    assert "applied=" in apply_cli.output
    assert uplift_cli.exit_code == 0
    assert "delta=" in uplift_cli.output
