"""Unit tests for the exec CLI command."""

import json

import pluggy
import pytest
from click.testing import CliRunner

from imbue.mngr.api.exec import ExecResult
from imbue.mngr.api.exec import MultiExecResult
from imbue.mngr.cli.exec import ExecCliOptions
from imbue.mngr.cli.exec import _emit_human_output
from imbue.mngr.cli.exec import _emit_json_output
from imbue.mngr.cli.exec import _emit_jsonl_exec_result
from imbue.mngr.cli.exec import exec_command


def test_exec_cli_options_fields() -> None:
    """Test ExecCliOptions has required fields."""
    opts = ExecCliOptions(
        agents=("my-agent",),
        agent_list=(),
        exec_all=False,
        command_arg="echo hello",
        user=None,
        cwd=None,
        timeout=None,
        start=True,
        on_error="continue",
        output_format="human",
        quiet=False,
        verbose=0,
        log_file=None,
        log_commands=None,
        log_command_output=None,
        log_env_vars=None,
        project_context_path=None,
        plugin=(),
        disable_plugin=(),
    )
    assert opts.agents == ("my-agent",)
    assert opts.command_arg == "echo hello"
    assert opts.user is None
    assert opts.cwd is None
    assert opts.timeout is None
    assert opts.start is True
    assert opts.on_error == "continue"


def test_exec_requires_command(
    cli_runner: CliRunner,
    plugin_manager: pluggy.PluginManager,
) -> None:
    """Test that exec requires the COMMAND argument."""
    result = cli_runner.invoke(
        exec_command,
        [],
        obj=plugin_manager,
        catch_exceptions=True,
    )
    assert result.exit_code != 0


def test_exec_nonexistent_agent(
    cli_runner: CliRunner,
    plugin_manager: pluggy.PluginManager,
) -> None:
    """Test executing on a non-existent agent."""
    result = cli_runner.invoke(
        exec_command,
        ["nonexistent-agent-99999", "echo hello"],
        obj=plugin_manager,
        catch_exceptions=True,
    )
    assert result.exit_code != 0


def test_emit_human_output_single_success(capsys: pytest.CaptureFixture[str]) -> None:
    """Test human output prints stdout and logs success for a single agent."""
    exec_result = ExecResult(agent_name="test-agent", stdout="hello world\n", stderr="", success=True)
    multi_result = MultiExecResult(successful_results=[exec_result], failed_agents=[])
    _emit_human_output(multi_result)

    captured = capsys.readouterr()
    assert "hello world" in captured.out


def test_emit_human_output_single_failure(capsys: pytest.CaptureFixture[str]) -> None:
    """Test human output handles failed commands."""
    exec_result = ExecResult(agent_name="test-agent", stdout="", stderr="bad command\n", success=False)
    multi_result = MultiExecResult(successful_results=[exec_result], failed_agents=[])
    _emit_human_output(multi_result)

    captured = capsys.readouterr()
    assert "bad command" in captured.err


def test_emit_human_output_multi_agent_shows_headers(capsys: pytest.CaptureFixture[str]) -> None:
    """Test human output shows agent name headers when there are multiple results."""
    result1 = ExecResult(agent_name="agent-1", stdout="output1\n", stderr="", success=True)
    result2 = ExecResult(agent_name="agent-2", stdout="output2\n", stderr="", success=True)
    multi_result = MultiExecResult(successful_results=[result1, result2], failed_agents=[])
    _emit_human_output(multi_result)

    captured = capsys.readouterr()
    assert "output1" in captured.out
    assert "output2" in captured.out


def test_emit_json_output_multi_agent(capsys: pytest.CaptureFixture[str]) -> None:
    """Test JSON output format for multiple agents."""
    result1 = ExecResult(agent_name="agent-1", stdout="hello\n", stderr="", success=True)
    result2 = ExecResult(agent_name="agent-2", stdout="world\n", stderr="", success=True)
    multi_result = MultiExecResult(successful_results=[result1, result2], failed_agents=[])
    _emit_json_output(multi_result)

    captured = capsys.readouterr()
    output = json.loads(captured.out.strip())
    assert output["total_executed"] == 2
    assert output["total_failed"] == 0
    assert len(output["results"]) == 2
    assert output["results"][0]["agent"] == "agent-1"
    assert output["results"][1]["agent"] == "agent-2"


def test_emit_json_output_with_failures(capsys: pytest.CaptureFixture[str]) -> None:
    """Test JSON output format includes failed agents."""
    result1 = ExecResult(agent_name="agent-1", stdout="hello\n", stderr="", success=True)
    multi_result = MultiExecResult(
        successful_results=[result1],
        failed_agents=[("agent-2", "host offline")],
    )
    _emit_json_output(multi_result)

    captured = capsys.readouterr()
    output = json.loads(captured.out.strip())
    assert output["total_executed"] == 1
    assert output["total_failed"] == 1
    assert output["failed_agents"][0]["agent"] == "agent-2"
    assert output["failed_agents"][0]["error"] == "host offline"


def test_emit_jsonl_exec_result(capsys: pytest.CaptureFixture[str]) -> None:
    """Test JSONL output format for a single exec result."""
    result = ExecResult(agent_name="test-agent", stdout="hello\n", stderr="", success=True)
    _emit_jsonl_exec_result(result)

    captured = capsys.readouterr()
    output = json.loads(captured.out.strip())
    assert output["event"] == "exec_result"
    assert output["agent"] == "test-agent"
    assert output["success"] is True
