"""CLI tests for plugins commands via CliRunner."""

from __future__ import annotations

import importlib.metadata
from unittest.mock import MagicMock, patch

from click.testing import CliRunner

from kuberoku.cli.main import cli
from kuberoku.factory import KuberokuFactory
from tests.backends.fake import FakeK8sClient

_PYPI_MONGODB = (
    b'{"info": {"name": "kuberoku-mongodb", "version": "1.0.0", "summary": "MongoDB addon"}}'
)


def _make_ctx(ns: str) -> dict[str, KuberokuFactory]:
    factory = KuberokuFactory(k8s_client=FakeK8sClient(), namespace=ns)
    return {"factory": factory}


def test_cli_plugins_list_empty(cli_runner: CliRunner, tmp_namespace: str) -> None:
    obj = _make_ctx(tmp_namespace)
    with patch(
        "kuberoku.sdk.plugins.importlib.metadata.entry_points",
        return_value=[],
    ):
        result = cli_runner.invoke(cli, ["plugins"], obj=obj)
    assert result.exit_code == 0
    assert "No plugins" in result.output


def test_cli_plugins_list_with_plugins(cli_runner: CliRunner, tmp_namespace: str) -> None:
    obj = _make_ctx(tmp_namespace)
    ep = MagicMock()
    ep.dist = MagicMock()
    ep.dist.name = "kuberoku-mongodb"
    ep.dist.version = "1.0.0"
    ep.dist.metadata = {"Summary": "MongoDB addon"}

    with patch(
        "kuberoku.sdk.plugins.importlib.metadata.entry_points",
        return_value=[ep],
    ):
        result = cli_runner.invoke(cli, ["plugins"], obj=obj)
    assert result.exit_code == 0
    assert "mongodb" in result.output


def test_cli_plugins_install(cli_runner: CliRunner, tmp_namespace: str) -> None:
    obj = _make_ctx(tmp_namespace)
    mock_dist = MagicMock()
    mock_dist.version = "1.0.0"
    mock_dist.metadata = {"Summary": "Test"}

    with (
        patch("kuberoku.sdk.plugins.subprocess.run"),
        patch(
            "kuberoku.sdk.plugins.importlib.metadata.distribution",
            return_value=mock_dist,
        ),
        patch(
            "kuberoku.sdk.plugins.importlib.metadata.entry_points",
            MagicMock(cache_clear=MagicMock()),
        ),
    ):
        result = cli_runner.invoke(cli, ["plugins", "install", "kuberoku-mongodb"], obj=obj)
    assert result.exit_code == 0
    assert "Installed" in result.output


def test_cli_plugins_uninstall(cli_runner: CliRunner, tmp_namespace: str) -> None:
    obj = _make_ctx(tmp_namespace)
    with patch("kuberoku.sdk.plugins.subprocess.run"):
        result = cli_runner.invoke(cli, ["plugins", "uninstall", "kuberoku-mongodb"], obj=obj)
    assert result.exit_code == 0
    assert "Uninstalled" in result.output


def test_cli_plugins_search(cli_runner: CliRunner, tmp_namespace: str) -> None:
    obj = _make_ctx(tmp_namespace)
    mock_response = MagicMock()
    mock_response.read.return_value = _PYPI_MONGODB
    mock_response.__enter__ = MagicMock(return_value=mock_response)
    mock_response.__exit__ = MagicMock(return_value=False)

    with (
        patch("urllib.request.urlopen", return_value=mock_response),
        patch(
            "kuberoku.sdk.plugins.importlib.metadata.distribution",
            side_effect=importlib.metadata.PackageNotFoundError("x"),
        ),
    ):
        result = cli_runner.invoke(cli, ["plugins", "search", "mongodb"], obj=obj)
    assert result.exit_code == 0
    assert "mongodb" in result.output


def test_cli_plugins_colon_syntax(cli_runner: CliRunner, tmp_namespace: str) -> None:
    """plugins:install should work like plugins install."""
    obj = _make_ctx(tmp_namespace)
    mock_dist = MagicMock()
    mock_dist.version = "1.0.0"
    mock_dist.metadata = {"Summary": "Test"}

    with (
        patch("kuberoku.sdk.plugins.subprocess.run"),
        patch(
            "kuberoku.sdk.plugins.importlib.metadata.distribution",
            return_value=mock_dist,
        ),
        patch(
            "kuberoku.sdk.plugins.importlib.metadata.entry_points",
            MagicMock(cache_clear=MagicMock()),
        ),
    ):
        result = cli_runner.invoke(cli, ["plugins:install", "kuberoku-mongodb"], obj=obj)
    assert result.exit_code == 0
    assert "Installed" in result.output
