from __future__ import annotations

import json
import re
import sys
import threading
from http.server import ThreadingHTTPServer
from pathlib import Path
from typing import Any
from urllib.error import HTTPError
from urllib.request import Request, urlopen

import pytest

ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "plugins" / "1c" / "agent"))

import agent_server as onec_agent  # noqa: E402
from core.observability import JsonlAuditStore  # noqa: E402

try:
    import yaml
except ModuleNotFoundError:
    yaml = None


def request_json(
    method: str,
    *,
    url: str,
    path: str,
    payload: dict[str, Any] | None = None,
    request_id: str | None = None,
) -> tuple[int, dict[str, Any], bool]:
    data = json.dumps(payload or {}).encode("utf-8") if payload is not None else None
    req = Request(
        f"{url}{path}",
        data=data,
        method=method,
        headers={"Content-Type": "application/json"},
    )
    if request_id:
        req.add_header("X-Request-Id", request_id)
    try:
        with urlopen(req, timeout=3) as response:
            body = response.read().decode("utf-8")
            return response.status, json.loads(body) if body else {}, False
    except HTTPError as exc:
        body = exc.read().decode("utf-8")
        return exc.code, json.loads(body) if body else {}, True


def request_raw(method: str, *, url: str, path: str) -> tuple[int, str]:
    req = Request(f"{url}{path}", method=method)
    try:
        with urlopen(req, timeout=3) as response:
            return response.status, response.read().decode("utf-8")
    except HTTPError as exc:
        return exc.code, exc.read().decode("utf-8", errors="replace")


