"""
NSX-T Transport_Zone state module
"""
import logging

log = logging.getLogger(__name__)

__virtualname__ = "nsxt_transport_zone"

try:
    from saltext.vmware.modules import nsxt_transport_zone

    HAS_NSXT_TRANSPORT_ZONE = True
except ImportError:
    HAS_NSXT_TRANSPORT_ZONE = False


def __virtual__():
    if not HAS_NSXT_TRANSPORT_ZONE:
        return False, "'nsxt_transport_zone' binary not found on system"
    return "nsxt_transport_zone"


def _needs_update(transport_zone_dict, **transport_zone_param):
    updatable_params = {
        "is_default",
        "description",
        "uplink_teaming_policy_names",
        "host_switch_id",
        "host_switch_mode",
        "host_switch_name",
        "transport_type",
        "tags",
    }

    for param in updatable_params:
        param_val_in_existing_transport_zone = transport_zone_dict.get(param)
        param_val_in_inputs_for_update = transport_zone_param.get(param)

        if not param_val_in_existing_transport_zone and param_val_in_inputs_for_update:
            return True
        if param_val_in_existing_transport_zone and not param_val_in_inputs_for_update:
            return True
        if (
            param_val_in_existing_transport_zone
            and param_val_in_inputs_for_update
            and param_val_in_existing_transport_zone != param_val_in_inputs_for_update
        ):
            return True


def present(
    name,
    hostname,
    username,
    password,
    display_name,
    host_switch_name,
    transport_type,
    is_default=None,
    description=None,
    verify_ssl=None,
    cert=None,
    cert_common_name=None,
    host_switch_id=None,
    host_switch_mode=None,
    uplink_teaming_policy_names=None,
    tags=None,
):
    """

    Registers transport zone in NSX-T Manager or updates the transport zone

    CLI Example:

    .. code-block:: bash

        salt vm_minion nsxt_transport_zone.present hostname=nsxt-manager.local username=admin ...

    name
        name of the operation to perform

    hostname
        The host name of NSX-T manager

    username
        Username to connect to NSX-T manager

    password
        Password to connect to NSX-T manager

    host-switch-name
        Host switch name for the transport zone

    transport-type
        Transport type for the transport zone

    is_default
        (Optional) Flag to indicate if the transport zone is the default one.
        Only one transport zone can be the default one for a given transport zone type.
        APIs that need transport zone can choose to use the default transport zone if a transport zone is not given

    display_name
        Display name for the transport zone

    description
        (Optional) Description for the transport zone

    verify_ssl
        (Optional) Option to enable/disable SSL verification. Enabled by default.
        If set to False, the certificate validation is skipped.

    cert
        (Optional) Path to the SSL certificate file to connect to NSX-T manager.
        The certificate can be retrieved from browser.

    cert_common_name
        (Optional) By default, the hostname parameter and the common name in certificate is compared for host name verification.
        If the client certificate common name and hostname do not match (in case of self-signed certificates),
        specify the certificate common name as part of this parameter. This value is then used to compare against
        certificate common name.

    host_switch_id
        (Optional) The host switch id generated by the system.

    host_switch_mode
        (Optional) Operational mode of the transport zone.
        STANDARD mode applies to all the hypervisors. ENS mode stands for Enhanced Networking Stack.
        This feature is only available for ESX hypervisor. It is not available on KVM, EDGE and Public Cloud Gateway etc.
        When a Transport Zone mode is set to ENS, only Transport Nodes of type ESX can participate in such a Transport Zone.

    host_switch_name
        (Optional) Name of the host switch on all transport nodes in this transport zone that will be used to run NSX network traffic.
        If this name is unset or empty then the default host switch name will be used.

    uplink_teaming_policy_names
        (Optional) Names of the switching uplink teaming policies that are supported by this transport zone.

    tags
        (Optional) Opaque identifiers meaningful to the API user

    """

    ret = {"name": name, "changes": {}, "result": None, "comment": ""}

    get_transport_zone = __salt__["nsxt_transport_zone.get_by_display_name"](
        hostname=hostname,
        username=username,
        password=password,
        display_name=display_name,
        verify_ssl=verify_ssl,
        cert=cert,
        cert_common_name=cert_common_name,
    )

    transport_zone_dict, transport_zone_id = None, None
    is_update = False

    if "error" in get_transport_zone:
        ret["result"] = False
        ret["comment"] = "Failed to get the transport zones : {}".format(
            get_transport_zone["error"]
        )
        return ret

    transport_zone_response_by_display_name = get_transport_zone["results"]

    transport_zone_dict = (
        transport_zone_response_by_display_name[0]
        if len(transport_zone_response_by_display_name) > 0
        else None
    )

    if len(transport_zone_response_by_display_name) > 1:
        ret["result"] = False
        ret["comment"] = "More than one transport zone exist with same display name : {}".format(
            display_name
        )
        return ret

    if transport_zone_dict is not None:
        is_update = _needs_update(
            transport_zone_dict,
            host_switch_name=host_switch_name,
            transport_type=transport_type,
            description=description,
            host_switch_id=host_switch_id,
            host_switch_mode=host_switch_mode,
            uplink_teaming_policy_names=uplink_teaming_policy_names,
            tags=tags,
            is_default=is_default,
        )
        transport_zone_id = transport_zone_dict["id"]
        revision = transport_zone_dict["_revision"]

    if __opts__["test"]:
        if transport_zone_dict is None:
            ret["result"] = None
            ret["comment"] = "Transport zone will be created in NSX-T Manager"
        else:
            ret["result"] = None
            ret["comment"] = "Transport zone would be updated"
        return ret

    if not is_update:

        if transport_zone_id:
            ret["result"] = True
            ret["comment"] = "Transport zone with display_name %s already exists", display_name
            return ret

        else:
            log.info("Start of the create of the transport zone")
            create_transport_zone = __salt__["nsxt_transport_zone.create"](
                hostname=hostname,
                username=username,
                password=password,
                verify_ssl=verify_ssl,
                cert=cert,
                cert_common_name=cert_common_name,
                display_name=display_name,
                host_switch_name=host_switch_name,
                transport_type=transport_type,
                description=description,
                host_switch_id=host_switch_id,
                host_switch_mode=host_switch_mode,
                uplink_teaming_policy_names=uplink_teaming_policy_names,
                tags=tags,
                is_default=is_default,
            )

        if "error" in create_transport_zone:
            ret["result"] = False
            ret["comment"] = "Fail to create transport_zone : {}".format(
                create_transport_zone["error"]
            )
            return ret

        ret["comment"] = "Transport Zone created successfully"
        ret["result"] = True
        ret["changes"]["new"] = create_transport_zone
        return ret
    else:
        log.info("Start of the update of the transport zone")
        update_transport_zone = __salt__["nsxt_transport_zone.update"](
            hostname=hostname,
            username=username,
            password=password,
            verify_ssl=verify_ssl,
            cert=cert,
            cert_common_name=cert_common_name,
            transport_zone_id=transport_zone_id,
            revision=revision,
            host_switch_name=host_switch_name,
            transport_type=transport_type,
            description=description,
            host_switch_id=host_switch_id,
            host_switch_mode=host_switch_mode,
            uplink_teaming_policy_names=uplink_teaming_policy_names,
            tags=tags,
            is_default=is_default,
            display_name=display_name,
        )

        if "error" in update_transport_zone:
            ret["result"] = False
            ret["comment"] = "Fail to update transport_zone : {}".format(
                update_transport_zone["error"]
            )
            return ret

        ret["comment"] = "Transport Zone updated successfully"
        ret["result"] = True
        ret["changes"]["old"] = transport_zone_dict
        ret["changes"]["new"] = update_transport_zone
        return ret


