# Copyright 2021-2022 Timo Röhling <roehling@debian.org>
# SPDX-License-Identifier: MIT
from dhros.rosbuilder.rosbuilder import run, cmdind
import itertools
import os
import re
import pytest
import dhros.common


BUILD_STEPS = ["configure", "build", "test", "install", "clean"]
BUILD_TYPES = ["ament_cmake", "ament_python", "catkin", "cmake"]


def default_command(step, btype):
    if step == "test" and btype == "catkin":
        return f"cmake --build .*/foo_{btype} --target run_tests"
    else:
        return f"dh_auto_{step} --sourcedir=foo_{btype} "


@pytest.mark.parametrize("step", BUILD_STEPS)
def test_override_step(capsys, rosbuilder, step):
    run(
        rosbuilder("--clean"),
        {f"ROS_EXECUTE_CUSTOM_{step.upper()}": "CUSTOMIZED COMMAND"},
    )
    run(rosbuilder(), {f"ROS_EXECUTE_CUSTOM_{step.upper()}": "CUSTOMIZED COMMAND"})
    captured = capsys.readouterr()
    for test_step, test_type in itertools.product(BUILD_STEPS, BUILD_TYPES):
        assert bool(
            re.search(
                f"(?m)^{cmdind}{default_command(test_step, test_type)}", captured.out
            )
        ) == (test_step != step)
    assert re.search(f"(?m)^{cmdind}CUSTOMIZED COMMAND$", captured.out)


@pytest.mark.parametrize("step,btype", itertools.product(BUILD_STEPS, BUILD_TYPES))
def test_override_type_step(capsys, rosbuilder, step, btype):
    run(
        rosbuilder("--clean"),
        {f"ROS_EXECUTE_CUSTOM_{step.upper()}_{btype.upper()}": "CUSTOMIZED COMMAND"},
    )
    run(
        rosbuilder(),
        {f"ROS_EXECUTE_CUSTOM_{step.upper()}_{btype.upper()}": "CUSTOMIZED COMMAND"},
    )
    captured = capsys.readouterr()
    for test_step, test_type in itertools.product(BUILD_STEPS, BUILD_TYPES):
        assert bool(
            re.search(
                f"(?m)^{cmdind}{default_command(test_step, test_type)}", captured.out
            )
        ) == (test_step != step or test_type != btype)
    assert re.search(f"(?m)^{cmdind}CUSTOMIZED COMMAND$", captured.out)


@pytest.mark.parametrize("step", BUILD_STEPS)
def test_before_hook(capsys, rosbuilder, step):
    run(
        rosbuilder("--clean"),
        {f"ROS_EXECUTE_BEFORE_{step.upper()}": "CUSTOMIZED COMMAND"},
    )
    run(rosbuilder(), {f"ROS_EXECUTE_BEFORE_{step.upper()}": "CUSTOMIZED COMMAND"})
    captured = capsys.readouterr()
    for test_step, test_type in itertools.product(BUILD_STEPS, BUILD_TYPES):
        assert bool(
            re.search(
                f"(?m)^{cmdind}CUSTOMIZED COMMAND\n{cmdind}{default_command(test_step, test_type)}",
                captured.out,
            )
        ) == (test_step == step)


@pytest.mark.parametrize("step", BUILD_STEPS)
def test_after_hook(capsys, rosbuilder, step):
    run(
        rosbuilder("--clean"),
        {f"ROS_EXECUTE_AFTER_{step.upper()}": "CUSTOMIZED COMMAND"},
    )
    run(rosbuilder(), {f"ROS_EXECUTE_AFTER_{step.upper()}": "CUSTOMIZED COMMAND"})
    captured = capsys.readouterr()
    for test_step, test_type in itertools.product(BUILD_STEPS, BUILD_TYPES):
        assert bool(
            re.search(
                f"(?m)^{cmdind}{default_command(test_step, test_type)}.*\n{cmdind}CUSTOMIZED COMMAND$",
                captured.out,
            )
        ) == (test_step == step)


@pytest.mark.parametrize("step,btype", itertools.product(BUILD_STEPS, BUILD_TYPES))
def test_before_type_hook(capsys, rosbuilder, step, btype):
    run(
        rosbuilder("--clean"),
        {f"ROS_EXECUTE_BEFORE_{step.upper()}_{btype.upper()}": "CUSTOMIZED COMMAND"},
    )
    run(
        rosbuilder(),
        {f"ROS_EXECUTE_BEFORE_{step.upper()}_{btype.upper()}": "CUSTOMIZED COMMAND"},
    )
    captured = capsys.readouterr()
    for test_step, test_type in itertools.product(BUILD_STEPS, BUILD_TYPES):
        assert bool(
            re.search(
                f"(?m)^{cmdind}CUSTOMIZED COMMAND\n{cmdind}{default_command(test_step, test_type)}",
                captured.out,
            )
        ) == (test_step == step and test_type == btype)


