"""Tests for ``ilum exec`` command."""

from __future__ import annotations

from unittest.mock import MagicMock, patch

import pytest
from typer.testing import CliRunner

from ilum.cli.exec_cmd import _build_exec_command
from ilum.cli.main import app
from ilum.core.kubernetes import PodStatus
from ilum.errors import ModuleError


@pytest.fixture()
def runner() -> CliRunner:
    return CliRunner()


@pytest.fixture()
def mock_k8s() -> MagicMock:
    from ilum.core.kubernetes import KubeClient

    mock = MagicMock(spec=KubeClient)
    mock.list_pods_by_label.return_value = [
        PodStatus(
            name="ilum-core-0",
            namespace="default",
            phase="Running",
            ready=True,
            restart_count=0,
        ),
    ]
    return mock


def _patch_exec(mock_k8s: MagicMock):
    return patch("ilum.cli.exec_cmd.KubeClient", return_value=mock_k8s)


class TestBuildExecCommand:
    def test_basic(self) -> None:
        cmd = _build_exec_command("pod-0", "default", "", "/bin/bash", None, None)
        assert cmd == ["kubectl", "exec", "-it", "pod-0", "-n", "default", "--", "/bin/bash"]

    def test_with_context(self) -> None:
        cmd = _build_exec_command("pod-0", "ns", "my-ctx", "/bin/sh", None, None)
        assert "--context" in cmd
        assert "my-ctx" in cmd

    def test_with_container(self) -> None:
        cmd = _build_exec_command("pod-0", "ns", "", "/bin/bash", "mycontainer", None)
        assert "-c" in cmd
        assert "mycontainer" in cmd

    def test_with_command(self) -> None:
        cmd = _build_exec_command("pod-0", "ns", "", "/bin/bash", None, "ls -la")
        assert cmd[-3:] == ["sh", "-c", "ls -la"]

    def test_all_options(self) -> None:
        cmd = _build_exec_command("pod-0", "ns", "ctx", "/bin/bash", "c1", "whoami")
        assert "pod-0" in cmd
        assert "-n" in cmd
        assert "ns" in cmd
        assert "--context" in cmd
        assert "ctx" in cmd
        assert "-c" in cmd
        assert "c1" in cmd
        assert "whoami" in cmd


class TestExecCommand:
    def test_exec_help(self, runner: CliRunner) -> None:
        result = runner.invoke(app, ["exec", "--help"])
        assert result.exit_code == 0
        assert "interactive shell" in result.output.lower() or "shell" in result.output.lower()

    def test_exec_no_pods_found(self, runner: CliRunner, mock_k8s: MagicMock) -> None:
        mock_k8s.list_pods_by_label.return_value = []
        with _patch_exec(mock_k8s):
            result = runner.invoke(app, ["exec", "core"])
        assert result.exit_code == 1

    def test_exec_unknown_module(self, runner: CliRunner) -> None:
        with patch("ilum.cli.exec_cmd.ModuleResolver") as mock_resolver_cls:
            mock_resolver = MagicMock()
            mock_resolver.get.side_effect = ModuleError("Unknown module 'nonexistent'")
            mock_resolver_cls.return_value = mock_resolver
            result = runner.invoke(app, ["exec", "nonexistent"])
        assert result.exit_code == 1

    def test_exec_with_command(self, runner: CliRunner, mock_k8s: MagicMock) -> None:
        with _patch_exec(mock_k8s), patch("subprocess.run") as mock_run:
            mock_run.return_value = MagicMock(returncode=0)
            result = runner.invoke(app, ["exec", "core", "--command", "ls -la"])
        assert result.exit_code == 0
        mock_run.assert_called_once()

    def test_exec_with_pod_flag(self, runner: CliRunner, mock_k8s: MagicMock) -> None:
        with _patch_exec(mock_k8s), patch("os.execvp") as mock_execvp:
            # os.execvp replaces process — mock it to return normally
            runner.invoke(app, ["exec", "core", "--pod", "my-pod-0"])
        mock_execvp.assert_called_once()
        cmd = mock_execvp.call_args[0][1]
        assert "my-pod-0" in cmd

    def test_exec_multiple_pods_no_tty(self, runner: CliRunner, mock_k8s: MagicMock) -> None:
        """Without TTY and multiple pods, should error."""
        mock_k8s.list_pods_by_label.return_value = [
            PodStatus(
                name="pod-0", namespace="default", phase="Running", ready=True, restart_count=0
            ),
            PodStatus(
                name="pod-1", namespace="default", phase="Running", ready=True, restart_count=0
            ),
        ]
        with _patch_exec(mock_k8s):
            # CliRunner does not provide a TTY
            result = runner.invoke(app, ["exec", "core"])
        assert result.exit_code == 1

    def test_exec_high_restart_warning(self, runner: CliRunner, mock_k8s: MagicMock) -> None:
        """Pod with >5 restarts should show a warning."""
        mock_k8s.list_pods_by_label.return_value = [
            PodStatus(
                name="ilum-core-0",
                namespace="default",
                phase="Running",
                ready=True,
                restart_count=10,
            ),
        ]
        with _patch_exec(mock_k8s), patch("os.execvp"):
            # The warning is written to stderr via Rich, not captured by CliRunner
            # Just verify the command doesn't crash
            runner.invoke(app, ["exec", "core"])
