import subprocess
from unittest.mock import MagicMock, patch
import pytest
from src.views.app import App


def docker_failure():
    raise subprocess.CalledProcessError(-1, "docker")


def one_running_container():
    return b"Whatever"


def multiple_running_containers():
    return b"Whatever\nWhatever"


def no_running_containers():
    return b""


@pytest.mark.parametrize("ps_results,expected_text", [
    (docker_failure, "Container status check is not possible"),
    (one_running_container, "Container Running"),
    (multiple_running_containers, "Containers Running"),
    (no_running_containers, "Run Container"),
])
def test_start_button_ui(ps_results, expected_text, qtbot, tools,
                         subprocess_mock):
    subprocess_run, _, _ = subprocess_mock

    def fake_subprocess_run(*args, **kwargs):
        mock_result = MagicMock()
        arguments = args[0]
        if len(arguments) > 1 and arguments[1] == 'ps':
            mock_result.stdout = ps_results()
        return mock_result

    subprocess_run.side_effect = fake_subprocess_run

    with patch("sys.platform", "darwin"):
        widget = App()
        qtbot.addWidget(widget)
        docker_tools = widget.tool_list.topLevelItem(0)
        first_item = docker_tools.child(0)  # type: ignore
        widget.tool_list.setCurrentItem(first_item)
        tool_display = widget.tool_display
        card = tool_display.currentWidget()
        card_layout = card.layout()  # type: ignore
        buttons_layout = card_layout.itemAt(3)  # type: ignore
        start_button = buttons_layout.itemAt(0).widget()  # type: ignore
        assert start_button.text().startswith(expected_text)


@pytest.mark.parametrize("system,args,kwargs", [
    ("linux", [
        "gnome-terminal", "-e",
        'bash -c "docker run --rm -it metasploitframework/metasploit-framework ; exec $SHELL"'
    ], {}),
    ("windows", [
        "start", "cmd", "/k",
        "docker run --rm -it metasploitframework/metasploit-framework "
    ], {
        "shell": True
    }),
    ("darwin", [
        "osascript", "-e",
        '\n                tell application "Terminal"\n                    do script "docker run --rm -it metasploitframework/metasploit-framework "\n                end tell\n            '
    ], {}),
])
def test_start_container(qtbot, tools, subprocess_mock, system, args, kwargs):
    with patch("sys.platform", system):
        widget = App()
        qtbot.addWidget(widget)
        docker_tools = widget.tool_list.topLevelItem(0)
        first_item = docker_tools.child(0)  # type: ignore
        widget.tool_list.setCurrentItem(first_item)
        tool_display = widget.tool_display
        card = tool_display.currentWidget()
        card_layout = card.layout()  # type: ignore
        buttons_layout = card_layout.itemAt(3)  # type: ignore
        start_button = buttons_layout.itemAt(0).widget()  # type: ignore
        start_button.click()
        _, subprocess_popen, _ = subprocess_mock
        subprocess_popen.assert_called_with(args, **kwargs)
