"""Marketplace registry operations."""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

import httpx
import yaml

from ievo.core.config import CACHE_DIR, MARKETPLACE_RAW, REGISTRY_URL, ensure_home


@dataclass
class RegistryEntry:
    """A single agent entry from registry.yaml."""

    name: str
    version: str
    description: str
    model: str
    dependencies: list[str]
    category: str = "core"


class Registry:
    """Interface to the ievo-marketplace registry."""

    def __init__(self, entries: dict[str, RegistryEntry] | None = None) -> None:
        self._entries = entries or {}

    @classmethod
    def load_cached(cls) -> Registry:
        """Load from local cache (~/.ievo/cache/registry.yaml)."""
        ensure_home()
        path = CACHE_DIR / "registry.yaml"
        if not path.exists():
            return cls()
        data = yaml.safe_load(path.read_text()) or {}
        entries = {}
        for agent in data.get("agents", []):
            entries[agent["name"]] = RegistryEntry(
                name=agent["name"],
                version=agent.get("version", "0.1.0"),
                description=agent.get("description", ""),
                model=agent.get("model", "sonnet"),
                dependencies=agent.get("dependencies", []),
                category=agent.get("category", "core"),
            )
        return cls(entries)

    async def fetch(self) -> None:
        """Download fresh registry from marketplace."""
        ensure_home()
        try:
            async with httpx.AsyncClient() as client:
                resp = await client.get(REGISTRY_URL, timeout=15)
                resp.raise_for_status()
                (CACHE_DIR / "registry.yaml").write_text(resp.text)
                data = yaml.safe_load(resp.text) or {}
                self._entries = {}
                for agent in data.get("agents", []):
                    self._entries[agent["name"]] = RegistryEntry(
                        name=agent["name"],
                        version=agent.get("version", "0.1.0"),
                        description=agent.get("description", ""),
                        model=agent.get("model", "sonnet"),
                        dependencies=agent.get("dependencies", []),
                        category=agent.get("category", "core"),
                    )
        except httpx.HTTPError:
            pass  # Fallback to cached

    def get(self, name: str) -> RegistryEntry | None:
        return self._entries.get(name)

    def list_all(self) -> list[RegistryEntry]:
        return list(self._entries.values())

    def agent_download_url(self, name: str) -> str:
        """URL to download agent package tarball."""
        return f"{MARKETPLACE_RAW}/agents/{name}"

    async def download_agent(self, name: str, dest: Path) -> bool:
        """Download agent files from marketplace to local dir.

        Uses GitHub Contents API to discover all files dynamically,
        then downloads each one via its raw URL.
        """
        entry = self.get(name)
        if not entry:
            return False

        dest.mkdir(parents=True, exist_ok=True)
        api_base = f"https://api.github.com/repos/ievo-ai/marketplace/contents/agents/{name}"

        async with httpx.AsyncClient(timeout=15) as client:
            files = await self._list_files_recursive(client, api_base)
            if not files:
                return False

            for rel_path, download_url in files:
                try:
                    resp = await client.get(download_url)
                    if resp.status_code == 200:
                        file_dest = dest / rel_path
                        file_dest.parent.mkdir(parents=True, exist_ok=True)
                        file_dest.write_text(resp.text)
                except httpx.HTTPError:
                    pass

        return True

    @staticmethod
    async def _list_files_recursive(
        client: httpx.AsyncClient,  # noqa: F821
        api_url: str,
    ) -> list[tuple[str, str]]:
        """List all files under a GitHub directory via Contents API.

        Returns list of (relative_path, download_url) tuples.
        """
        result: list[tuple[str, str]] = []
        try:
            resp = await client.get(api_url)
            if resp.status_code != 200:
                return result
            items = resp.json()
            if not isinstance(items, list):
                return result
            for item in items:
                if item["type"] == "file":
                    # path from API is "agents/name/file" — extract relative part
                    parts = item["path"].split("/", 2)
                    rel = parts[2] if len(parts) > 2 else item["name"]
                    result.append((rel, item["download_url"]))
                elif item["type"] == "dir":
                    sub = await Registry._list_files_recursive(client, item["url"])
                    result.extend(sub)
        except Exception:
            pass
        return result
