"""PluginService — list, install, uninstall, search plugins."""

from __future__ import annotations

import importlib.metadata
import json
import subprocess
import sys
import urllib.request
from collections.abc import Callable
from typing import TYPE_CHECKING

from kuberoku.branding import PLUGIN_GROUP, PLUGIN_PREFIX
from kuberoku.exceptions import KuberokuError
from kuberoku.models import PluginInfo

if TYPE_CHECKING:
    from kuberoku.factory import KuberokuFactory


class PluginService:
    """Business logic for plugin management."""

    def __init__(self, factory: KuberokuFactory) -> None:
        self._factory = factory

    def list_installed(self) -> tuple[PluginInfo, ...]:
        """Scan entry_points for installed plugins."""
        eps = importlib.metadata.entry_points(group=PLUGIN_GROUP)
        plugins: list[PluginInfo] = []

        for ep in eps:
            dist = ep.dist
            if dist is None:
                continue

            package_name = dist.name
            command_name = package_name.removeprefix(PLUGIN_PREFIX)
            version = dist.version
            description = ""
            meta = dist.metadata
            if meta:
                description = meta.get("Summary", "") or ""

            plugins.append(
                PluginInfo(
                    name=command_name,
                    package=package_name,
                    version=version,
                    description=description,
                    installed=True,
                )
            )

        return tuple(sorted(plugins, key=lambda p: p.name))

    def install(
        self,
        package_name: str,
        on_step: Callable[[str], None] | None = None,
    ) -> PluginInfo:
        """Install a plugin via pip subprocess."""
        if getattr(sys, "frozen", False):
            raise KuberokuError(
                "Plugin install is not supported in frozen (PyInstaller) builds. "
                "Use pip/pipx instead."
            )

        if on_step:
            on_step(f"Installing {package_name}...")

        subprocess.run(
            [sys.executable, "-m", "pip", "install", package_name],
            check=True,
            capture_output=True,
        )

        # Reload metadata
        importlib.metadata.entry_points.cache_clear()  # type: ignore[attr-defined]

        command_name = package_name.removeprefix(PLUGIN_PREFIX)
        try:
            dist = importlib.metadata.distribution(package_name)
            version = dist.version
            description = ""
            meta = dist.metadata
            if meta:
                description = meta.get("Summary", "") or ""
        except importlib.metadata.PackageNotFoundError:
            version = "unknown"
            description = ""

        return PluginInfo(
            name=command_name,
            package=package_name,
            version=version,
            description=description,
            installed=True,
        )

    def uninstall(
        self,
        package_name: str,
        on_step: Callable[[str], None] | None = None,
    ) -> None:
        """Uninstall a plugin via pip subprocess."""
        if getattr(sys, "frozen", False):
            raise KuberokuError(
                "Plugin uninstall is not supported in frozen (PyInstaller) builds."
            )

        if on_step:
            on_step(f"Uninstalling {package_name}...")

        subprocess.run(
            [sys.executable, "-m", "pip", "uninstall", "-y", package_name],
            check=True,
            capture_output=True,
        )

    def search(self, query: str) -> tuple[PluginInfo, ...]:
        """Search PyPI for kuberoku-* packages matching query.

        Uses the PyPI JSON API to search for packages.
        """
        search_name = f"{PLUGIN_PREFIX}{query}"
        url = f"https://pypi.org/pypi/{search_name}/json"

        try:
            with urllib.request.urlopen(url, timeout=10) as resp:
                data = json.loads(resp.read())
        except Exception:
            return ()

        info = data.get("info", {})
        name = info.get("name", search_name)
        command_name = name.removeprefix(PLUGIN_PREFIX)

        # Check if installed
        installed = False
        try:
            importlib.metadata.distribution(name)
            installed = True
        except importlib.metadata.PackageNotFoundError:
            pass

        return (
            PluginInfo(
                name=command_name,
                package=name,
                version=info.get("version", ""),
                description=info.get("summary", ""),
                installed=installed,
            ),
        )