@pytest.mark.parametrize("step,btype", itertools.product(BUILD_STEPS, BUILD_TYPES))
def test_after_type_hook(capsys, rosbuilder, step, btype):
    run(
        rosbuilder("--clean"),
        {f"ROS_EXECUTE_AFTER_{step.upper()}_{btype.upper()}": "CUSTOMIZED COMMAND"},
    )
    run(
        rosbuilder(),
        {f"ROS_EXECUTE_AFTER_{step.upper()}_{btype.upper()}": "CUSTOMIZED COMMAND"},
    )
    captured = capsys.readouterr()
    for test_step, test_type in itertools.product(BUILD_STEPS, BUILD_TYPES):
        assert bool(
            re.search(
                f"(?m)^{cmdind}{default_command(test_step, test_type)}.*\n{cmdind}CUSTOMIZED COMMAND$",
                captured.out,
            )
        ) == (test_step == step and test_type == btype)


@pytest.mark.parametrize("step", BUILD_STEPS)
def test_extra_args(capsys, rosbuilder, step):
    run(rosbuilder("--clean"), {f"ROS_{step.upper()}_ARGS": "EXTRA ARGS"})
    run(rosbuilder(), {f"ROS_{step.upper()}_ARGS": "EXTRA ARGS"})
    captured = capsys.readouterr()
    for test_step, test_type in itertools.product(BUILD_STEPS, BUILD_TYPES):
        assert bool(
            re.search(
                f"(?m)^{cmdind}{default_command(test_step, test_type)}.* EXTRA ARGS$",
                captured.out,
            )
        ) == (test_step == step)


@pytest.mark.parametrize("step,btype", itertools.product(BUILD_STEPS, BUILD_TYPES))
def test_extra_type_args(capsys, rosbuilder, step, btype):
    run(
        rosbuilder("--clean"),
        {f"ROS_{step.upper()}_{btype.upper()}_ARGS": "EXTRA ARGS"},
    )
    run(rosbuilder(), {f"ROS_{step.upper()}_{btype.upper()}_ARGS": "EXTRA ARGS"})
    captured = capsys.readouterr()
    for test_step, test_type in itertools.product(BUILD_STEPS, BUILD_TYPES):
        assert bool(
            re.search(
                f"(?m)^{cmdind}{default_command(test_step, test_type)}.* EXTRA ARGS$",
                captured.out,
            )
        ) == (test_step == step and test_type == btype)


@pytest.mark.parametrize("step", BUILD_STEPS)
def test_command_prefix(capsys, rosbuilder, step):
    run(rosbuilder("--clean"), {f"ROS_{step.upper()}_WRAPPER": "WRAPPING COMMAND"})
    run(rosbuilder(), {f"ROS_{step.upper()}_WRAPPER": "WRAPPING COMMAND"})
    captured = capsys.readouterr()
    for test_step, test_type in itertools.product(BUILD_STEPS, BUILD_TYPES):
        assert bool(
            re.search(
                f"(?m)^{cmdind}WRAPPING COMMAND {default_command(test_step, test_type)}",
                captured.out,
            )
        ) == (test_step == step)


@pytest.mark.parametrize("step,btype", itertools.product(BUILD_STEPS, BUILD_TYPES))
def test_type_command_prefix(capsys, rosbuilder, step, btype):
    run(
        rosbuilder("--clean"),
        {f"ROS_{step.upper()}_{btype.upper()}_WRAPPER": "WRAPPING COMMAND"},
    )
    run(
        rosbuilder(),
        {f"ROS_{step.upper()}_{btype.upper()}_WRAPPER": "WRAPPING COMMAND"},
    )
    captured = capsys.readouterr()
    for test_step, test_type in itertools.product(BUILD_STEPS, BUILD_TYPES):
        assert bool(
            re.search(
                f"(?m)^{cmdind}WRAPPING COMMAND {default_command(test_step, test_type)}",
                captured.out,
            )
        ) == (test_step == step and test_type == btype)


@pytest.mark.parametrize("package", [f"foo_{t}" for t in BUILD_TYPES])
def test_skip_package(capsys, rosbuilder, package):
    run(rosbuilder(), {f"ROS_SKIP_PACKAGES": package})
    captured = capsys.readouterr()
    for test_type in BUILD_TYPES:
        assert bool(
            re.search(
                f"(?m)^{cmdind}{default_command('build', test_type)}", captured.out
            )
        ) == (f"foo_{test_type}" != package)


@pytest.mark.parametrize("package", [f"foo_{t}" for t in BUILD_TYPES] + ["1"])
def test_skip_tests(capsys, rosbuilder, package):
    run(rosbuilder(), {f"ROS_SKIP_TESTS": package})
    captured = capsys.readouterr()
    for test_type in BUILD_TYPES:
        assert re.search(
            f"(?m)^{cmdind}{default_command('build', test_type)}", captured.out
        )
        assert bool(
            re.search(
                f"(?m)^{cmdind}{default_command('test', test_type)}", captured.out
            )
        ) == (f"foo_{test_type}" != package and package != "1")
        if test_type != "ament_python":
            build_testing = (
                "ON" if f"foo_{test_type}" != package and package != "1" else "OFF"
            )
            assert re.search(
                f"(?m)^{cmdind}{default_command('configure', test_type)}.* -DBUILD_TESTING={build_testing}",
                captured.out,
            )
