"""Tests for token validation, error mapping and retry behavior."""

import pytest
import responses
from tests.conftest import BASE, FAKE_TOKEN

from accuweather_client import WeatherClient
from accuweather_client._http import Transport
from accuweather_client.exceptions import (
    ApiRequestError,
    ApiServerError,
    InvalidTokenError,
    RateLimitExceededError,
)


@pytest.mark.parametrize(
    "bad_token", ["", "short", "x" * 100, "!" * 32, None, 12345]
)
def test_invalid_token_format_rejected(bad_token):
    with pytest.raises(InvalidTokenError) as excinfo:
        WeatherClient(token=bad_token, city="sydney")
    # The token value must never be echoed back.
    if isinstance(bad_token, str) and bad_token:
        assert bad_token not in str(excinfo.value)


@responses.activate
def test_http_401_raises_invalid_token():
    responses.get(f"{BASE}/locations/v1/cities/search", json={}, status=401)
    with pytest.raises(InvalidTokenError):
        _ = WeatherClient(token=FAKE_TOKEN, city="sydney").location


@responses.activate
def test_http_404_raises_api_request_error():
    responses.get(f"{BASE}/locations/v1/cities/search", body="{}", status=404)
    with pytest.raises(ApiRequestError) as excinfo:
        _ = WeatherClient(token=FAKE_TOKEN, city="sydney").location
    assert excinfo.value.status_code == 404


@responses.activate
def test_http_429_raises_rate_limit_error_with_headers():
    responses.get(
        f"{BASE}/locations/v1/cities/search",
        body="quota exceeded",
        status=429,
        headers={"RateLimit-Remaining": "0"},
    )
    with pytest.raises(RateLimitExceededError) as excinfo:
        _ = WeatherClient(token=FAKE_TOKEN, city="sydney").location
    assert excinfo.value.rate_limit_headers.get("RateLimit-Remaining") == "0"


@responses.activate
def test_http_503_with_quota_message_raises_rate_limit_error():
    responses.get(
        f"{BASE}/locations/v1/cities/search",
        body="The allowed number of requests has been exceeded.",
        status=503,
    )
    with pytest.raises(RateLimitExceededError):
        _ = WeatherClient(token=FAKE_TOKEN, city="sydney").location


@responses.activate
def test_http_500_retried_then_raises_server_error():
    for _ in range(4):  # initial try + 3 retries
        responses.get(
            f"{BASE}/locations/v1/cities/search", body="boom", status=500
        )
    with pytest.raises((ApiServerError, ApiRequestError)):
        _ = WeatherClient(token=FAKE_TOKEN, city="sydney").location
    assert len(responses.calls) == 4


@responses.activate
def test_http_400_not_retried():
    responses.get(f"{BASE}/locations/v1/cities/search", body="no", status=400)
    with pytest.raises(ApiRequestError):
        _ = WeatherClient(token=FAKE_TOKEN, city="sydney").location
    assert len(responses.calls) == 1


@responses.activate
def test_connection_error_wrapped():
    # Nothing registered for this URL: responses raises ConnectionError.
    transport = Transport(FAKE_TOKEN, retries=0)
    with pytest.raises(ApiRequestError, match="Failed to reach"):
        transport.get("currentconditions/v1/1")


def test_user_agent_header_set():
    from accuweather_client import __version__

    transport = Transport(FAKE_TOKEN)
    assert (
        transport.session.headers["User-Agent"]
        == f"accuweather-client/{__version__}"
    )
