import pytest

from mnemosynecore import llm


class _Resp:
    def __init__(self, data):
        self._data = data

    def raise_for_status(self):
        return None

    def json(self):
        return self._data


def test_llm_chat_with_direct_token(monkeypatch):
    captured = {}
    monkeypatch.setattr(
        llm.requests,
        "post",
        lambda url, json=None, headers=None, timeout=None: (
            captured.update(
                {"url": url, "payload": json, "headers": headers, "timeout": timeout}
            )
            or _Resp({"choices": [{"message": {"content": "ok"}}]})
        ),
    )

    out = llm.llm_chat(
        prompt="hello",
        model="gpt-test",
        token="direct-token",
        base_url="https://llm.example/v1",
    )
    assert out == "ok"
    assert captured["url"] == "https://llm.example/v1/chat/completions"
    assert captured["headers"]["Authorization"] == "Bearer direct-token"
    assert captured["payload"]["model"] == "gpt-test"


def test_llm_chat_reads_token_from_text_file(monkeypatch, tmp_path):
    token_file = tmp_path / "llm_token.txt"
    token_file.write_text("token-from-file", encoding="utf-8")

    captured = {}
    monkeypatch.setattr(
        llm.requests,
        "post",
        lambda url, json=None, headers=None, timeout=None: (
            captured.update({"headers": headers})
            or _Resp({"choices": [{"message": {"content": "done"}}]})
        ),
    )

    out = llm.llm_chat(
        prompt="ping",
        model="m",
        token_path=str(token_file),
        base_url="https://gw.local/v1",
    )
    assert out == "done"
    assert captured["headers"]["Authorization"] == "Bearer token-from-file"


def test_llm_chat_reads_token_from_json_file(monkeypatch, tmp_path):
    token_file = tmp_path / "llm_token.json"
    token_file.write_text('{"api_key":"json-token"}', encoding="utf-8")

    captured = {}
    monkeypatch.setattr(
        llm.requests,
        "post",
        lambda url, json=None, headers=None, timeout=None: (
            captured.update({"headers": headers})
            or _Resp({"choices": [{"message": {"content": "ok-json"}}]})
        ),
    )

    out = llm.llm_chat(
        prompt="ping",
        model="m",
        token_path=str(token_file),
        base_url="https://gw.local/v1",
    )
    assert out == "ok-json"
    assert captured["headers"]["Authorization"] == "Bearer json-token"


def test_llm_chat_uses_conn_config_and_parse_json(monkeypatch):
    captured = {}
    monkeypatch.setattr(
        llm,
        "resolve_secret",
        lambda conn_id: {
            "host": "http://llm-gateway.prod.a.o3.ru/api",
            "password": "vault-token",
            "model": "DeepSeek-V3-0324-AWQ[CM]",
            "extra": '{"endpoint":"/chat/completions"}',
        },
    )
    monkeypatch.setattr(
        llm.requests,
        "post",
        lambda url, json=None, headers=None, timeout=None: (
            captured.update({"url": url, "payload": json, "headers": headers})
            or _Resp({"choices": [{"message": {"content": '{"result":"ok"}'}}]})
        ),
    )

    out = llm.llm_chat(
        prompt="return json",
        llm_conn="LLM_GATEWAY",
        parse_json=True,
    )
    assert out == {"result": "ok"}
    assert captured["url"] == "http://llm-gateway.prod.a.o3.ru/api/chat/completions"
    assert captured["payload"]["model"] == "DeepSeek-V3-0324-AWQ[CM]"
    assert captured["headers"]["Authorization"] == "Bearer vault-token"


def test_llm_chat_test_supports_creds_path(monkeypatch):
    captured = {}
    monkeypatch.setattr(
        llm,
        "resolve_secret_test",
        lambda conn_id, dir_path=None, creds_path=None: (
            captured.update({"dir_path": dir_path, "creds_path": creds_path})
            or {
                "host": "https://llm.local/v1",
                "token": "secret-token",
                "model": "gpt-test",
            }
        ),
    )
    monkeypatch.setattr(
        llm.requests,
        "post",
        lambda *args, **kwargs: _Resp({"choices": [{"message": {"content": "ok"}}]}),
    )

    out = llm.llm_chat_test(
        prompt="hello",
        llm_conn="LLM_CONN",
        creds_path="/tmp/llm_conn.json",
    )
    assert out == "ok"
    assert captured["creds_path"] == "/tmp/llm_conn.json"


def test_llm_chat_appends_prompt_to_messages(monkeypatch):
    captured = {}
    monkeypatch.setattr(
        llm.requests,
        "post",
        lambda url, json=None, headers=None, timeout=None: (
            captured.update({"messages": json["messages"]})
            or _Resp({"choices": [{"message": {"content": "ok"}}]})
        ),
    )

    llm.llm_chat(
        model="m",
        token="t",
        base_url="https://llm/v1",
        messages=[{"role": "system", "content": "rules"}],
        prompt="user question",
    )

    assert len(captured["messages"]) == 2
    assert captured["messages"][1]["content"] == "user question"


def test_llm_chat_extracts_list_content(monkeypatch):
    monkeypatch.setattr(
        llm.requests,
        "post",
        lambda *args, **kwargs: _Resp(
            {
                "choices": [
                    {
                        "message": {
                            "content": [
                                {"type": "text", "text": "hello"},
                                {"text": " world"},
                            ]
                        }
                    }
                ]
            }
        ),
    )

    out = llm.llm_chat(
        prompt="x",
        model="m",
        token="t",
        base_url="https://llm/v1",
    )
    assert out == "hello world"


def test_llm_chat_raises_when_token_missing():
    with pytest.raises(ValueError, match="Токен LLM не найден"):
        llm.llm_chat(
            prompt="x",
            model="m",
            llm_conn={},
            base_url="https://llm/v1",
        )


def test_llm_chat_return_raw(monkeypatch):
    monkeypatch.setattr(
        llm.requests,
        "post",
        lambda *args, **kwargs: _Resp({"id": "abc", "choices": [{"message": {"content": "ok"}}]}),
    )

    out = llm.llm_chat(
        prompt="hello",
        model="gpt",
        token="tok",
        base_url="https://llm/v1",
        return_raw=True,
    )
    assert out["id"] == "abc"
