"""Tests for TrustMemClient (mocked HTTP responses)."""
import os
import unittest.mock

import pytest

from trustmem_client import TrustMemClient


@pytest.fixture
def client():
    return TrustMemClient(base_url="http://test:8080")


@pytest.fixture
def auth_client():
    return TrustMemClient(base_url="http://test:8080", api_key="tm-secret")


# ==============================================================
# Init & repr
# ==============================================================
class TestInit:
    def test_repr(self, client):
        assert "TrustMemClient(" in repr(client)
        assert "test:8080" in repr(client)

    def test_context_manager(self):
        with TrustMemClient(base_url="http://test:8080") as c:
            assert isinstance(c, TrustMemClient)

    def test_auth_header_set(self, auth_client):
        headers = auth_client._client.headers
        assert headers["Authorization"] == "Bearer tm-secret"

    def test_no_auth_header_when_no_key(self, client):
        assert "Authorization" not in client._client.headers

    def test_env_var_base_url(self, monkeypatch):
        monkeypatch.setenv("TRUSTMEM_BASE_URL", "http://env-host:9090")
        monkeypatch.delenv("TRUSTMEM_API_KEY", raising=False)
        with unittest.mock.patch.dict("sys.modules", {"dotenv": None}):
            c = TrustMemClient()
        assert "env-host:9090" in str(c._client.base_url)
        c.close()

    def test_env_var_api_key(self, monkeypatch):
        monkeypatch.setenv("TRUSTMEM_API_KEY", "tm-from-env")
        monkeypatch.delenv("TRUSTMEM_BASE_URL", raising=False)
        with unittest.mock.patch.dict("sys.modules", {"dotenv": None}):
            c = TrustMemClient()
        assert c._client.headers["Authorization"] == "Bearer tm-from-env"
        c.close()

    def test_explicit_args_override_env(self, monkeypatch):
        monkeypatch.setenv("TRUSTMEM_BASE_URL", "http://env-host:9090")
        monkeypatch.setenv("TRUSTMEM_API_KEY", "tm-from-env")
        with unittest.mock.patch.dict("sys.modules", {"dotenv": None}):
            c = TrustMemClient(base_url="http://explicit:1234", api_key="tm-explicit")
        assert "explicit:1234" in str(c._client.base_url)
        assert c._client.headers["Authorization"] == "Bearer tm-explicit"
        c.close()


# ==============================================================
# Add
# ==============================================================
class TestAdd:
    def test_add_messages(self, client, httpx_mock):
        httpx_mock.add_response(
            url="http://test:8080/v1/memories",
            json={"stats": {"added": 1, "extracted": 1}},
        )
        result = client.add(
            [{"role": "user", "content": "Hello world"}],
            user_id="user1",
        )
        assert "stats" in result

    def test_add_with_user_id(self, client, httpx_mock):
        httpx_mock.add_response(
            url="http://test:8080/v1/memories",
            json={"stats": {"added": 1}},
        )
        result = client.add(
            [{"role": "user", "content": "Data"}],
            user_id="user-a",
        )
        assert "stats" in result
        req = httpx_mock.get_request()
        import json
        body = json.loads(req.content)
        assert body["user_id"] == "user-a"

    def test_add_with_visibility(self, client, httpx_mock):
        httpx_mock.add_response(
            url="http://test:8080/v1/memories",
            json={"stats": {"added": 1}},
        )
        result = client.add(
            [{"role": "user", "content": "Org data"}],
            visibility="organization",
        )
        assert "stats" in result
        req = httpx_mock.get_request()
        import json
        body = json.loads(req.content)
        assert body["visibility"] == "organization"
        assert "user_id" not in body

    def test_add_with_tags(self, client, httpx_mock):
        httpx_mock.add_response(
            url="http://test:8080/v1/memories",
            json={"stats": {"added": 1}},
        )
        result = client.add(
            [{"role": "user", "content": "Tagged"}],
            user_id="user1",
            tags=["food"],
        )
        assert "stats" in result


# ==============================================================
# Search
# ==============================================================
class TestSearch:
    def test_search(self, client, httpx_mock):
        httpx_mock.add_response(
            url="http://test:8080/v1/memories/search",
            json={"results": [{"content": "sky is blue"}], "relations": []},
        )
        result = client.search("sky", user_id="user1")
        assert len(result["results"]) == 1
        assert "relations" in result

    def test_search_with_params(self, client, httpx_mock):
        httpx_mock.add_response(
            url="http://test:8080/v1/memories/search",
            json={"results": [], "relations": []},
        )
        result = client.search("test", user_id="user1", limit=5)
        assert result["results"] == []
        req = httpx_mock.get_request()
        import json
        body = json.loads(req.content)
        assert body["limit"] == 5


# ==============================================================
# Get All
# ==============================================================
class TestGetAll:
    def test_get_all(self, client, httpx_mock):
        httpx_mock.add_response(
            method="GET",
            json={"results": [], "relations": []},
        )
        result = client.get_all(visibility="organization")
        assert result["results"] == []
        req = httpx_mock.get_request()
        assert "visibility=organization" in str(req.url)

    def test_get_all_with_user_id(self, client, httpx_mock):
        httpx_mock.add_response(
            method="GET",
            json={"results": [{"id": "1"}], "relations": []},
        )
        result = client.get_all(user_id="user-a")
        assert len(result["results"]) == 1
        req = httpx_mock.get_request()
        assert "user_id=user-a" in str(req.url)


# ==============================================================
# Delete
# ==============================================================
class TestDelete:
    def test_delete(self, client, httpx_mock):
        httpx_mock.add_response(
            url="http://test:8080/v1/memories/abc-123",
            json={"deleted": True},
        )
        assert client.delete("abc-123") is True

    def test_delete_nonexistent(self, client, httpx_mock):
        httpx_mock.add_response(
            url="http://test:8080/v1/memories/nonexistent",
            json={"deleted": False},
        )
        assert client.delete("nonexistent") is False


# ==============================================================
# Auth header propagation
# ==============================================================
class TestAuthPropagation:
    def test_bearer_sent_on_add(self, auth_client, httpx_mock):
        httpx_mock.add_response(
            url="http://test:8080/v1/memories",
            json={"stats": {"added": 1}},
        )
        auth_client.add(
            [{"role": "user", "content": "test"}],
            user_id="user1",
        )
        req = httpx_mock.get_request()
        assert req.headers["Authorization"] == "Bearer tm-secret"

    def test_bearer_sent_on_search(self, auth_client, httpx_mock):
        httpx_mock.add_response(
            url="http://test:8080/v1/memories/search",
            json={"results": [], "relations": []},
        )
        auth_client.search("test", user_id="user1")
        req = httpx_mock.get_request()
        assert req.headers["Authorization"] == "Bearer tm-secret"


# ==============================================================
# Error handling
# ==============================================================
class TestErrorHandling:
    def test_401_raises(self, client, httpx_mock):
        httpx_mock.add_response(
            url="http://test:8080/v1/memories",
            status_code=401,
            json={"detail": "Unauthorized"},
        )
        with pytest.raises(Exception):
            client.add(
                [{"role": "user", "content": "test"}],
                user_id="user1",
            )

    def test_500_raises(self, client, httpx_mock):
        httpx_mock.add_response(
            url="http://test:8080/v1/memories/search",
            status_code=500,
            json={"detail": "Internal error"},
        )
        with pytest.raises(Exception):
            client.search("test", user_id="user1")
