"""Tests for ai4gh.core.client."""

from __future__ import annotations

import pytest
from pytest_httpx import HTTPXMock

from ai4gh.core.auth import BearerTokenAuth, NoAuth
from ai4gh.core.client import GA4GHClient

SERVICE_INFO_RESPONSE = {
    "id": "org.ga4gh.test",
    "name": "Test Client Service",
    "type": {
        "group": "org.ga4gh",
        "artifact": "drs",
        "version": "1.4.0",
    },
}


class DRSClient(GA4GHClient):
    """Test subclass of GA4GHClient."""

    spec_name = "drs"
    spec_version = "1.4.0"
    base_path = "/ga4gh/drs/v1"


class TestGA4GHClientInit:
    def test_with_base_url(self) -> None:
        client = GA4GHClient(base_url="https://example.org")
        assert client._base_url == "https://example.org"

    def test_strips_trailing_slash(self) -> None:
        client = GA4GHClient(base_url="https://example.org/")
        assert client._base_url == "https://example.org"

    def test_default_auth_is_no_auth(self) -> None:
        client = GA4GHClient(base_url="https://example.org")
        assert isinstance(client._auth, NoAuth)

    def test_custom_auth(self) -> None:
        auth = BearerTokenAuth("test-token")
        client = GA4GHClient(base_url="https://example.org", auth=auth)
        assert client._auth is auth

    def test_url_from_config(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.setenv("AI4GH_DRS_URL", "https://drs.example.org")
        client = DRSClient()
        assert client._base_url == "https://drs.example.org"


class TestGA4GHClientURL:
    def test_url_with_base_path(self) -> None:
        client = DRSClient(base_url="https://example.org")
        assert client.url == "https://example.org/ga4gh/drs/v1"

    def test_url_without_base_path(self) -> None:
        client = GA4GHClient(base_url="https://example.org")
        assert client.url == "https://example.org"


class TestGA4GHClientRequest:
    @pytest.mark.asyncio
    async def test_get_request(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(
            url="https://example.org/ga4gh/drs/v1/objects/abc",
            json={"id": "abc", "name": "test-object"},
        )
        client = DRSClient(base_url="https://example.org")
        result = await client._request("GET", "/objects/abc")
        assert result == {"id": "abc", "name": "test-object"}

    @pytest.mark.asyncio
    async def test_post_request(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(
            url="https://example.org/ga4gh/drs/v1/search",
            json={"results": []},
        )
        client = DRSClient(base_url="https://example.org")
        result = await client._request("POST", "/search", json={"query": "test"})
        assert result == {"results": []}

    @pytest.mark.asyncio
    async def test_delete_request(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(
            url="https://example.org/ga4gh/drs/v1/objects/abc",
            json={"deleted": True},
        )
        client = DRSClient(base_url="https://example.org")
        result = await client._request("DELETE", "/objects/abc")
        assert result == {"deleted": True}

    @pytest.mark.asyncio
    async def test_auth_headers_injected(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(
            url="https://example.org/ga4gh/drs/v1/objects/abc",
            json={"id": "abc"},
        )
        auth = BearerTokenAuth("test-token")
        client = DRSClient(base_url="https://example.org", auth=auth)
        await client._request("GET", "/objects/abc")
        request = httpx_mock.get_request()
        assert request is not None
        assert request.headers["Authorization"] == "Bearer test-token"


class TestGA4GHClientServiceInfo:
    @pytest.mark.asyncio
    async def test_get_service_info(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(
            url="https://example.org/ga4gh/drs/v1/service-info",
            json=SERVICE_INFO_RESPONSE,
        )
        client = DRSClient(base_url="https://example.org")
        info = await client.get_service_info()
        assert info.id == "org.ga4gh.test"
        assert info.type.artifact == "drs"


class TestGA4GHClientContextManager:
    @pytest.mark.asyncio
    async def test_async_context_manager(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(
            url="https://example.org/ga4gh/drs/v1/service-info",
            json=SERVICE_INFO_RESPONSE,
        )
        async with DRSClient(base_url="https://example.org") as client:
            info = await client.get_service_info()
            assert info.id == "org.ga4gh.test"


class TestGA4GHClientClose:
    @pytest.mark.asyncio
    async def test_close(self) -> None:
        client = GA4GHClient(base_url="https://example.org")
        await client.close()  # should not raise
