"""Tests for AuthManager token caching and refresh logic."""

import httpx
import pytest

from dalysdk.auth import AuthManager
from dalysdk.exceptions import AuthenticationError

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _auth_transport(
    *,
    status: int = 200,
    body: dict | None = None,
    call_count: list[int] | None = None,
):
    """Create a mock transport for the auth endpoint."""
    if body is None:
        body = {
            "result": "success",
            "token": "jwt-token-123",
        }

    def handler(request: httpx.Request) -> httpx.Response:
        if call_count is not None:
            call_count[0] += 1
        return httpx.Response(status, json=body)

    return httpx.MockTransport(handler)


# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------


class TestAuthManager:
    def test_token_fetched_on_first_access(self):
        manager = AuthManager("wk_test", "uk_test", "https://mock.api.com")
        # Patch httpx.post — use monkeypatch indirectly via transport
        call_count = [0]

        import dalysdk.auth as auth_module

        original_post = httpx.post

        def mock_post(url, **kwargs):
            call_count[0] += 1
            return httpx.Response(
                200,
                json={
                    "result": "success",
                    "token": "fetched-token",
                },
            )

        auth_module.httpx.post = mock_post
        try:
            token = manager.token
            assert token == "fetched-token"
            assert call_count[0] == 1
        finally:
            auth_module.httpx.post = original_post

    def test_token_cached_on_second_access(self):
        manager = AuthManager("wk_test", "uk_test", "https://mock.api.com")
        call_count = [0]

        import dalysdk.auth as auth_module

        original_post = httpx.post

        def mock_post(url, **kwargs):
            call_count[0] += 1
            return httpx.Response(
                200,
                json={
                    "result": "success",
                    "token": "cached-token",
                },
            )

        auth_module.httpx.post = mock_post
        try:
            _ = manager.token
            _ = manager.token
            assert call_count[0] == 1  # Only one fetch
        finally:
            auth_module.httpx.post = original_post

    def test_invalidate_clears_cache(self):
        manager = AuthManager("wk_test", "uk_test", "https://mock.api.com")
        call_count = [0]

        import dalysdk.auth as auth_module

        original_post = httpx.post

        def mock_post(url, **kwargs):
            call_count[0] += 1
            return httpx.Response(
                200,
                json={
                    "result": "success",
                    "token": f"token-{call_count[0]}",
                },
            )

        auth_module.httpx.post = mock_post
        try:
            t1 = manager.token
            manager.invalidate()
            t2 = manager.token
            assert t1 != t2
            assert call_count[0] == 2
        finally:
            auth_module.httpx.post = original_post

    def test_expired_token_triggers_refresh(self):
        manager = AuthManager("wk_test", "uk_test", "https://mock.api.com")
        call_count = [0]

        import dalysdk.auth as auth_module

        original_post = httpx.post

        def mock_post(url, **kwargs):
            call_count[0] += 1
            return httpx.Response(
                200,
                json={
                    "result": "success",
                    "token": f"token-{call_count[0]}",
                },
            )

        auth_module.httpx.post = mock_post
        try:
            _ = manager.token  # First fetch
            # Simulate expiry by setting token_expiry to the past
            manager._token_expiry = 0
            _ = manager.token  # Expired — refetches
            assert call_count[0] == 2
        finally:
            auth_module.httpx.post = original_post

    def test_401_raises_authentication_error(self):
        manager = AuthManager("wk_bad", "uk_bad", "https://mock.api.com")

        import dalysdk.auth as auth_module

        original_post = httpx.post

        def mock_post(url, **kwargs):
            return httpx.Response(401, json={"detail": "Invalid API keys"})

        auth_module.httpx.post = mock_post
        try:
            with pytest.raises(AuthenticationError):
                _ = manager.token
        finally:
            auth_module.httpx.post = original_post

    def test_500_raises_authentication_error(self):
        manager = AuthManager("wk_test", "uk_test", "https://mock.api.com")

        import dalysdk.auth as auth_module

        original_post = httpx.post

        def mock_post(url, **kwargs):
            return httpx.Response(500, json={"detail": "Server down"})

        auth_module.httpx.post = mock_post
        try:
            with pytest.raises(AuthenticationError):
                _ = manager.token
        finally:
            auth_module.httpx.post = original_post
