import pytest

from cobbler import enums, utils, validate
from cobbler.api import CobblerAPI
from tests.conftest import does_not_raise


@pytest.mark.parametrize("test_architecture,test_raise", [
    (enums.Archs.X86_64, does_not_raise()),
    ("x86_64", does_not_raise()),
    ("abc", pytest.raises(ValueError)),
    (0, pytest.raises(TypeError))
])
def test_validate_arch(test_architecture, test_raise):
    # Arrange

    # Act
    with test_raise:
        result = validate.validate_arch(test_architecture)

        # Assert
        if isinstance(test_architecture, str):
            assert result.value == test_architecture
        elif isinstance(test_architecture, enums.Archs):
            assert result == test_architecture
        else:
            raise TypeError("result had a non expected result")


def test_validate_os_version():
    # Arrange
    utils.load_signatures("/var/lib/cobbler/distro_signatures.json")

    # Act
    result = validate.validate_os_version("rhel4", "redhat")

    # Assert
    assert result == "rhel4"


def test_validate_breed():
    # Arrange
    utils.load_signatures("/var/lib/cobbler/distro_signatures.json")

    # Act
    result = validate.validate_breed("redhat")

    # Assert
    assert result == "redhat"


def test_set_repos():
    # Arrange
    test_api = CobblerAPI()

    # Act
    # TODO: Test this also with the bypass check
    result = validate.validate_repos("testrepo1 testrepo2", test_api, bypass_check=True)

    # Assert
    assert result == ["testrepo1", "testrepo2"]


def test_set_virt_file_size():
    # Arrange

    # Act
    # TODO: Test multiple disks via comma separation
    result = validate.validate_virt_file_size("8")

    # Assert
    assert isinstance(result, float)
    assert result == 8


@pytest.mark.parametrize("test_driver,test_raise", [
    (enums.VirtDiskDrivers.RAW, does_not_raise()),
    (enums.VALUE_INHERITED, does_not_raise()),
    (enums.VirtDiskDrivers.INHERTIED, does_not_raise()),
    ("qcow2", does_not_raise()),
    ("bad_driver", pytest.raises(ValueError)),
    (0, pytest.raises(TypeError))
])
def test_set_virt_disk_driver(test_driver, test_raise):
    # Arrange

    # Act
    with test_raise:
        result = validate.validate_virt_disk_driver(test_driver)

        # Assert
        if isinstance(test_driver, str):
            assert result.value == test_driver
        elif isinstance(test_driver, enums.VirtDiskDrivers):
            assert result == test_driver
        else:
            raise TypeError("Unexpected type for value!")


@pytest.mark.parametrize("test_autoboot,expectation", [
    (True, does_not_raise()),
    (False, does_not_raise()),
    (0, does_not_raise()),
    (1, does_not_raise()),
    (2, does_not_raise()),
    ("Test", does_not_raise())
])
def test_set_virt_auto_boot(test_autoboot, expectation):
    # Arrange

    # Act
    with expectation:
        result = validate.validate_virt_auto_boot(test_autoboot)

        # Assert
        assert isinstance(result, bool)
        assert result is True or result is False


@pytest.mark.parametrize("test_input,expected_exception", [
    (True, does_not_raise()),
    (False, does_not_raise()),
    (0, does_not_raise()),
    (1, does_not_raise()),
    (5, does_not_raise()),
    ("", does_not_raise())
])
def test_set_virt_pxe_boot(test_input, expected_exception):
    # Arrange

    # Act
    with expected_exception:
        result = validate.validate_virt_pxe_boot(test_input)

        # Assert
        assert isinstance(result, bool)
        assert result or not result


def test_set_virt_ram():
    # Arrange

    # Act
    result = validate.validate_virt_ram(1024)

    # Assert
    assert result == 1024


@pytest.mark.parametrize("value,expected_exception", [
    ("qemu", does_not_raise()),
    (enums.VirtType.QEMU, does_not_raise()),
    (0, pytest.raises(TypeError))
])
def test_set_virt_type(value, expected_exception):
    # Arrange

    # Act
    with expected_exception:
        result = validate.validate_virt_type("qemu")

        # Assert
        if isinstance(value, str):
            assert result.value == value
        elif isinstance(value, enums.VirtType):
            assert result == value
        else:
            raise TypeError("Unexpected type for value!")


def test_set_virt_bridge():
    # Arrange

    # Act
    result = validate.validate_virt_bridge("testbridge")

    # Assert
    assert result == "testbridge"


def test_validate_virt_path():
    # Arrange
    test_location = "/somerandomfakelocation"

    # Act
    result = validate.validate_virt_path(test_location)

    # Assert
    assert result == test_location


@pytest.mark.parametrize("value,expected_exception", [
    (0, does_not_raise()),
    (5, does_not_raise()),
    (enums.VALUE_INHERITED, does_not_raise()),
    (False, does_not_raise()),
    (0.0, pytest.raises(TypeError)),
    (-5, pytest.raises(ValueError)),
    ("test", pytest.raises(TypeError))
])
def test_set_virt_cpus(value, expected_exception):
    # Arrange

    # Act
    with expected_exception:
        result = validate.validate_virt_cpus(value)

        # Assert
        if value == enums.VALUE_INHERITED:
            assert result == 0
        else:
            assert result == int(value)


def test_set_serial_device():
    # Arrange

    # Act
    result = validate.validate_serial_device(0)

    # Assert
    assert result == 0


def test_set_serial_baud_rate():
    # Arrange

    # Act
    result = validate.validate_serial_baud_rate(9600)

    # Assert
    assert result == enums.BaudRates.B9600


@pytest.mark.parametrize("test_value,expected_result", [
    ("test", False),
    (0, False),
    ("ftp://test/test", False),
    ("http://test_invalid/test", False),
    ("http://test§invalid/test", False),
    ("http://test.local/test", True),
    # ("http://test.local:80/test", True),
    ("http://test/test", True),
    ("http://@@server@@/test", True),
    ("http://10.0.0.1/test", True),
    ("http://fe80::989c:95ff:fe42:47bf/test", True),
])
def test_validate_boot_remote_file(test_value, expected_result):
    # Arrange

    # Act
    result = validate.validate_boot_remote_file(test_value)

    # Assert
    assert expected_result == result


@pytest.mark.parametrize("test_value,expected_result", [
    ("test", False),
    (0, False),
    ("http://test.local/test", False),
    ("http://test/test", False),
    ("ftp://test/test", False),
    # ("(tftp,10.0.0.1:invalid)/test", False),
    # ("(tftp,local_invalid)/test", False),
    ("(http,10.0.0.1)/test", True),
    ("(tftp,10.0.0.1)/test", True),
    ("(tftp,test.local)/test", True),
    ("(tftp,10.0.0.1:8080)/test", True)
])
def test_validate_grub_remote_file(test_value, expected_result):
    # Arrange

    # Act
    result = validate.validate_grub_remote_file(test_value)

    # Assert
    assert expected_result == result
