"""Service discovery via Service Info and Service Registry."""

from __future__ import annotations

from ai4gh.core.config import Config
from ai4gh.core.transport import Transport
from ai4gh.core.types import ServiceInfo


class ServiceInfoClient:
    """Client for the GA4GH Service Info specification (v1.0.0).

    Every GA4GH API implementation exposes a /service-info endpoint
    that returns standardized metadata about the service.
    """

    def __init__(
        self,
        base_url: str,
        *,
        transport: Transport | None = None,
        config: Config | None = None,
    ) -> None:
        self._base_url = base_url.rstrip("/")
        self._transport = transport or Transport(config or Config())

    async def get(self) -> ServiceInfo:
        """Fetch service info from the endpoint.

        Returns:
            Parsed ServiceInfo model.
        """
        url = f"{self._base_url}/service-info"
        response = await self._transport.get(url)
        return ServiceInfo.model_validate(response.json())


class ServiceRegistryClient:
    """Client for the GA4GH Service Registry specification (v1.0.0).

    A Service Registry aggregates multiple GA4GH services and enables
    discovery by type, organization, or other criteria.
    """

    def __init__(
        self,
        base_url: str,
        *,
        transport: Transport | None = None,
        config: Config | None = None,
    ) -> None:
        self._base_url = base_url.rstrip("/")
        self._transport = transport or Transport(config or Config())

    async def list_services(self) -> list[ServiceInfo]:
        """List all registered services.

        Returns:
            List of ServiceInfo objects for all registered services.
        """
        url = f"{self._base_url}/services"
        response = await self._transport.get(url)
        data = response.json()
        return [ServiceInfo.model_validate(item) for item in data]

    async def get_service(self, service_id: str) -> ServiceInfo:
        """Get a specific registered service by ID.

        Args:
            service_id: The service identifier.

        Returns:
            ServiceInfo for the requested service.
        """
        url = f"{self._base_url}/services/{service_id}"
        response = await self._transport.get(url)
        return ServiceInfo.model_validate(response.json())

    async def discover(
        self,
        *,
        service_type: str | None = None,
        organization: str | None = None,
    ) -> list[ServiceInfo]:
        """Discover services by type and/or organization.

        Args:
            service_type: Filter by GA4GH service type (e.g., "org.ga4gh:beacon:2.0.0").
            organization: Filter by organization name.

        Returns:
            List of matching ServiceInfo objects.
        """
        services = await self.list_services()
        results: list[ServiceInfo] = []

        for svc in services:
            if service_type:
                type_str = f"{svc.type.group}:{svc.type.artifact}:{svc.type.version}"
                if type_str != service_type:
                    continue
            if (
                organization
                and svc.organization
                and organization.lower() not in svc.organization.name.lower()
            ):
                continue
            results.append(svc)

        return results

    async def get_service_info(self) -> ServiceInfo:
        """Get the Service Registry's own service info.

        Returns:
            ServiceInfo for the registry itself.
        """
        client = ServiceInfoClient(self._base_url, transport=self._transport)
        return await client.get()


async def discover_services(
    registry_urls: list[str],
    *,
    service_type: str | None = None,
    config: Config | None = None,
) -> list[ServiceInfo]:
    """Discover GA4GH services across multiple registries.

    Args:
        registry_urls: List of Service Registry base URLs.
        service_type: Optional filter by service type.
        config: Optional configuration.

    Returns:
        Aggregated list of discovered services.
    """
    transport = Transport(config or Config())
    results: list[ServiceInfo] = []

    for url in registry_urls:
        client = ServiceRegistryClient(url, transport=transport)
        try:
            services = await client.discover(service_type=service_type)
            results.extend(services)
        except Exception:
            continue

    await transport.close()
    return results
