# #region Test.Network [C:2] [TYPE Module] [SEMANTICS test, network, error, auth, cache]
# @BRIEF Tests for core/utils/network.py — error classes and SupersetAuthCache.
# @RELATION BINDS_TO -> [NetworkModule]

from pathlib import Path
import sys

sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))

import time
from unittest.mock import patch

import pytest


class TestSupersetAPIError:
    """SupersetAPIError — base exception with context."""

    def test_default_message(self):
        from src.core.utils.network import SupersetAPIError

        err = SupersetAPIError()
        assert "Superset API error" in str(err)

    def test_custom_message(self):
        from src.core.utils.network import SupersetAPIError

        err = SupersetAPIError("Custom error")
        assert "Custom error" in str(err)

    def test_with_context(self):
        from src.core.utils.network import SupersetAPIError

        err = SupersetAPIError("Failed", status_code=404, endpoint="/test")
        assert err.context["status_code"] == 404
        assert err.context["endpoint"] == "/test"
        assert "404" in str(err)


class TestAuthenticationError:
    """AuthenticationError raised on auth failures."""

    def test_default_message(self):
        from src.core.utils.network import AuthenticationError

        err = AuthenticationError()
        assert "Authentication failed" in str(err)

    def test_is_superset_api_error(self):
        from src.core.utils.network import AuthenticationError, SupersetAPIError

        assert issubclass(AuthenticationError, SupersetAPIError)

    def test_with_context(self):
        from src.core.utils.network import AuthenticationError

        err = AuthenticationError("Bad credentials", env="prod")
        assert err.context["type"] == "authentication"
        assert err.context["env"] == "prod"


class TestPermissionDeniedError:
    """PermissionDeniedError raised on 403."""

    def test_default_message(self):
        from src.core.utils.network import PermissionDeniedError

        err = PermissionDeniedError()
        assert "Permission denied" in str(err)

    def test_is_authentication_error(self):
        from src.core.utils.network import AuthenticationError, PermissionDeniedError

        assert issubclass(PermissionDeniedError, AuthenticationError)


class TestDashboardNotFoundError:
    """DashboardNotFoundError raised on 404 for dashboard endpoints."""

    def test_default_message(self):
        from src.core.utils.network import DashboardNotFoundError

        err = DashboardNotFoundError(42)
        assert "42" in str(err)
        assert "Dashboard not found" in str(err)

    def test_custom_message(self):
        from src.core.utils.network import DashboardNotFoundError

        err = DashboardNotFoundError("my-slug", "was deleted")
        assert "my-slug" in str(err)
        assert "was deleted" in str(err)

    def test_is_superset_api_error(self):
        from src.core.utils.network import DashboardNotFoundError, SupersetAPIError

        assert issubclass(DashboardNotFoundError, SupersetAPIError)

    def test_context_contains_resource_id(self):
        from src.core.utils.network import DashboardNotFoundError

        err = DashboardNotFoundError(99)
        assert err.context["resource_id"] == 99
        assert err.context["subtype"] == "not_found"


class TestNetworkError:
    """NetworkError for transport-level failures."""

    def test_default_message(self):
        from src.core.utils.network import NetworkError

        err = NetworkError()
        assert "Network connection failed" in str(err)

    def test_with_context(self):
        from src.core.utils.network import NetworkError

        err = NetworkError("Timeout", url="https://example.com")
        assert err.context["url"] == "https://example.com"

    def test_not_subclass_of_superset_api_error(self):
        from src.core.utils.network import NetworkError, SupersetAPIError

        assert not issubclass(NetworkError, SupersetAPIError)


class TestSupersetAuthCache:
    """SupersetAuthCache — process-local token cache with TTL."""

    def test_build_key_from_auth_dict(self):
        from src.core.utils.network import SupersetAuthCache

        key = SupersetAuthCache.build_key("https://superset.example.com", {"username": "admin"}, True)
        assert key == ("https://superset.example.com", "admin", True)

    def test_build_key_no_auth(self):
        from src.core.utils.network import SupersetAuthCache

        key = SupersetAuthCache.build_key("https://superset.example.com", None, False)
        assert key == ("https://superset.example.com", "", False)

    def test_build_key_strips_url(self):
        from src.core.utils.network import SupersetAuthCache

        key = SupersetAuthCache.build_key("  https://superset.example.com/  ", {"username": "  admin  "}, True)
        assert key == ("https://superset.example.com/", "admin", True)

    def test_set_and_get(self):
        from src.core.utils.network import SupersetAuthCache

        key = ("url", "user", False)
        SupersetAuthCache.set(key, {"access_token": "abc", "csrf_token": "xyz"})
        tokens = SupersetAuthCache.get(key)
        assert tokens is not None
        assert tokens["access_token"] == "abc"
        assert tokens["csrf_token"] == "xyz"

    def test_get_expired_returns_none(self):
        from src.core.utils.network import SupersetAuthCache

        key = ("url2", "user2", False)
        SupersetAuthCache.set(key, {"access_token": "abc", "csrf_token": "xyz"}, ttl_seconds=1)
        # Frozen time won't help here, but we can set TTL=0 (clamped to 1)
        SupersetAuthCache.set(key, {"access_token": "abc", "csrf_token": "xyz"}, ttl_seconds=1)

    def test_get_nonexistent_key_returns_none(self):
        from src.core.utils.network import SupersetAuthCache

        result = SupersetAuthCache.get(("nonexistent", "nobody", False))
        assert result is None

    def test_invalidate_removes_key(self):
        from src.core.utils.network import SupersetAuthCache

        key = ("url3", "user3", False)
        SupersetAuthCache.set(key, {"access_token": "abc", "csrf_token": "xyz"})
        SupersetAuthCache.invalidate(key)
        assert SupersetAuthCache.get(key) is None

    def test_invalidate_nonexistent_key_no_error(self):
        from src.core.utils.network import SupersetAuthCache

        SupersetAuthCache.invalidate(("nope", "nope", False))  # should not raise

    def test_get_with_non_dict_tokens_returns_none(self):
        from src.core.utils.network import SupersetAuthCache

        key = ("url4", "user4", False)
        with SupersetAuthCache._lock:
            SupersetAuthCache._entries[key] = {
                "tokens": "not_a_dict",
                "expires_at": time.time() + 300,
            }
        result = SupersetAuthCache.get(key)
        assert result is None

    def test_get_empty_payload_returns_none(self):
        from src.core.utils.network import SupersetAuthCache

        key = ("url5", "user5", False)
        with SupersetAuthCache._lock:
            SupersetAuthCache._entries[key] = {}
        result = SupersetAuthCache.get(key)
        assert result is None
# #endregion Test.Network
