"""
:codeauthor: Gareth J. Greenaway (ggreenaway@vmware.com)
"""

import logging
import os

import pytest
import salt.defaults.exitcodes
from saltfactories.exceptions import FactoryNotStarted
from saltfactories.utils import random_string
from tests.support.helpers import PRE_PYTEST_SKIP_REASON

log = logging.getLogger(__name__)


@pytest.fixture(scope="package", autouse=True)
def skip_on_tcp_transport(request):
    if request.config.getoption("--transport") == "tcp":
        pytest.skip("Deltaproxy under the TPC transport is not working. See #61367")


@pytest.fixture
def proxy_minion_id(salt_master):
    _proxy_minion_id = random_string("proxy-minion-")

    try:
        yield _proxy_minion_id
    finally:
        # Remove stale key if it exists
        pytest.helpers.remove_stale_minion_key(salt_master, _proxy_minion_id)


def clear_proxy_minions(salt_master, proxy_minion_id):
    for proxy in [proxy_minion_id, "dummy_proxy_one", "dummy_proxy_two"]:
        pytest.helpers.remove_stale_minion_key(salt_master, proxy)

        cachefile = os.path.join(
            salt_master.config["cachedir"], "{}.cache".format(proxy)
        )
        if os.path.exists(cachefile):
            os.unlink(cachefile)


@pytest.mark.slow_test
def test_exit_status_no_proxyid(salt_master, proxy_minion_id):
    """
    Ensure correct exit status when --proxyid argument is missing.
    """
    config_defaults = {
        "metaproxy": "deltaproxy",
    }

    with pytest.raises(FactoryNotStarted) as exc:
        factory = salt_master.salt_proxy_minion_daemon(
            proxy_minion_id, include_proxyid_cli_flag=False, defaults=config_defaults
        )
        factory.start(start_timeout=10, max_start_attempts=1)

    assert exc.value.exitcode == salt.defaults.exitcodes.EX_USAGE, exc.value
    assert "Usage" in exc.value.stderr, exc.value
    assert "error: salt-proxy requires --proxyid" in exc.value.stderr, exc.value


@pytest.mark.skip_on_windows(reason="Windows does not do user checks")
def test_exit_status_unknown_user(salt_master, proxy_minion_id):
    """
    Ensure correct exit status when the proxy is configured to run as an
    unknown user.
    """
    config_defaults = {
        "metaproxy": "deltaproxy",
    }

    with pytest.raises(FactoryNotStarted) as exc:
        factory = salt_master.salt_proxy_minion_daemon(
            proxy_minion_id,
            overrides={"user": "unknown-user"},
            defaults=config_defaults,
        )
        factory.start(start_timeout=10, max_start_attempts=1)

    assert exc.value.exitcode == salt.defaults.exitcodes.EX_NOUSER, exc.value
    assert "The user is not available." in exc.value.stderr, exc.value


@pytest.mark.slow_test
def test_exit_status_unknown_argument(salt_master, proxy_minion_id):
    """
    Ensure correct exit status when an unknown argument is passed to
    salt-proxy.
    """
    config_defaults = {
        "metaproxy": "deltaproxy",
    }

    with pytest.raises(FactoryNotStarted) as exc:
        factory = salt_master.salt_proxy_minion_daemon(
            proxy_minion_id, defaults=config_defaults
        )
        factory.start("--unknown-argument", start_timeout=10, max_start_attempts=1)

    assert exc.value.exitcode == salt.defaults.exitcodes.EX_USAGE, exc.value
    assert "Usage" in exc.value.stderr, exc.value
    assert "no such option: --unknown-argument" in exc.value.stderr, exc.value


# Hangs on Windows. You can add a timeout to the proxy.run command, but then
# it just times out.
@pytest.mark.skip_on_windows(reason=PRE_PYTEST_SKIP_REASON)
def test_exit_status_correct_usage(
    salt_master,
    salt_cli,
    proxy_minion_id,
):
    """
    Ensure the salt-proxy control proxy starts and
    is able to respond to test.ping, additionally ensure that
    the proxies being controlled also respond to test.ping.

    Finally ensure correct exit status when salt-proxy exits correctly.

    Skip on Windows because daemonization not supported
    """

    config_defaults = {
        "metaproxy": "deltaproxy",
    }
    proxy_one = "dummy_proxy_one"
    proxy_two = "dummy_proxy_two"

    top_file = """
    base:
      {control}:
        - controlproxy
      {one}:
        - {one}
      {two}:
        - {two}
    """.format(
        control=proxy_minion_id,
        one=proxy_one,
        two=proxy_two,
    )
    controlproxy_pillar_file = """
    proxy:
        proxytype: deltaproxy
        ids:
          - {}
          - {}
    """.format(
        proxy_one, proxy_two
    )

    dummy_proxy_one_pillar_file = """
    proxy:
      proxytype: dummy
    """

    dummy_proxy_two_pillar_file = """
    proxy:
      proxytype: dummy
    """

    top_tempfile = salt_master.pillar_tree.base.temp_file("top.sls", top_file)
    controlproxy_tempfile = salt_master.pillar_tree.base.temp_file(
        "controlproxy.sls", controlproxy_pillar_file
    )
    dummy_proxy_one_tempfile = salt_master.pillar_tree.base.temp_file(
        "{}.sls".format(proxy_one),
        dummy_proxy_one_pillar_file,
    )
    dummy_proxy_two_tempfile = salt_master.pillar_tree.base.temp_file(
        "{}.sls".format(proxy_two),
        dummy_proxy_two_pillar_file,
    )
    with top_tempfile, controlproxy_tempfile, dummy_proxy_one_tempfile, dummy_proxy_two_tempfile:
        factory = salt_master.salt_proxy_minion_daemon(
            proxy_minion_id,
            defaults=config_defaults,
            extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
            start_timeout=240,
        )