"""
Monit service module. This module will create a monit type
service watcher.
"""

import re

import salt.utils.path

# Function alias to make sure not to shadow built-in's
__func_alias__ = {
    "id_": "id",
    "reload_": "reload",
}


def __virtual__():
    if salt.utils.path.which("monit") is not None:
        # The monit binary exists, let the module load
        return True
    return (
        False,
        "The monit execution module cannot be loaded: the monit binary is not in the"
        " path.",
    )


def start(name):
    """

    CLI Example:

    .. code-block:: bash

        salt '*' monit.start <service name>
    """
    cmd = f"monit start {name}"

    return not __salt__["cmd.retcode"](cmd, python_shell=False)


def stop(name):
    """
    Stops service via monit

    CLI Example:

    .. code-block:: bash

        salt '*' monit.stop <service name>
    """
    cmd = f"monit stop {name}"

    return not __salt__["cmd.retcode"](cmd, python_shell=False)


def restart(name):
    """
    Restart service via monit

    CLI Example:

    .. code-block:: bash

        salt '*' monit.restart <service name>
    """
    cmd = f"monit restart {name}"

    return not __salt__["cmd.retcode"](cmd, python_shell=False)


def unmonitor(name):
    """
    Unmonitor service via monit

    CLI Example:

    .. code-block:: bash

        salt '*' monit.unmonitor <service name>
    """
    cmd = f"monit unmonitor {name}"

    return not __salt__["cmd.retcode"](cmd, python_shell=False)


def monitor(name):
    """
    monitor service via monit

    CLI Example:

    .. code-block:: bash

        salt '*' monit.monitor <service name>
    """
    cmd = f"monit monitor {name}"

    return not __salt__["cmd.retcode"](cmd, python_shell=False)


def summary(svc_name=""):
    """
    Display a summary from monit

    CLI Example:

    .. code-block:: bash

        salt '*' monit.summary
        salt '*' monit.summary <service name>
    """
    ret = {}
    cmd = "monit summary"
    res = __salt__["cmd.run"](cmd).splitlines()
    for line in res:
        if "daemon is not running" in line:
            return dict(monit="daemon is not running", result=False)
        elif not line or svc_name not in line or "The Monit daemon" in line:
            continue
        else:
            parts = line.split("'")
            if len(parts) == 3:
                resource, name, status_ = (parts[0].strip(), parts[1], parts[2].strip())
                if svc_name != "" and svc_name != name:
                    continue
                if resource not in ret:
                    ret[resource] = {}
                ret[resource][name] = status_
    return ret


def status(svc_name=""):
    """
    Display a process status from monit

    CLI Example:

    .. code-block:: bash

        salt '*' monit.status
        salt '*' monit.status <service name>
    """

    cmd = "monit status"
    res = __salt__["cmd.run"](cmd)

    # Monit uses a different separator since 5.18.0
    if version() < "5.18.0":
        fieldlength = 33
    else:
        fieldlength = 28

    separator = 3 + fieldlength
    prostr = "Process" + " " * fieldlength

    s = res.replace("Process", prostr).replace("'", "").split("\n\n")
    entries = {}
    for process in s[1:-1]:
        pro = process.splitlines()
        tmp = {}
        for items in pro:
            key = items[:separator].strip()
            tmp[key] = items[separator - 1 :].strip()
        entries[pro[0].split()[1]] = tmp
    if svc_name == "":
        ret = entries
    else:
        ret = entries.get(svc_name, "No such service")
    return ret


def reload_():
    """
    .. versionadded:: 2016.3.0

    Reload monit configuration

    CLI Example:

    .. code-block:: bash

        salt '*' monit.reload
    """
    cmd = "monit reload"
    return not __salt__["cmd.retcode"](cmd, python_shell=False)


def configtest():
    """
    .. versionadded:: 2016.3.0

    Test monit configuration syntax

    CLI Example:

    .. code-block:: bash

        salt '*' monit.configtest
    """
    ret = {}
    cmd = "monit -t"
    out = __salt__["cmd.run_all"](cmd)

    if out["retcode"] != 0:
        ret["comment"] = "Syntax Error"
        ret["stderr"] = out["stderr"]
        ret["result"] = False
        return ret

    ret["comment"] = "Syntax OK"
    ret["stdout"] = out["stdout"]
    ret["result"] = True
    return ret


def version():
    """
    .. versionadded:: 2016.3.0

    Return version from monit -V

    CLI Example:

    .. code-block:: bash

        salt '*' monit.version
    """
    cmd = "monit -V"
    out = __salt__["cmd.run"](cmd).splitlines()
    ret = out[0].split()
    return ret[-1]


def id_(reset=False):
    """
    .. versionadded:: 2016.3.0

    Return monit unique id.

    reset : False
        Reset current id and generate a new id when it's True.

    CLI Example:

    .. code-block:: bash

        salt '*' monit.id [reset=True]
    """
    if reset:
        id_pattern = re.compile(r"Monit id (?P<id>[^ ]+)")
        cmd = "echo y|monit -r"
        out = __salt__["cmd.run_all"](cmd, python_shell=True)
        ret = id_pattern.search(out["stdout"]).group("id")
        return ret if ret else False
    else:
        cmd = "monit -i"
        out = __salt__["cmd.run"](cmd)
        ret = out.split(":")[-1].strip()
    return ret


def validate():
    """
    .. versionadded:: 2016.3.0

    Check all services

    CLI Example:

    .. code-block:: bash

        salt '*' monit.validate
    """
    cmd = "monit validate"
    return not __salt__["cmd.retcode"](cmd, python_shell=False)
