"""Tests for the HTTP client."""

from __future__ import annotations

import pytest
import httpx
from unittest.mock import MagicMock, patch

from genosis.http import HttpClient
from genosis.errors import (
    AuthenticationError,
    BadRequestError,
    ConnectionError,
    GenosisError,
    RateLimitError,
    TimeoutError,
)


def make_client(**kwargs) -> HttpClient:
    defaults = {
        "api_key": "gns_test_abc123",
        "base_url": "https://api.usegenosis.ai",
        "max_retries": 0,
        "timeout": 10.0,
    }
    defaults.update(kwargs)
    return HttpClient(**defaults)


def mock_response(status: int, data: dict, headers: dict | None = None) -> MagicMock:
    resp = MagicMock(spec=httpx.Response)
    resp.status_code = status
    resp.is_success = 200 <= status < 300
    resp.json.return_value = data
    resp.headers = httpx.Headers(headers or {})
    resp.text = str(data)
    return resp


class TestHttpClientInit:
    def test_rejects_plaintext_http(self):
        with pytest.raises(ValueError, match="HTTPS"):
            HttpClient(api_key="gns_test_x", base_url="http://example.com")

    def test_allows_localhost_http(self):
        client = HttpClient(api_key="gns_test_x", base_url="http://localhost:3001")
        assert "localhost" in client.base_url

    def test_allows_127_http(self):
        client = HttpClient(api_key="gns_test_x", base_url="http://127.0.0.1:3001")
        assert "127.0.0.1" in client.base_url

    def test_strips_trailing_slash(self):
        client = HttpClient(api_key="gns_test_x", base_url="https://api.usegenosis.ai/")
        assert not client.base_url.endswith("/")

    def test_persistent_client_created(self):
        client = make_client()
        assert client._client is not None


class TestHttpClientRequests:
    def test_successful_get(self):
        client = make_client()
        resp_data = {"id": "123", "name": "Test"}
        client._client.request = MagicMock(return_value=mock_response(200, resp_data))

        result = client.get("/v1/account")
        assert result.data == resp_data
        assert result.status == 200

    def test_sends_auth_header(self):
        client = make_client(api_key="gns_test_mykey")
        client._client.request = MagicMock(return_value=mock_response(200, {}))

        client.get("/v1/account")

        # Auth header is set on the persistent client at init
        auth = client._client.headers.get("authorization")
        assert auth == "Bearer gns_test_mykey"

    def test_401_raises_authentication_error(self):
        client = make_client()
        client._client.request = MagicMock(
            return_value=mock_response(401, {"error": {"message": "Unauthorized", "code": "UNAUTHORIZED"}})
        )

        with pytest.raises(AuthenticationError) as exc_info:
            client.get("/v1/account")
        assert exc_info.value.status == 401

    def test_429_raises_rate_limit_error(self):
        client = make_client()
        client._client.request = MagicMock(
            return_value=mock_response(429, {"error": {"message": "Too many requests", "code": "RATE_LIMITED"}})
        )

        with pytest.raises(RateLimitError):
            client.get("/v1/account")

    def test_304_returns_none_data(self):
        client = make_client()
        resp = mock_response(304, {})
        resp.is_success = False
        client._client.request = MagicMock(return_value=resp)

        result = client.get("/v1/manifest?provider=anthropic&model=claude-sonnet-4-6")
        assert result.status == 304
        assert result.data is None

    def test_timeout_raises_timeout_error(self):
        client = make_client(max_retries=0)
        client._client.request = MagicMock(side_effect=httpx.ReadTimeout("timed out"))

        with pytest.raises(TimeoutError):
            client.get("/v1/account")

    def test_connection_error(self):
        client = make_client(max_retries=0)
        client._client.request = MagicMock(side_effect=httpx.ConnectError("refused"))

        with pytest.raises(ConnectionError):
            client.get("/v1/account")

    def test_user_agent_header(self):
        from genosis.version import VERSION
        client = make_client()

        ua = client._client.headers.get("user-agent")
        assert ua == f"genosis-sdk-python/{VERSION}"

    def test_close(self):
        client = make_client()
        client._client.close = MagicMock()
        client.close()
        client._client.close.assert_called_once()