@pytest.fixture
def onec_agent_server(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
    monkeypatch.setattr(
        onec_agent,
        "route_for_model",
        lambda model_id=None, *, plugin=onec_agent.DEFAULT_PLUGIN: {
            "plugin": plugin,
            "model": {"id": model_id or "stub-model", "task": ["1c"]},
            "base_url": "http://127.0.0.1:8000",
            "served_model_name": "stub-model",
            "container_name": None,
            "host": None,
            "role": None,
        },
    )
    monkeypatch.setattr(
        onec_agent,
        "call_model",
        lambda provider, model, messages, temperature=0.2, max_tokens=1200, base_url=None: {
            "text": f"Stub answer for {model} via {provider.name}",
            "raw": {"model": model, "provider": provider.name, "messages": messages},
            "latency_ms": 0,
            "provider_base_url": base_url or provider.base_url,
        },
    )
    providers = {
        "default": onec_agent.ProviderConfig(
            name="default",
            data={
                "type": "openai-compatible",
                "base_url": "http://127.0.0.1:8000",
                "model": "stub-model",
            },
        ),
    }
    store = onec_agent.Store(tmp_path / "onec-agent.db")
    audit_store = JsonlAuditStore(tmp_path / "reports" / "observability" / "onec-agent", service="onec-agent")

    def _handler(*args: Any, **kwargs: Any) -> None:
        onec_agent.AgentHandler(
            *args,
            store=store,
            providers=providers,
            system_prompt="Ты помощник по 1С",
            audit_store=audit_store,
            **kwargs,
        )

    server = ThreadingHTTPServer(("127.0.0.1", 0), _handler)
    thread = threading.Thread(target=server.serve_forever, kwargs={"poll_interval": 0.05}, daemon=True)
    thread.start()

    try:
        yield {
            "url": f"http://127.0.0.1:{server.server_address[1]}",
            "audit_root": str(tmp_path / "reports" / "observability" / "onec-agent"),
        }
    finally:
        server.shutdown()
        thread.join(timeout=3)
        server.server_close()


def _assert_has_trace(payload: dict[str, Any], expected: str | None = None) -> None:
    trace = payload.get("trace_id")
    assert isinstance(trace, str)
    if expected is not None:
        assert trace == expected
        return
    assert re.fullmatch(r"[0-9a-f]{32}", trace) is not None


def test_health_is_alive(onec_agent_server: dict[str, str]) -> None:
    status, payload, is_error = request_json("GET", url=onec_agent_server["url"], path="/v1/health")
    assert not is_error
    assert status == 200
    assert payload["status"] == "ok"
    _assert_has_trace(payload)


def test_ui_served(onec_agent_server: dict[str, str]) -> None:
    url = onec_agent_server["url"]
    status, body = request_raw("GET", url=url, path="/")
    assert status == 200
    assert "<title>1С Agent</title>" in body

    status, js_body = request_raw("GET", url=url, path="/ui/assets/app.js")
    assert status == 200
    assert "sendTurn" in js_body


def test_state_endpoint(onec_agent_server: dict[str, str]) -> None:
    url = onec_agent_server["url"]

    request_json("POST", url=url, path="/v1/projects", payload={"name": "Состояние"})
    request_json("POST", url=url, path="/v1/projects", payload={"name": "Состояние-2"})
    status, listing, _ = request_json("GET", url=url, path="/v1/projects")
    project_id = listing["projects"][0]["id"]
    status, got_project, _ = request_json("GET", url=url, path=f"/v1/projects/{project_id}")
    assert status == 200
    assert got_project["project"]["id"] == project_id
    request_json("POST", url=url, path=f"/v1/projects/{project_id}/chats", payload={"title": "СтатусДиалог"})

    status, state, is_error = request_json("GET", url=url, path="/v1/state")
    assert not is_error
    assert status == 200
    assert state["service"] == "onec-agent"
    assert state["state"]["projects"] >= 2
    assert state["state"]["chats"] >= 1
    assert "started_at" in state
    assert "uptime_seconds" in state
    assert "default" in state["providers"]["ids"]
    _assert_has_trace(state)


def test_openapi_contract_smoke() -> None:
    contract = ROOT / "plugins" / "1c" / "agent" / "openapi.yaml"
    assert contract.exists()
    if yaml is None:
        return

    with contract.open("r", encoding="utf-8") as stream:
        data = yaml.safe_load(stream)

    assert data["openapi"].startswith("3.")
    paths = set(data.get("paths", {}).keys())
    expected = {
        "/v1/health",
        "/v1/state",
        "/v1/projects",
        "/v1/projects/{project_id}",
        "/v1/projects/{project_id}/chats",
        "/v1/projects/{project_id}/chats/{chat_id}",
        "/v1/projects/{project_id}/chats/{chat_id}/messages",
        "/v1/projects/{project_id}/chats/{chat_id}/runtime",
        "/v1/projects/{project_id}/chats/{chat_id}/turn",
        "/v1/projects/{project_id}/chats/{chat_id}/onec-tool",
        "/v1/models",
        "/v1/providers",
    }
    assert expected.issubset(paths)


def test_project_chat_crud_flow(onec_agent_server: dict[str, str]) -> None:
    url = onec_agent_server["url"]

    status, created, _ = request_json(
        "POST",
        url=url,
        path="/v1/projects",
        payload={"name": "Проект", "description": "Исходный", "metadata": {"owner": "test"}},
        request_id="req-1",
    )
    assert status == 201
    project_id = created["project"]["id"]
    _assert_has_trace(created, expected="req-1")

    status, listing, _ = request_json("GET", url=url, path="/v1/projects")
    assert status == 200
    assert [p["id"] for p in listing["projects"]] == [project_id]

    status, updated, _ = request_json("PATCH", url=url, path=f"/v1/projects/{project_id}", payload={"description": "Обновленный"})
    assert status == 200
    assert updated["project"]["description"] == "Обновленный"

    status, chat_created, _ = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats",
        payload={"title": "Диалог", "temperature": 0.12, "max_tokens": 512},
    )
    assert status == 201
    chat_id = chat_created["chat"]["id"]
    status, got_chat, _ = request_json("GET", url=url, path=f"/v1/projects/{project_id}/chats/{chat_id}")
    assert status == 200
    assert got_chat["chat"]["id"] == chat_id

    status, messages_before, _ = request_json(
        "GET",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/messages",
    )
    assert status == 200
    assert messages_before["messages"] == []

    status, _msg, _ = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/messages",
        payload={"role": "user", "content": "Проверка"},
    )
    assert status == 201

    status, messages, _ = request_json(
        "GET",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/messages?limit=10",
    )
    assert status == 200
    assert len(messages["messages"]) == 1
    assert messages["messages"][0]["content"] == "Проверка"

    status, chat, _ = request_json(
        "PATCH",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}",
        payload={"title": "Диалог 2", "rag_profile": "official", "temperature": 0.5},
    )
    assert status == 200
    assert chat["chat"]["title"] == "Диалог 2"
    assert chat["chat"]["temperature"] == 0.5

    status, bad, _is_error = request_json(
        "PATCH",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}",
        payload={"metadata": []},
    )
    assert status == 400
    assert bad["error"]["code"] == "invalid_argument"
    _assert_has_trace(bad)


