from __future__ import annotations

import pytest
import respx
import httpx

from surfinguard import Guard, Policy
from surfinguard.exceptions import (
    AuthenticationError,
    RateLimitError,
    APIError,
    NotAllowedError,
    SurfinguardError,
)
from surfinguard.models import CheckResult
from surfinguard.enums import RiskLevel


class TestAuthenticationError:
    def test_401_raises(self, mock_api):
        mock_api.post("/v2/check/url").mock(
            return_value=httpx.Response(401, json={"error": "Invalid API key"})
        )
        guard = Guard(
            api_key="sg_test_bad_key_000000000000000000000",
            base_url="https://test.surfinguard.com",
        )
        with pytest.raises(AuthenticationError, match="Invalid API key"):
            guard.check_url("https://example.com")

    def test_inherits_from_base(self):
        assert issubclass(AuthenticationError, SurfinguardError)


class TestRateLimitError:
    def test_429_raises_with_retry_after(self, mock_api):
        mock_api.post("/v2/check/url").mock(
            return_value=httpx.Response(
                429,
                json={"error": "Rate limit exceeded"},
                headers={"Retry-After": "60"},
            )
        )
        guard = Guard(
            api_key="sg_test_0123456789abcdef0123456789abcdef",
            base_url="https://test.surfinguard.com",
        )
        with pytest.raises(RateLimitError) as exc_info:
            guard.check_url("https://example.com")
        assert exc_info.value.retry_after == 60

    def test_429_without_retry_after(self, mock_api):
        mock_api.post("/v2/check/url").mock(
            return_value=httpx.Response(429, json={"error": "Too many requests"})
        )
        guard = Guard(
            api_key="sg_test_0123456789abcdef0123456789abcdef",
            base_url="https://test.surfinguard.com",
        )
        with pytest.raises(RateLimitError) as exc_info:
            guard.check_url("https://example.com")
        assert exc_info.value.retry_after is None


class TestAPIError:
    def test_500_raises(self, mock_api):
        mock_api.post("/v2/check/url").mock(
            return_value=httpx.Response(500, json={"error": "Internal server error"})
        )
        guard = Guard(
            api_key="sg_test_0123456789abcdef0123456789abcdef",
            base_url="https://test.surfinguard.com",
        )
        with pytest.raises(APIError) as exc_info:
            guard.check_url("https://example.com")
        assert exc_info.value.status_code == 500

    def test_400_raises(self, mock_api):
        mock_api.post("/v2/check/url").mock(
            return_value=httpx.Response(400, json={"error": "Bad request"})
        )
        guard = Guard(
            api_key="sg_test_0123456789abcdef0123456789abcdef",
            base_url="https://test.surfinguard.com",
        )
        with pytest.raises(APIError) as exc_info:
            guard.check_url("https://example.com")
        assert exc_info.value.status_code == 400

    def test_non_json_error_body(self, mock_api):
        mock_api.post("/v2/check/url").mock(
            return_value=httpx.Response(502, content=b"Bad Gateway")
        )
        guard = Guard(
            api_key="sg_test_0123456789abcdef0123456789abcdef",
            base_url="https://test.surfinguard.com",
        )
        with pytest.raises(APIError) as exc_info:
            guard.check_url("https://example.com")
        assert exc_info.value.status_code == 502


class TestNotAllowedError:
    def test_has_result(self):
        result = CheckResult(
            allow=False, score=9, level=RiskLevel.DANGER,
            primitive=None, primitive_scores=[], reasons=["Bad"],
            latency_ms=1.0,
        )
        err = NotAllowedError(result)
        assert err.result is result
        assert err.result.score == 9
        assert "DANGER" in str(err)

    def test_inherits_from_base(self):
        assert issubclass(NotAllowedError, SurfinguardError)