def absent(
    name,
    hostname,
    username,
    password,
    display_name,
    verify_ssl=None,
    cert=None,
    cert_common_name=None,
):
    """

    Deletes transport zone in NSX-T Manager if present. Requires display_name of the transport zone which user want to delete and also the tranpsort type of the transport zone

    CLI Example:

    .. code-block:: bash

        salt vm_minion nsxt_transport_zone.absent hostname=nsxt-manager.local username=admin ...

    name
        Name of the operation to perform

    hostname
        The host name of NSX-T manager

    username
        Username to connect to NSX-T manager

    password
        Password to connect to NSX-T manager

    display_name
        display_name of the transport zone to be deleted

    transport_type
        transport_type of the transport zone to be deleted

    verify_ssl
        (Optional) Option to enable/disable SSL verification. Enabled by default.
        If set to False, the certificate validation is skipped.

    cert
        (Optional) Path to the SSL certificate file to connect to NSX-T manager.
        The certificate can be retrieved from browser.

    cert_common_name
        (Optional) By default, the hostname parameter and the common name in certificate is compared for host name verification.
        If the client certificate common name and hostname do not match (in case of self-signed certificates),
        specify the certificate common name as part of this parameter. This value is then used to compare against
        certificate common name.

    """

    log.info("Start of the delete of the transport zone")

    ret = {"name": name, "changes": {}, "result": None, "comment": ""}

    transport_zone_dict = None

    get_transport_zone = __salt__["nsxt_transport_zone.get_by_display_name"](
        hostname=hostname,
        username=username,
        password=password,
        display_name=display_name,
        verify_ssl=verify_ssl,
        cert=cert,
        cert_common_name=cert_common_name,
    )

    if "error" in get_transport_zone:
        ret["result"] = False
        ret["comment"] = "Failed to get the transport zones : {}".format(
            get_transport_zone["error"]
        )
        return ret

    transport_zone_response_by_display_name = get_transport_zone["results"]

    transport_zone_dict = (
        transport_zone_response_by_display_name[0]
        if len(transport_zone_response_by_display_name) > 0
        else None
    )

    if len(transport_zone_response_by_display_name) > 1:
        ret["result"] = False
        ret["comment"] = "More than one transport zone exist with same display name : {}".format(
            display_name
        )
        return ret

    if len(transport_zone_response_by_display_name) == 0:
        ret["result"] = True
        ret["comment"] = "No transport zone exist with same display name : {}".format(display_name)
        return ret

    if transport_zone_dict is not None:
        id = transport_zone_dict["id"]

    delete_transport_zone = __salt__["nsxt_transport_zone.delete"](
        hostname=hostname,
        username=username,
        password=password,
        transport_zone_id=id,
        verify_ssl=verify_ssl,
        cert=cert,
        cert_common_name=cert_common_name,
    )

    if "error" in delete_transport_zone:
        ret["result"] = False
        ret["comment"] = "Failed to delete the transport-zone : {}".format(
            delete_transport_zone["error"]
        )
        return ret

    ret["comment"] = "Transport zone deleted successfully"
    ret["changes"]["old"] = transport_zone_dict
    ret["changes"]["new"] = {}
    ret["result"] = True

    return ret
