"""
    :codeauthor: Gareth J. Greenaway <ggreenaway@vmware.com>
"""

import logging

import pytest
import salt.modules.beacons as beaconmod
import salt.states.beacon as beaconstate
import salt.states.service as service
import salt.utils.platform
from salt.utils.event import SaltEvent
from tests.support.mock import MagicMock, patch

log = logging.getLogger(__name__)


def func(name):
    """
    Mock func method
    """
    return name


@pytest.fixture
def configure_loader_modules():
    return {
        service: {
            "__env__": "base",
            "__salt__": {},
            "__opts__": {"test": False, "cachedir": ""},
            "__instance_id__": "",
            "__low__": {},
            "__utils__": {},
            "__context__": {},
        },
        beaconstate: {"__salt__": {}, "__opts__": {}},
        beaconmod: {"__salt__": {}, "__opts__": {}},
    }


def test_get_systemd_only():
    """
    Test the _get_system_only function
    """

    def test_func(cats, dogs, no_block):
        pass

    with patch.object(service._get_systemd_only, "HAS_SYSTEMD", True, create=True):
        ret, warnings = service._get_systemd_only(
            test_func, {"cats": 1, "no_block": 2, "unmask": 3}
        )
        assert len(warnings) == 0
        assert ret == {"no_block": 2}

        ret, warnings = service._get_systemd_only(test_func, {"cats": 1, "unmask": 3})

        assert len(warnings) == 0
        assert ret == {}


def test_get_systemd_only_platform():
    """
    Test the _get_system_only function on unsupported platforms
    """

    def test_func(cats, dogs, no_block):
        pass

    with patch.object(service._get_systemd_only, "HAS_SYSTEMD", False, create=True):
        ret, warnings = service._get_systemd_only(
            test_func, {"cats": 1, "no_block": 2, "unmask": 3}
        )

        assert warnings == ["The 'no_block' argument is not supported by this platform"]
        assert ret == {}

        ret, warnings = service._get_systemd_only(test_func, {"cats": 1, "unmask": 3})

        assert len(warnings) == 0
        assert ret == {}


def test_get_systemd_only_no_mock():
    """
    Test the _get_system_only without mocking
    """

    def test_func(cats, dogs, no_block):
        pass

    ret, warnings = service._get_systemd_only(
        test_func, {"cats": 1, "no_block": 2, "unmask": 3}
    )

    assert isinstance(ret, dict)
    assert isinstance(warnings, list)


def test_running():
    """
    Test to verify that the service is running
    """
    ret = [
        {"comment": "", "changes": {}, "name": "salt", "result": True},
        {
            "changes": {},
            "comment": "The service salt is already running",
            "name": "salt",
            "result": True,
        },
        {
            "changes": "saltstack",
            "comment": "The service salt is already running",
            "name": "salt",
            "result": True,
        },
        {
            "changes": {},
            "comment": "Service salt is set to start",
            "name": "salt",
            "result": None,
        },
        {
            "changes": "saltstack",
            "comment": "Started service salt",
            "name": "salt",
            "result": True,
        },
        {
            "changes": {},
            "comment": "The service salt is already running",
            "name": "salt",
            "result": True,
        },
        {
            "changes": "saltstack",
            "comment": "Service salt failed to start",
            "name": "salt",
            "result": False,
        },
        {
            "changes": "saltstack",
            "comment": (
                "Started service salt\nService masking not available on this minion"
            ),
            "name": "salt",
            "result": True,
        },
        {
            "changes": "saltstack",
            "comment": (
                "Started service salt\nService masking not available on this minion"
            ),
            "name": "salt",
            "result": True,
        },
        {
            "changes": {},
            "comment": (
                "The service salt is disabled but enable is not True. Set enable to"
                " True to successfully start the service."
            ),
            "name": "salt",
            "result": False,
        },
        {
            "changes": {},
            "comment": "The service salt is set to restart",
            "name": "salt",
            "result": None,
        },
    ]

    tmock = MagicMock(return_value=True)
    fmock = MagicMock(return_value=False)
    vmock = MagicMock(return_value="salt")
    with patch.object(service, "_enabled_used_error", vmock):
        assert service.running("salt", enabled=1) == "salt"

    with patch.object(service, "_available", fmock):
        assert service.running("salt") == ret[0]

    with patch.object(service, "_available", tmock):
        with patch.dict(service.__opts__, {"test": False}):
            with patch.dict(
                service.__salt__,
                {"service.enabled": tmock, "service.status": tmock},
            ):
                assert service.running("salt") == ret[1]

            mock = MagicMock(return_value={"changes": "saltstack"})
            with patch.dict(
                service.__salt__,
                {
                    "service.enabled": MagicMock(side_effect=[False, True]),
                    "service.status": tmock,
                },
            ):
                with patch.object(service, "_enable", mock):
                    assert service.running("salt", True) == ret[2]

            with patch.dict(
                service.__salt__,
                {
                    "service.enabled": MagicMock(side_effect=[True, False]),
                    "service.status": tmock,
                },
            ):
                with patch.object(service, "_disable", mock):
                    assert service.running("salt", False) == ret[2]

            with patch.dict(
                service.__salt__,
                {
                    "service.status": MagicMock(side_effect=[False, True]),
                    "service.enabled": MagicMock(side_effect=[False, True]),
                    "service.start": MagicMock(return_value="stack"),
                },
            ):
                with patch.object(
                    service,
                    "_enable",
                    MagicMock(return_value={"changes": "saltstack"}),
                ):
                    assert service.running("salt", True) == ret[4]

            with patch.dict(
                service.__salt__,
                {
                    "service.status": MagicMock(side_effect=[False, True]),
                    "service.enabled": MagicMock(side_effect=[False, True]),
                    "service.unmask": MagicMock(side_effect=[False, True]),
                    "service.start": MagicMock(return_value="stack"),