"""
Tests for arp_sdk.client module.

Covers ARPClient construction, sub-client initialization, authorization header,
context manager lifecycle, and close() behavior.
"""

from unittest.mock import patch, MagicMock

import pytest

from arp_sdk.client import ARPClient
from arp_sdk.http import HttpClient
from arp_sdk.resources.agents import AgentsClient
from arp_sdk.resources.reputation import ReputationClient
from arp_sdk.resources.transactions import TransactionsClient
from arp_sdk.resources.staking import StakingClient
from arp_sdk.resources.guilds import GuildsClient


API_URL = "https://api.arp.test"
API_KEY = "test-api-key-12345"


# ──────────────────────────────────────────────
# Constructor
# ──────────────────────────────────────────────


class TestARPClientConstructor:
    """Test that the constructor sets up all sub-clients correctly."""

    def test_creates_agents_sub_client(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        assert isinstance(client.agents, AgentsClient)
        client.close()

    def test_creates_reputation_sub_client(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        assert isinstance(client.reputation, ReputationClient)
        client.close()

    def test_creates_transactions_sub_client(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        assert isinstance(client.transactions, TransactionsClient)
        client.close()

    def test_creates_staking_sub_client(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        assert isinstance(client.staking, StakingClient)
        client.close()

    def test_creates_guilds_sub_client(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        assert isinstance(client.guilds, GuildsClient)
        client.close()

    def test_all_sub_clients_present(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        assert hasattr(client, "agents")
        assert hasattr(client, "reputation")
        assert hasattr(client, "transactions")
        assert hasattr(client, "staking")
        assert hasattr(client, "guilds")
        client.close()


# ──────────────────────────────────────────────
# Authorization header
# ──────────────────────────────────────────────


class TestAuthorizationHeader:
    """Verify the Authorization header is set correctly on the internal HTTP client."""

    def test_authorization_header_set_correctly(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        # Access the internal HttpClient's headers
        headers = client._http._headers
        assert headers["Authorization"] == f"Bearer {API_KEY}"
        client.close()

    def test_accept_header_set(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        headers = client._http._headers
        assert headers["Accept"] == "application/json"
        client.close()

    def test_user_agent_header_set(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        headers = client._http._headers
        assert headers["User-Agent"] == "arp-sdk-py/0.1.0"
        client.close()

    def test_different_api_key_reflected(self):
        key = "another-key-67890"
        client = ARPClient(api_url=API_URL, api_key=key)
        headers = client._http._headers
        assert headers["Authorization"] == f"Bearer {key}"
        client.close()


# ──────────────────────────────────────────────
# close()
# ──────────────────────────────────────────────


class TestClose:
    """Test that close() delegates to the HTTP client."""

    def test_close_closes_http_client(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        # Spy on the internal HTTP client's close method
        original_close = client._http.close
        close_called = False

        def spy_close():
            nonlocal close_called
            close_called = True
            original_close()

        client._http.close = spy_close
        client.close()
        assert close_called

    def test_close_can_be_called_multiple_times(self):
        """Calling close() twice should not raise an error."""
        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        client.close()
        # httpx.Client tolerates multiple close() calls
        client.close()


# ──────────────────────────────────────────────
# Context manager
# ──────────────────────────────────────────────


class TestContextManager:
    """ARPClient should work as a context manager."""

    def test_context_manager_returns_self(self):
        with ARPClient(api_url=API_URL, api_key=API_KEY) as client:
            assert isinstance(client, ARPClient)

    def test_context_manager_has_sub_clients(self):
        with ARPClient(api_url=API_URL, api_key=API_KEY) as client:
            assert isinstance(client.agents, AgentsClient)
            assert isinstance(client.reputation, ReputationClient)
            assert isinstance(client.transactions, TransactionsClient)
            assert isinstance(client.staking, StakingClient)
            assert isinstance(client.guilds, GuildsClient)

    def test_context_manager_closes_on_exit(self):
        close_called = False

        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        original_close = client.close

        def spy_close():
            nonlocal close_called
            close_called = True
            original_close()

        client.close = spy_close

        with client:
            pass

        assert close_called

    def test_context_manager_closes_on_exception(self):
        close_called = False

        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        original_close = client.close

        def spy_close():
            nonlocal close_called
            close_called = True
            original_close()

        client.close = spy_close

        with pytest.raises(RuntimeError):
            with client:
                raise RuntimeError("test error")

        assert close_called


# ──────────────────────────────────────────────
# Configuration passthrough
# ──────────────────────────────────────────────


class TestConfiguration:
    """Verify that constructor parameters are forwarded correctly."""

    def test_custom_timeout(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY, timeout=60.0)
        assert client._http._timeout == 60.0
        client.close()

    def test_custom_max_retries(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY, max_retries=5)
        assert client._http._max_retries == 5
        client.close()

    def test_base_url_trailing_slash_stripped(self):
        client = ARPClient(api_url=f"{API_URL}/", api_key=API_KEY)
        assert client._http._base_url == API_URL
        client.close()

    def test_private_key_stored(self):
        pk = "0xdeadbeef"
        client = ARPClient(api_url=API_URL, api_key=API_KEY, private_key=pk)
        assert client._private_key == pk
        client.close()

    def test_private_key_default_none(self):
        client = ARPClient(api_url=API_URL, api_key=API_KEY)
        assert client._private_key is None
        client.close()