def test_delete_and_validation_paths(onec_agent_server: dict[str, str]) -> None:
    url = onec_agent_server["url"]

    status, created, _ = request_json("POST", url=url, path="/v1/projects", payload={"name": "ДляУдаления"})
    project_id = created["project"]["id"]

    status, chat_created, _ = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats",
        payload={"title": "Удаляемый"},
    )
    chat_id = chat_created["chat"]["id"]

    status, bad, is_error = request_json(
        "GET",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/messages?limit=abc",
    )
    assert status == 400
    assert is_error
    assert bad["error"]["code"] == "invalid_argument"

    status, bad_limit, is_error = request_json(
        "GET",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/messages?limit=0",
    )
    assert status == 400
    assert is_error
    assert bad_limit["error"]["code"] == "invalid_argument"

    status, _, _ = request_json("DELETE", url=url, path=f"/v1/projects/{project_id}/chats/{chat_id}")
    assert status == 204

    status, _, is_error = request_json(
        "GET",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}",
    )
    assert status == 404
    assert is_error

    status, _, _ = request_json("DELETE", url=url, path=f"/v1/projects/{project_id}")
    assert status == 204

    status, _, is_error = request_json(
        "GET",
        url=url,
        path=f"/v1/projects/{project_id}",
    )
    assert status == 404
    assert is_error


def test_turn_runtime_question_fastpath(onec_agent_server: dict[str, str]) -> None:
    url = onec_agent_server["url"]

    status, project_data, _ = request_json("POST", url=url, path="/v1/projects", payload={"name": "Проверка runtime вопроса"})
    assert status == 201
    project_id = project_data["project"]["id"]

    status, chat_data, _ = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats",
        payload={"title": "Runtime"},
    )
    assert status == 201
    chat_id = chat_data["chat"]["id"]

    status, turn_data, is_error = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/turn",
        payload={"message": "Какая модель ии подключена? Какой адаптер и rag?"},
    )
    assert status == 200
    assert not is_error
    assert "runtime-конфигурация" in turn_data["assistant_message"]["content"]
    assert turn_data["assistant_message"]["payload"]["guardrail"] == {"type": "runtime_direct_answer"}
    assert turn_data["assistant_message"]["payload"]["raw"]["reason"] == "runtime_question_fastpath"
    _assert_has_trace(turn_data)


def test_turn_persists_full_payload_journal(onec_agent_server: dict[str, str]) -> None:
    url = onec_agent_server["url"]

    status, project_data, _ = request_json("POST", url=url, path="/v1/projects", payload={"name": "Журнал-чата"})
    assert status == 201
    project_id = project_data["project"]["id"]

    status, chat_data, _ = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats",
        payload={"title": "Смотрим payload"},
    )
    assert status == 201
    chat_id = chat_data["chat"]["id"]

    status, turn_data, _ = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/turn",
        payload={"message": "Опиши коротко, как проверить проблему в 1С.", "use_rag": True},
    )
    assert status == 200
    assistant_payload = turn_data["assistant_message"]["payload"]
    assert assistant_payload["transport"]["outbound"]["provider_id"]
    assert assistant_payload["transport"]["inbound"]["provider_response"]
    assert assistant_payload["transport"]["outbound"]["model"]["id"]
    user_payload = turn_data["user_message"]["payload"]
    assert user_payload["transport"]["outbound"]["runtime"]["history_limit"]

    status, all_messages, _ = request_json(
        "GET",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/messages?limit=50",
    )
    assert status == 200
    assert len(all_messages["messages"]) == 2
    assert "transport" in all_messages["messages"][0]["payload"]
    assert "transport" in all_messages["messages"][1]["payload"]


