"""Tests for CLI command parsing and argument handling."""

from unittest.mock import Mock, patch

from typer.testing import CliRunner

from fwauto.cli import app

runner = CliRunner()


@patch("fwauto.cli.run_workflow")
def test_deploy_with_binary_args(mock_run_workflow):
    """Test flash command correctly parses --binary-args."""
    # Invoke flash command with --binary-args
    result = runner.invoke(app, ["deploy", "--binary-args", "on"])

    # Should succeed
    assert result.exit_code == 0

    # Verify run_workflow was called with correct state
    mock_run_workflow.assert_called_once()
    call_args = mock_run_workflow.call_args[0][0]

    # Check command_args contains binary_args
    assert "command_args" in call_args
    assert call_args["command_args"]["binary_args"] == "on"
    assert call_args["command"] == "deploy"
    assert call_args["execution_mode"] == "deploy"


@patch("fwauto.cli.run_workflow")
def test_deploy_with_binary_args_short_option(mock_run_workflow):
    """Test flash command correctly parses -ba short option."""
    result = runner.invoke(app, ["deploy", "-ba", "arg1 arg2"])

    assert result.exit_code == 0

    call_args = mock_run_workflow.call_args[0][0]
    assert call_args["command_args"]["binary_args"] == "arg1 arg2"


@patch("fwauto.cli.run_workflow")
def test_deploy_without_binary_args(mock_run_workflow):
    """Test flash command with no binary args sets empty string."""
    result = runner.invoke(app, ["deploy"])

    assert result.exit_code == 0

    call_args = mock_run_workflow.call_args[0][0]
    assert call_args["command_args"]["binary_args"] == ""


@patch("fwauto.cli.run_workflow")
def test_run_with_binary_args(mock_run_workflow):
    """Test run command correctly parses --binary-args."""
    result = runner.invoke(app, ["run", "--binary-args", "test"])

    assert result.exit_code == 0

    call_args = mock_run_workflow.call_args[0][0]
    assert call_args["command_args"]["binary_args"] == "test"
    assert call_args["command"] == "run"
    assert call_args["execution_mode"] == "run"


@patch("fwauto.cli.run_workflow")
def test_deploy_with_complex_binary_args(mock_run_workflow):
    """Test flash command with complex arguments."""
    result = runner.invoke(app, ["deploy", "--binary-args", "--mode test --timeout 5"])

    assert result.exit_code == 0

    call_args = mock_run_workflow.call_args[0][0]
    assert call_args["command_args"]["binary_args"] == "--mode test --timeout 5"


@patch("fwauto.cli.run_workflow")
def test_build_has_no_binary_args(mock_run_workflow):
    """Test build command does not have binary_args option."""
    # Build command should not accept --binary-args
    result = runner.invoke(app, ["build", "--binary-args", "test"])

    # Should fail with error about unknown option
    assert result.exit_code != 0
    # Error message can be in stdout or stderr
    output = (result.stdout + result.stderr).lower() if result.stderr else result.stdout.lower()
    assert "no such option" in output or "unrecognized" in output or result.exit_code == 2


@patch("fwauto.cli.run_workflow")
@patch("fwauto.config.find_project_root")
@patch("fwauto.config.load_project_config")
def test_deploy_with_scenario(mock_load_config, mock_find_root, mock_run_workflow):
    """Test flash command with --scenario option."""

    from fwauto.scenario import Scenario, ScenarioManager

    # Mock project root
    mock_find_root.return_value = "/test/project"

    # Mock config with scenarios
    mock_config = Mock()
    scenario = Scenario("led-on", "Turn on LED", "on")
    mock_config.get_scenario_manager.return_value = ScenarioManager([scenario])
    mock_load_config.return_value = mock_config

    result = runner.invoke(app, ["deploy", "--scenario", "led-on"])

    assert result.exit_code == 0
    mock_run_workflow.assert_called_once()

    call_args = mock_run_workflow.call_args[0][0]
    assert call_args["command_args"]["binary_args"] == "on"


@patch("fwauto.cli.run_workflow")
@patch("fwauto.config.find_project_root")
@patch("fwauto.config.load_project_config")
def test_deploy_with_scenario_short_option(mock_load_config, mock_find_root, mock_run_workflow):
    """Test flash command with -s short option."""

    from fwauto.scenario import Scenario, ScenarioManager

    mock_find_root.return_value = "/test/project"
    mock_config = Mock()
    scenario = Scenario("test-mode", "Test mode", "--mode test")
    mock_config.get_scenario_manager.return_value = ScenarioManager([scenario])
    mock_load_config.return_value = mock_config

    result = runner.invoke(app, ["deploy", "-s", "test-mode"])

    assert result.exit_code == 0
    call_args = mock_run_workflow.call_args[0][0]
    assert call_args["command_args"]["binary_args"] == "--mode test"


@patch("fwauto.config.find_project_root")
def test_deploy_with_scenario_not_found(mock_find_root):
    """Test flash command with non-existent scenario."""

    from fwauto.scenario import ScenarioManager

    mock_find_root.return_value = "/test/project"

    # Need to patch load_project_config at the right location
    with patch("fwauto.config.load_project_config") as mock_load_config:
        mock_config = Mock()
        mock_config.get_scenario_manager.return_value = ScenarioManager([])
        mock_load_config.return_value = mock_config

        result = runner.invoke(app, ["deploy", "--scenario", "nonexistent"])

        assert result.exit_code == 1
        assert "not found" in result.stdout.lower()


@patch("fwauto.cli.run_workflow")
@patch("fwauto.config.find_project_root")
@patch("fwauto.config.load_project_config")
def test_deploy_binary_args_overrides_scenario(mock_load_config, mock_find_root, mock_run_workflow):
    """Test that --binary-args takes precedence over --scenario."""

    from fwauto.scenario import Scenario, ScenarioManager

    mock_find_root.return_value = "/test/project"
    mock_config = Mock()
    scenario = Scenario("led-on", "Turn on LED", "on")
    mock_config.get_scenario_manager.return_value = ScenarioManager([scenario])
    mock_load_config.return_value = mock_config

    # Both --binary-args and --scenario provided
    result = runner.invoke(app, ["deploy", "--binary-args", "custom", "--scenario", "led-on"])

    assert result.exit_code == 0
    call_args = mock_run_workflow.call_args[0][0]
    # binary_args should win
    assert call_args["command_args"]["binary_args"] == "custom"
