#
# SPDX-FileCopyrightText: Copyright (c) provide.io llc. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#


from typing import Any, cast

import httpx
from provide.foundation import logger

from tofusoup.config.defaults import OPENTOFU_REGISTRY_URL
from tofusoup.registry.models.module import Module, ModuleVersion
from tofusoup.registry.models.provider import (
    Provider,
    ProviderPlatform,
    ProviderVersion,
)

from .base import BaseTfRegistry, RegistryConfig


class OpenTofuRegistry(BaseTfRegistry):
    def __init__(self, config: RegistryConfig | None = None) -> None:
        super().__init__(config or RegistryConfig(base_url=OPENTOFU_REGISTRY_URL))

    async def _search_api_opentofu(self, query: str | None) -> list[dict[str, Any]]:
        if not self._client:
            return []
        api_search_url = "https://api.opentofu.org/registry/docs/search"
        params: dict[str, Any] = {"limit": 20}
        if query:
            params["q"] = query
        try:
            response = await self._client.get(api_search_url, params=params)
            response.raise_for_status()
            data = response.json()
            return cast(
                list[dict[str, Any]],
                data if isinstance(data, list) else data.get("items", []),
            )
        except (httpx.HTTPStatusError, httpx.RequestError) as e:
            logger.error(
                "Error during OpenTofu API search",
                request_url=e.request.url,
                exc_info=True,
            )
            return []

    async def list_modules(self, query: str | None = None) -> list[Module]:
        items_data = await self._search_api_opentofu(query)
        result_modules: list[Module] = []
        for item in items_data:
            if item and item.get("id", "").startswith("modules/"):
                parts = item["id"].split("/")
                if len(parts) == 4:
                    result_modules.append(
                        Module(
                            id=item["id"],
                            namespace=parts[1],
                            name=parts[2],
                            provider_name=parts[3],
                            description=item.get("description"),
                        )
                    )
        return result_modules

    async def list_providers(self, query: str | None = None) -> list[Provider]:
        items_data = await self._search_api_opentofu(query)
        result_providers: list[Provider] = []
        for item in items_data:
            if item and item.get("id", "").startswith("providers/"):
                parts = item["id"].split("/")
                if len(parts) == 3:
                    result_providers.append(
                        Provider(
                            id=item["id"],
                            namespace=parts[1],
                            name=parts[2],
                            description=item.get("description"),
                            tier=item.get("tier"),
                        )
                    )
        return result_providers

    async def get_provider_details(self, namespace: str, name: str) -> dict[str, Any]:
        if not self._client:
            return {}
        endpoint = f"/v1/providers/{namespace}/{name}"
        try:
            response = await self._client.get(endpoint)
            if response.status_code == 404:
                return {}
            response.raise_for_status()
            result: dict[str, Any] = response.json()
            return result
        except (httpx.HTTPStatusError, httpx.RequestError) as e:
            logger.error(
                f"Error fetching OpenTofu provider details for '{namespace}/{name}'",
                request_url=e.request.url,
                exc_info=True,
            )
            return {}

    async def list_provider_versions(self, provider_id: str) -> list[ProviderVersion]:
        if not self._client or "/" not in provider_id:
            return []
        namespace, name = provider_id.split("/", 1)
        endpoint = f"/v1/providers/{namespace}/{name}/versions"
        try:
            response = await self._client.get(endpoint)
            if response.status_code == 404:
                return []
            response.raise_for_status()
            data = response.json()
            return [
                ProviderVersion(
                    version=v.get("version", ""),
                    protocols=v.get("protocols", []),
                    platforms=[
                        ProviderPlatform(os=p.get("os", ""), arch=p.get("arch", ""))
                        for p in v.get("platforms", [])
                    ],
                )
                for v in data.get("versions", [])
            ]
        except (httpx.HTTPStatusError, httpx.RequestError) as e:
            logger.error(
                f"Error fetching OpenTofu provider versions for '{provider_id}'",
                request_url=e.request.url,
                exc_info=True,
            )
            return []

    async def get_module_details(
        self, namespace: str, name: str, provider: str, version: str
    ) -> dict[str, Any]:
        if not self._client:
            return {}
        endpoint = f"/v1/modules/{namespace}/{name}/{provider}/{version}"
        try:
            response = await self._client.get(endpoint)
            if response.status_code == 404:
                return {}
            response.raise_for_status()
            result: dict[str, Any] = response.json()
            return result
        except (httpx.HTTPStatusError, httpx.RequestError) as e:
            logger.error(
                f"Error fetching OpenTofu module details for '{namespace}/{name}/{provider}/{version}'",
                request_url=e.request.url,
                exc_info=True,
            )
            return {}

    async def list_module_versions(self, module_id: str) -> list[ModuleVersion]:
        if not self._client or module_id.count("/") != 2:
            return []
        namespace, name, provider = module_id.split("/")
        endpoint = f"/v1/modules/{namespace}/{name}/{provider}/versions"
        try:
            response = await self._client.get(endpoint)
            if response.status_code == 404:
                return []
            response.raise_for_status()
            data = response.json()
            versions_data = data.get("modules", [{}])[0].get("versions", [])
            return [ModuleVersion(version=v.get("version", "")) for v in versions_data if v.get("version")]
        except (httpx.HTTPStatusError, httpx.RequestError) as e:
            logger.error(
                f"Error fetching OpenTofu module versions for '{module_id}'",
                request_url=e.request.url,
                exc_info=True,
            )
            return []


# 🥣🔬🔚