def test_turn_writes_audit_jsonl(onec_agent_server: dict[str, str]) -> None:
    url = onec_agent_server["url"]

    status, project_data, _ = request_json("POST", url=url, path="/v1/projects", payload={"name": "Audit log"}, request_id="req-audit-1")
    assert status == 201
    project_id = project_data["project"]["id"]

    status, chat_data, _ = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats",
        payload={"title": "Audit chat"},
        request_id="req-audit-2",
    )
    assert status == 201
    chat_id = chat_data["chat"]["id"]

    status, turn_data, is_error = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/turn",
        payload={"message": "Опиши коротко, как проверить проблему в 1С.", "use_rag": False},
        request_id="req-audit-3",
    )
    assert status == 200
    assert not is_error
    assert turn_data["turn_id"]

    audit_root = Path(onec_agent_server["audit_root"])
    access_files = sorted((audit_root / "access_events").glob("*.jsonl"))
    turn_files = sorted((audit_root / "turn_audit").glob("*.jsonl"))
    model_files = sorted((audit_root / "model_calls").glob("*.jsonl"))
    assert access_files
    assert turn_files
    assert model_files

    access_records = [json.loads(line) for line in access_files[-1].read_text(encoding="utf-8").splitlines() if line.strip()]
    turn_records = [json.loads(line) for line in turn_files[-1].read_text(encoding="utf-8").splitlines() if line.strip()]
    model_records = [json.loads(line) for line in model_files[-1].read_text(encoding="utf-8").splitlines() if line.strip()]

    assert any(record["request_id"] == "req-audit-3" and record["status_code"] == 200 for record in access_records)
    assert any(record["turn_id"] == turn_data["turn_id"] and record["outcome"] == "success" for record in turn_records)
    assert any(record["turn_id"] == turn_data["turn_id"] and record["served_model_name"] == "stub-model" for record in model_records)


def test_turn_builds_agent_context_with_rag_tools_and_order(
    onec_agent_server: dict[str, str],
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    url = onec_agent_server["url"]

    monkeypatch.setattr(
        onec_agent,
        "build_rag_prompt",
        lambda question, profile_name="auto", limit=None: {
            "prompt": f"RAG PROMPT profile={profile_name} limit={limit}: {question}",
            "profile": profile_name,
            "context_count": 1,
            "sources": [{"source_path": "stub.md", "title": "Stub", "chunk_index": 0, "score": 1.0}],
        },
    )
    monkeypatch.setattr(
        onec_agent,
        "call_adapter",
        lambda method, params, base_url=None: {"ok": True, "method": method, "params": params},
    )

    status, project_data, _ = request_json("POST", url=url, path="/v1/projects", payload={"name": "Контекст turn"})
    assert status == 201
    project_id = project_data["project"]["id"]

    status, chat_data, _ = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats",
        payload={"title": "context", "system_prompt": "Chat-only policy", "rag_profile": "official", "rag_limit": 3},
    )
    assert status == 201
    chat_id = chat_data["chat"]["id"]

    request_json("POST", url=url, path=f"/v1/projects/{project_id}/chats/{chat_id}/messages", payload={"role": "user", "content": "first"})
    request_json("POST", url=url, path=f"/v1/projects/{project_id}/chats/{chat_id}/messages", payload={"role": "assistant", "content": "second"})

    status, turn_data, is_error = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/turn",
        payload={
            "message": "Найди реквизит документа",
            "adapter_calls": [{"method": "tool.echo", "params": {"value": 7}}],
            "use_rag": True,
        },
    )
    assert status == 200
    assert not is_error
    assert turn_data["rag"]["profile"] == "official"
    assert turn_data["tools"][0]["method"] == "tool.echo"

    messages = turn_data["assistant_message"]["payload"]["raw"]["messages"]
    assert messages[0]["role"] == "system"
    assert "Ты помощник по 1С" in messages[0]["content"]
    assert "Chat-only policy" in messages[0]["content"]
    assert messages[1]["role"] == "system"
    assert "tool.echo" in messages[1]["content"]
    assert messages[2]["role"] == "system"
    assert "RAG PROMPT profile=official limit=3" in messages[2]["content"]
    assert [(item["role"], item["content"]) for item in messages[-3:]] == [
        ("user", "first"),
        ("assistant", "second"),
        ("user", "Найди реквизит документа"),
    ]

    audit_root = Path(onec_agent_server["audit_root"])
    retrieval_files = sorted((audit_root / "retrieval_events").glob("*.jsonl"))
    tool_files = sorted((audit_root / "tool_calls").glob("*.jsonl"))
    assert retrieval_files
    assert tool_files

    retrieval_records = [json.loads(line) for line in retrieval_files[-1].read_text(encoding="utf-8").splitlines() if line.strip()]
    tool_records = [json.loads(line) for line in tool_files[-1].read_text(encoding="utf-8").splitlines() if line.strip()]

    assert any(record["profile"] == "official" and record["plugin"] == "1c" for record in retrieval_records)
    assert any(record["tool_name"] == "tool.echo" and record["target_service"] == "1c-adapter" for record in tool_records)



