"""Basic tests for the GraphMem Python client."""

import json
from unittest.mock import MagicMock, patch

import httpx
import pytest

from graphmem import GraphMem, GraphMemError
from graphmem.types import RetryConfig, Triple


def _mock_response(data: dict, status_code: int = 200) -> httpx.Response:
    """Create a mock httpx.Response."""
    response = MagicMock(spec=httpx.Response)
    response.status_code = status_code
    response.json.return_value = data
    response.headers = {}
    return response


class TestGraphMemInit:
    def test_requires_api_key(self):
        with pytest.raises(ValueError, match="api_key is required"):
            GraphMem(api_key="")

    def test_strips_trailing_slash(self):
        mem = GraphMem(api_key="gm_test", base_url="https://example.com/")
        assert mem._base_url == "https://example.com"

    def test_default_retry_config(self):
        mem = GraphMem(api_key="gm_test")
        assert mem._retry.max_retries == 3
        assert mem._retry.base_delay == 0.5

    def test_custom_retry_config(self):
        mem = GraphMem(api_key="gm_test", retry=RetryConfig(max_retries=5))
        assert mem._retry.max_retries == 5


class TestRemember:
    @patch.object(httpx.Client, "request")
    def test_remember(self, mock_request):
        mock_request.return_value = _mock_response(
            {"success": True, "extractedCount": 3, "mergedCount": 2, "message": "ok"}
        )
        mem = GraphMem(api_key="gm_test")
        result = mem.remember("Alice works at Acme")
        assert result.extracted_count == 3
        assert result.merged_count == 2
        assert result.message == "ok"


class TestGetContext:
    @patch.object(httpx.Client, "request")
    def test_json_format(self, mock_request):
        mock_request.return_value = _mock_response(
            {
                "format": "json",
                "query": "Alice",
                "entities": [{"name": "Alice"}],
                "edges": [],
            }
        )
        mem = GraphMem(api_key="gm_test")
        result = mem.get_context("Alice")
        assert result.format == "json"
        assert result.query == "Alice"

    @patch.object(httpx.Client, "request")
    def test_text_format(self, mock_request):
        mock_request.return_value = _mock_response(
            {"format": "text", "query": "Alice", "content": "Alice works at Acme"}
        )
        mem = GraphMem(api_key="gm_test")
        result = mem.get_context("Alice")
        assert result.format == "text"
        assert result.content == "Alice works at Acme"


class TestSearch:
    @patch.object(httpx.Client, "request")
    def test_search(self, mock_request):
        mock_request.return_value = _mock_response(
            {
                "success": True,
                "entity": {"name": "Alice", "userId": "u1"},
                "edges": [],
            }
        )
        mem = GraphMem(api_key="gm_test")
        result = mem.search("Alice")
        assert result.entity["name"] == "Alice"


class TestErrorHandling:
    @patch.object(httpx.Client, "request")
    def test_api_error(self, mock_request):
        mock_request.return_value = _mock_response(
            {"success": False, "error": "Not found"}, status_code=404
        )
        mem = GraphMem(api_key="gm_test")
        with pytest.raises(GraphMemError) as exc:
            mem.search("missing")
        assert exc.value.status == 404


class TestRateLimit:
    @patch.object(httpx.Client, "request")
    def test_rate_limit_headers_parsed(self, mock_request):
        response = _mock_response({"status": "ok", "version": "1", "timestamp": "now"})
        response.headers = {
            "X-RateLimit-Remaining": "99",
            "X-RateLimit-Limit": "100",
            "X-RateLimit-Reset": "1700000000",
        }
        mock_request.return_value = response
        mem = GraphMem(api_key="gm_test")
        mem.health()
        assert mem.rate_limit.remaining == 99
        assert mem.rate_limit.limit == 100
        assert mem.rate_limit.reset == 1700000000


class TestContextManager:
    def test_context_manager(self):
        with GraphMem(api_key="gm_test") as mem:
            assert mem._api_key == "gm_test"
