"""Tests for ai4gh.core.registry."""

from __future__ import annotations

import pytest
from pytest_httpx import HTTPXMock

from ai4gh.core.registry import (
    ServiceInfoClient,
    ServiceRegistryClient,
    discover_services,
)

SERVICE_INFO_RESPONSE = {
    "id": "org.ga4gh.test",
    "name": "Test Service",
    "type": {
        "group": "org.ga4gh",
        "artifact": "beacon",
        "version": "2.0.0",
    },
    "organization": {
        "name": "Test Organization",
        "url": "https://example.org",
    },
    "version": "1.0.0",
}

SERVICES_RESPONSE = [
    {
        "id": "svc-beacon",
        "name": "Beacon",
        "type": {"group": "org.ga4gh", "artifact": "beacon", "version": "2.0.0"},
        "organization": {"name": "Test Org", "url": "https://example.org"},
    },
    {
        "id": "svc-drs",
        "name": "DRS",
        "type": {"group": "org.ga4gh", "artifact": "drs", "version": "1.4.0"},
        "organization": {"name": "Other Org", "url": "https://other.org"},
    },
]


class TestServiceInfoClient:
    @pytest.mark.asyncio
    async def test_get(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(url="https://example.org/service-info", json=SERVICE_INFO_RESPONSE)
        client = ServiceInfoClient("https://example.org")
        info = await client.get()
        assert info.id == "org.ga4gh.test"
        assert info.type.artifact == "beacon"

    @pytest.mark.asyncio
    async def test_strips_trailing_slash(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(url="https://example.org/service-info", json=SERVICE_INFO_RESPONSE)
        client = ServiceInfoClient("https://example.org/")
        info = await client.get()
        assert info.id == "org.ga4gh.test"


class TestServiceRegistryClient:
    @pytest.mark.asyncio
    async def test_list_services(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(url="https://registry.example.org/services", json=SERVICES_RESPONSE)
        client = ServiceRegistryClient("https://registry.example.org")
        services = await client.list_services()
        assert len(services) == 2
        assert services[0].id == "svc-beacon"

    @pytest.mark.asyncio
    async def test_get_service(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(
            url="https://registry.example.org/services/svc-beacon",
            json=SERVICES_RESPONSE[0],
        )
        client = ServiceRegistryClient("https://registry.example.org")
        svc = await client.get_service("svc-beacon")
        assert svc.id == "svc-beacon"

    @pytest.mark.asyncio
    async def test_discover_by_type(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(url="https://registry.example.org/services", json=SERVICES_RESPONSE)
        client = ServiceRegistryClient("https://registry.example.org")
        results = await client.discover(service_type="org.ga4gh:beacon:2.0.0")
        assert len(results) == 1
        assert results[0].id == "svc-beacon"

    @pytest.mark.asyncio
    async def test_discover_by_organization(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(url="https://registry.example.org/services", json=SERVICES_RESPONSE)
        client = ServiceRegistryClient("https://registry.example.org")
        results = await client.discover(organization="Other")
        assert len(results) == 1
        assert results[0].id == "svc-drs"

    @pytest.mark.asyncio
    async def test_discover_no_filters(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(url="https://registry.example.org/services", json=SERVICES_RESPONSE)
        client = ServiceRegistryClient("https://registry.example.org")
        results = await client.discover()
        assert len(results) == 2

    @pytest.mark.asyncio
    async def test_get_service_info(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(
            url="https://registry.example.org/service-info",
            json=SERVICE_INFO_RESPONSE,
        )
        client = ServiceRegistryClient("https://registry.example.org")
        info = await client.get_service_info()
        assert info.id == "org.ga4gh.test"


class TestDiscoverServices:
    @pytest.mark.asyncio
    async def test_multi_registry(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(
            url="https://r1.example.org/services",
            json=[SERVICES_RESPONSE[0]],
        )
        httpx_mock.add_response(
            url="https://r2.example.org/services",
            json=[SERVICES_RESPONSE[1]],
        )
        results = await discover_services(["https://r1.example.org", "https://r2.example.org"])
        assert len(results) == 2

    @pytest.mark.asyncio
    async def test_skips_failed_registries(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(
            url="https://good.example.org/services",
            json=[SERVICES_RESPONSE[0]],
        )
        # Transport retries ServerError up to 3 times, so mock all attempts
        for _ in range(3):
            httpx_mock.add_response(
                url="https://bad.example.org/services",
                status_code=500,
                text="error",
            )
        results = await discover_services(["https://good.example.org", "https://bad.example.org"])
        assert len(results) == 1
        assert results[0].id == "svc-beacon"

    @pytest.mark.asyncio
    async def test_with_type_filter(self, httpx_mock: HTTPXMock) -> None:
        httpx_mock.add_response(
            url="https://r1.example.org/services",
            json=SERVICES_RESPONSE,
        )
        results = await discover_services(
            ["https://r1.example.org"],
            service_type="org.ga4gh:drs:1.4.0",
        )
        assert len(results) == 1
        assert results[0].id == "svc-drs"