def test_adapter_live_methods_require_base_id(onec_agent_server: dict[str, str]) -> None:
    onec_agent.validate_adapter_call("help.methods", {})
    onec_agent.validate_adapter_call("metadata.saved_state.forms.search", {"base_id": "upo_test"})
    with pytest.raises(ValueError, match="requires params.base_id"):
        onec_agent.validate_adapter_call("metadata.saved_state.forms.search", {})
    with pytest.raises(ValueError, match="requires params.base_id"):
        onec_agent.validate_adapter_call("storage.files.list", {"table": "ConfigSave"})

    url = onec_agent_server["url"]
    status, project_data, _ = request_json("POST", url=url, path="/v1/projects", payload={"name": "base-id guard"})
    assert status == 201
    project_id = project_data["project"]["id"]
    status, chat_data, _ = request_json("POST", url=url, path=f"/v1/projects/{project_id}/chats", payload={"title": "guard"})
    assert status == 201
    chat_id = chat_data["chat"]["id"]

    status, turn_data, is_error = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/turn",
        payload={
            "message": "Проверь сохраненное состояние",
            "adapter_calls": [{"method": "metadata.saved_state.forms.search", "params": {"table": "ConfigSave"}}],
        },
    )
    assert status == 400
    assert is_error
    assert turn_data["error"]["code"] == "adapter_error"
    assert "forbidden technical fields: table" in turn_data["error"]["message"]

    audit_root = Path(onec_agent_server["audit_root"])
    turn_files = sorted((audit_root / "turn_audit").glob("*.jsonl"))
    assert turn_files
    turn_records = [json.loads(line) for line in turn_files[-1].read_text(encoding="utf-8").splitlines() if line.strip()]
    assert any(
        record["outcome"] == "failure"
        and record["failure_type"] == "adapter_error"
        and record["error_code"] == "adapter_error"
        and "forbidden technical fields: table" in str(record["error_message"])
        for record in turn_records
    )


