"""
Module for configuring DNS Client on Windows systems
"""


def __virtual__():
    """
    Load if the module win_dns_client is loaded
    """
    if "win_dns_client.add_dns" in __salt__:
        return "win_dns_client"
    return (False, "win_dns_client module could not be loaded")


def dns_exists(name, servers=None, interface="Local Area Connection", replace=False):
    """
    Configure the DNS server list in the specified interface

    Example:

    .. code-block:: yaml

        config_dns_servers:
          win_dns_client.dns_exists:
            - replace: True #remove any servers not in the "servers" list, default is False
            - servers:
              - 8.8.8.8
              - 8.8.8.9
    """
    ret = {
        "name": name,
        "result": True,
        "changes": {
            "Servers Reordered": [],
            "Servers Added": [],
            "Servers Removed": [],
        },
        "comment": "",
    }

    if __opts__["test"]:
        ret["comment"] = "DNS Servers are set to be updated"
        ret["result"] = None
    else:
        ret["comment"] = "DNS Servers have been updated"

    # Validate syntax
    if not isinstance(servers, list):
        ret["result"] = False
        ret["comment"] = "servers entry is not a list !"
        return ret

    # Do nothing is already configured
    configured_list = __salt__["win_dns_client.get_dns_servers"](interface)
    if configured_list == servers:
        ret["comment"] = f"{servers} are already configured"
        ret["changes"] = {}
        ret["result"] = True
        return ret

    # add the DNS servers
    for i, server in enumerate(servers):
        if __opts__["test"]:
            if server in configured_list:
                if configured_list.index(server) != i:
                    ret["changes"]["Servers Reordered"].append(server)
            else:
                ret["changes"]["Servers Added"].append(server)
        else:
            if not __salt__["win_dns_client.add_dns"](server, interface, i + 1):
                ret["comment"] = "Failed to add {} as DNS server number {}".format(
                    server, i + 1
                )
                ret["result"] = False
                ret["changes"] = {}
                return ret
            else:
                if server in configured_list:
                    if configured_list.index(server) != i:
                        ret["changes"]["Servers Reordered"].append(server)
                else:
                    ret["changes"]["Servers Added"].append(server)

    # remove dns servers that weren't in our list
    if replace:
        for i, server in enumerate(configured_list):
            if server not in servers:
                if __opts__["test"]:
                    ret["changes"]["Servers Removed"].append(server)
                else:
                    if not __salt__["win_dns_client.rm_dns"](server, interface):
                        ret["comment"] = (
                            f"Failed to remove {server} from DNS server list"
                        )
                        ret["result"] = False
                        return ret
                    else:
                        ret["changes"]["Servers Removed"].append(server)

    return ret


def dns_dhcp(name, interface="Local Area Connection"):
    """
    Configure the DNS server list from DHCP Server
    """
    ret = {"name": name, "result": True, "changes": {}, "comment": ""}

    # Check the config
    config = __salt__["win_dns_client.get_dns_config"](interface)
    if config == "dhcp":
        ret["comment"] = f"{interface} already configured with DNS from DHCP"
        return ret
    else:
        ret["changes"] = {"dns": "configured from DHCP"}

    if __opts__["test"]:
        ret["result"] = None
        return ret

    # change the configuration
    ret["result"] = __salt__["win_dns_client.dns_dhcp"](interface)
    if not ret["result"]:
        ret["changes"] = {}
        ret["comment"] = 'Could not configure "{}" DNS servers from DHCP'.format(
            interface
        )

    return ret


def primary_suffix(name, suffix=None, updates=False):
    """
    .. versionadded:: 2014.7.0

    Configure the global primary DNS suffix of a DHCP client.

    suffix : None
        The suffix which is advertised for this client when acquiring a DHCP lease
        When none is set, the explicitly configured DNS suffix will be removed.

    updates : False
        Allow syncing the DNS suffix with the AD domain when the client's AD domain membership changes

    .. code-block:: yaml

        primary_dns_suffix:
            win_dns_client.primary_suffix:
                - suffix: sub.domain.tld
                - updates: True
    """

    ret = {"name": name, "changes": {}, "result": True, "comment": "No changes needed"}

    suffix = str(suffix)

    if not isinstance(updates, bool):
        ret["result"] = False
        ret["comment"] = "'updates' must be a boolean value"
        return ret

    # TODO: waiting for an implementation of
    # https://github.com/saltstack/salt/issues/6792 to be able to handle the
    # requirement for a reboot to actually apply this state.
    # Until then, this method will only be able to verify that the required
    # value has been written to the registry and rebooting needs to be handled
    # manually

    reg_data = {
        "suffix": {
            "hive": "HKEY_LOCAL_MACHINE",
            "key": r"SYSTEM\CurrentControlSet\services\Tcpip\Parameters",
            "vname": "NV Domain",
            "vtype": "REG_SZ",
            "old": None,
            "new": suffix,
        },
        "updates": {
            "hive": "HKEY_LOCAL_MACHINE",
            "key": r"SYSTEM\CurrentControlSet\services\Tcpip\Parameters",
            "vname": "SyncDomainWithMembership",
            "vtype": "REG_DWORD",
            "old": None,
            "new": updates,
        },
    }

    reg_data["suffix"]["old"] = __utils__["reg.read_value"](
        reg_data["suffix"]["hive"],
        reg_data["suffix"]["key"],
        reg_data["suffix"]["vname"],
    )["vdata"]

    reg_data["updates"]["old"] = bool(
        __utils__["reg.read_value"](
            reg_data["updates"]["hive"],
            reg_data["updates"]["key"],
            reg_data["updates"]["vname"],
        )["vdata"]
    )

    updates_operation = "enabled" if reg_data["updates"]["new"] else "disabled"

    # No changes to suffix needed
    if reg_data["suffix"]["new"] == reg_data["suffix"]["old"]:
        # No changes to updates policy needed
        if reg_data["updates"]["new"] == reg_data["updates"]["old"]:
            return ret
        # Changes to update policy needed
        else:
            ret["comment"] = f"{updates_operation} suffix updates"
            ret["changes"] = {
                "old": {"updates": reg_data["updates"]["old"]},
                "new": {"updates": reg_data["updates"]["new"]},
            }
    # Changes to suffix needed
    else:
        # Changes to updates policy needed
        if reg_data["updates"]["new"] != reg_data["updates"]["old"]:
            ret["comment"] = (
                "Updated primary DNS suffix ({}) and {} suffix updates".format(
                    suffix, updates_operation
                )
            )
            ret["changes"] = {
                "old": {
                    "suffix": reg_data["suffix"]["old"],
                    "updates": reg_data["updates"]["old"],
                },
                "new": {
                    "suffix": reg_data["suffix"]["new"],
                    "updates": reg_data["updates"]["new"],
                },
            }
        # No changes to updates policy needed
        else:
            ret["comment"] = f"Updated primary DNS suffix ({suffix})"
            ret["changes"] = {
                "old": {"suffix": reg_data["suffix"]["old"]},
                "new": {"suffix": reg_data["suffix"]["new"]},
            }

    suffix_result = __utils__["reg.set_value"](
        reg_data["suffix"]["hive"],
        reg_data["suffix"]["key"],
        reg_data["suffix"]["vname"],
        reg_data["suffix"]["new"],
        reg_data["suffix"]["vtype"],
    )

    updates_result = __utils__["reg.set_value"](
        reg_data["updates"]["hive"],
        reg_data["updates"]["key"],
        reg_data["updates"]["vname"],
        reg_data["updates"]["new"],
        reg_data["updates"]["vtype"],
    )

    ret["result"] = suffix_result & updates_result

    return ret