def test_agent_adapter_policy_uses_effective_view_and_blocks_storage_selectors(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    prepared = onec_agent.prepare_agent_adapter_call(
        "metadata.object.full",
        {"base_id": "upo_test", "name": "Отчет.Продажи"},
    )
    assert prepared["configuration_view"] == "effective_working"
    assert prepared["source_state"] == "working"

    with pytest.raises(ValueError, match="forbidden technical fields: table"):
        onec_agent.prepare_agent_adapter_call(
            "metadata.saved_state.forms.search",
            {"base_id": "upo_test", "table": "ConfigSave"},
        )

    with pytest.raises(ValueError, match="forbidden technical fields: module_ref"):
        onec_agent.prepare_agent_adapter_call(
            "code.read",
            {"base_id": "upo_test", "selector": {"module_ref": "private"}},
        )

    monkeypatch.setenv("ONEC_AGENT_ALLOW_DIAGNOSTIC", "true")
    assert onec_agent.prepare_agent_adapter_call(
        "metadata.saved_state.forms.search",
        {"base_id": "upo_test", "table": "ConfigSave"},
    )["table"] == "ConfigSave"


def test_agent_calls_adapter_through_mcp(monkeypatch: pytest.MonkeyPatch) -> None:
    requests: list[tuple[dict[str, Any], dict[str, str], str]] = []

    class FakeResponse:
        def __init__(self, body: dict[str, Any], headers: dict[str, str] | None = None) -> None:
            self._body = json.dumps(body).encode("utf-8")
            self.headers = headers or {}

        def read(self) -> bytes:
            return self._body

        def __enter__(self):
            return self

        def __exit__(self, *_args: object) -> None:
            return None

    def fake_urlopen(request: Request, timeout: float):
        body = json.loads(request.data.decode("utf-8"))
        requests.append((body, dict(request.headers), request.full_url))
        if body["method"] == "initialize":
            return FakeResponse({"jsonrpc": "2.0", "id": body["id"], "result": {}}, {"Mcp-Session-Id": "test-session"})
        return FakeResponse(
            {
                "jsonrpc": "2.0",
                "id": body["id"],
                "result": {"content": [{"type": "text", "text": json.dumps({"status": "ok"})}]},
            }
        )

    monkeypatch.setattr(onec_agent, "urlopen", fake_urlopen)
    result = onec_agent.call_adapter("metadata.object.forms", {"base_id": "upo_test", "ref": "Report.Тест"})

    assert result == {"status": "ok"}
    assert len(requests) == 2
    assert requests[0][0]["method"] == "initialize"
    assert requests[1][0]["method"] == "tools/call"
    assert requests[1][0]["params"]["name"] == "onec_request"
    assert requests[1][0]["params"]["arguments"]["payload"]["source_state"] == "working"
    assert requests[1][2] == "http://docker.cin.su:8021/mcp"


def test_agent_system_prompt_requires_mcp_name_first_navigation() -> None:
    prompt = onec_agent.DEFAULT_SYSTEM_PROMPT_PATH.read_text(encoding="utf-8")
    assert "только инструментом MCP `onec_request`" in prompt
    assert "source_state=working" in prompt
    assert "Не проси и не подставляй GUID либо `module_ref`" in prompt


def test_get_chat_runtime(onec_agent_server: dict[str, str]) -> None:
    url = onec_agent_server["url"]

    status, project_data, _ = request_json(
        "POST",
        url=url,
        path="/v1/projects",
        payload={"name": "runtime-check"},
    )
    assert status == 201
    project_id = project_data["project"]["id"]

    status, chat_data, _ = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats",
        payload={"title": "runtime", "model_id": "stub-model", "provider_id": "default", "temperature": 0.2, "max_tokens": 100},
    )
    assert status == 201
    chat_id = chat_data["chat"]["id"]

    status, runtime_data, _ = request_json(
        "GET",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/runtime",
    )
    assert status == 200
    assert runtime_data["project_id"] == project_id
    assert runtime_data["chat_id"] == chat_id
    runtime = runtime_data["runtime"]
    assert runtime["provider"]["id"] == "default"
    assert runtime["project"]["id"] == project_id
    assert runtime["chat"]["id"] == chat_id
    assert runtime["model"]["selected_model_id"] == "stub-model"
    assert runtime["model"]["chat_model_id"] == "stub-model"


def test_runtime_question_does_not_fire_on_general_1c_question(onec_agent_server: dict[str, str]) -> None:
    url = onec_agent_server["url"]

    status, project_data, _ = request_json(
        "POST",
        url=url,
        path="/v1/projects",
        payload={"name": "runtime-false-positive-check"},
    )
    assert status == 201
    project_id = project_data["project"]["id"]

    status, chat_data, _ = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats",
        payload={"title": "test"},
    )
    assert status == 201
    chat_id = chat_data["chat"]["id"]

    status, turn_data, _ = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/turn",
        payload={"message": "что такое 1С?", "use_rag": False},
    )
    assert status == 200
    assert "runtime-конфигурация" not in str(turn_data["assistant_message"]["content"]).lower()
    assert "Stub answer for stub-model via default" in turn_data["assistant_message"]["content"]


def test_validation_paths_return_client_errors(onec_agent_server: dict[str, str]) -> None:
    url = onec_agent_server["url"]

    status, bad_project, is_error = request_json("POST", url=url, path="/v1/projects", payload={"name": "Bad", "metadata": []})
    assert status == 400
    assert is_error
    assert bad_project["error"]["code"] == "invalid_argument"

    status, project_data, _ = request_json("POST", url=url, path="/v1/projects", payload={"name": "Validation"})
    assert status == 201
    project_id = project_data["project"]["id"]

    status, bad_chat, is_error = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats",
        payload={"title": "bad provider", "provider_id": "missing"},
    )
    assert status == 400
    assert is_error
    assert bad_chat["error"]["code"] == "invalid_argument"

    status, chat_data, _ = request_json("POST", url=url, path=f"/v1/projects/{project_id}/chats", payload={"title": "ok"})
    assert status == 201
    chat_id = chat_data["chat"]["id"]

    status, bad_turn, is_error = request_json(
        "POST",
        url=url,
        path=f"/v1/projects/{project_id}/chats/{chat_id}/turn",
        payload={"message": "Привет", "history_limit": "bad"},
    )
    assert status == 400
    assert is_error
    assert bad_turn["error"]["code"] == "invalid_argument"

