"""
Autogenerated using `pop-create-idem <https://gitlab.com/saltstack/pop/pop-create-idem>`__

hub.exec.boto3.client.ec2.associate_dhcp_options
hub.exec.boto3.client.ec2.create_dhcp_options
hub.exec.boto3.client.ec2.delete_dhcp_options
hub.exec.boto3.client.ec2.describe_dhcp_options
"""
import copy
from dataclasses import field
from dataclasses import make_dataclass
from typing import Any
from typing import Dict
from typing import List

__contracts__ = ["resource"]
TREQ = {
    "absent": {"require": ["aws.ec2.vpc.absent"]},
}


async def present(
    hub,
    ctx,
    name: str,
    dhcp_configurations: List[
        make_dataclass(
            "NewDhcpConfiguration",
            [
                ("Key", str, field(default=None)),
                ("Values", List[str], field(default=None)),
            ],
        )
    ] = None,
    resource_id: str = None,
    tags: Dict[str, Any]
    or List[
        make_dataclass(
            "Tag",
            [("Key", str, field(default=None)), ("Value", str, field(default=None))],
        )
    ] = None,
    vpc_id: List[str] = None,
) -> Dict[str, Any]:
    r"""
    **Autogenerated function**

    Creates a set of DHCP options for your VPC. After creating the set, you must associate it with the VPC, causing
    all existing and new instances that you launch in the VPC to use this set of DHCP options. The following are the
    individual DHCP options you can specify. For more information about the options, see RFC 2132.    domain-name-
    servers - The IP addresses of up to four domain name servers, or AmazonProvidedDNS. The default DHCP option set
    specifies AmazonProvidedDNS. If specifying more than one domain name server, specify the IP addresses in a
    single parameter, separated by commas. To have your instance receive a custom DNS hostname as specified in
    domain-name, you must set domain-name-servers to a custom DNS server.    domain-name - If you're using
    AmazonProvidedDNS in us-east-1, specify ec2.internal. If you're using AmazonProvidedDNS in another Region,
    specify region.compute.internal (for example, ap-northeast-1.compute.internal). Otherwise, specify a domain name
    (for example, ExampleCompany.com). This value is used to complete unqualified DNS hostnames. Important: Some
    Linux operating systems accept multiple domain names separated by spaces. However, Windows and other Linux
    operating systems treat the value as a single domain, which results in unexpected behavior. If your DHCP options
    set is associated with a VPC that has instances with multiple operating systems, specify only one domain name.
    ntp-servers - The IP addresses of up to four Network Time Protocol (NTP) servers.    netbios-name-servers - The
    IP addresses of up to four NetBIOS name servers.    netbios-node-type - The NetBIOS node type (1, 2, 4, or 8).
    We recommend that you specify 2 (broadcast and multicast are not currently supported). For more information
    about these node types, see RFC 2132.   Your VPC automatically starts out with a set of DHCP options that
    includes only a DNS server that we provide (AmazonProvidedDNS). If you create a set of options, and if your VPC
    has an internet gateway, make sure to set the domain-name-servers option either to AmazonProvidedDNS or to a
    domain name server of your choice. For more information, see DHCP options sets in the Amazon Virtual Private
    Cloud User Guide.

    Args:
        name(Text): An Idem name to identify the dhcp option resource.
        dhcp_configurations (List): A DHCP configuration option.
            * Key (str, optional): The name of a DHCP option. Options are domain-name-servers|domain-name|ntp-servers|netbios-name-servers|netbios-node-type
            * Values (List[str], optional): One or more values for the DHCP option.
                * Value (string): The attribute value. The value is case-sensitive.
        resource_id(Text, optional): AWS DHCP Option Set ID.
        tags(Dict or List, optional): Dict in the format of {tag-key: tag-value} or List of tags in the format of
            [{"Key": tag-key, "Value": tag-value}] to associate with the dhcp option resource. Defaults to None.
            * Key (string) --  The key of the tag. Tag keys are case-sensitive and accept a maximum of 127 Unicode characters. May not begin with aws: .
            * Value (string) -- The value of the tag. Tag values are case-sensitive and accept a maximum of 255 Unicode characters.
        vpc_id (List, optional): The list of AWS VPC ID that needs to be associated with dhcp options set.

    Request Syntax:
        [dhcp_option-name]:
          aws.ec2.dhcp_option.present:
          - resource_id: 'string'
          - dhcp_configurations:
              - Key: 'string'
                Values: List
                    - Value: 'string'
          - vpc_id: 'List'
          - tags:
              - Key: 'string'
                Value: 'string'

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            my-dhcp-option:
              aws.ec2.dhcp_option.present:
                - dhcp_configurations:
                    - Key: domain-name-servers
                      Values:
                            - Value : 10.2.5.1
                            - Value : 10.2.5.2
                - vpc_id:
                  - vpc-76db75b8
                - tags:
                    - Key: test_name
                      Value: test-dhcp
    """

    result = dict(comment=(), old_state=None, new_state=None, name=name, result=True)
    before = None
    resource_updated = False
    if resource_id:
        resource = hub.tool.boto3.resource.create(
            ctx, "ec2", "DhcpOptions", resource_id
        )
        before = await hub.tool.boto3.resource.describe(resource)

    if isinstance(tags, List):
        tags = hub.tool.aws.tag_utils.convert_tag_list_to_dict(tags)

    if before:
        convert_ret = (
            await hub.tool.aws.ec2.conversion_utils.convert_raw_dhcp_to_present(
                ctx, raw_resource=before, idem_resource_name=name
            )
        )
        result["result"] = convert_ret["result"]
        if not result["result"]:
            result["comment"] = result["comment"] + convert_ret["comment"]
        result["old_state"] = convert_ret["ret"]
        plan_state = copy.deepcopy(result["old_state"])
        result["comment"] = (f"aws.ec2.dhcp_option '{name}' already exists",)
        if vpc_id is not None:
            if not ctx.get("test", False):
                vpc_ret = await hub.exec.boto3.client.ec2.describe_vpcs(
                    ctx, VpcIds=vpc_id
                )
                if not vpc_ret["result"]:
                    result["comment"] = vpc_ret["comment"]
                    result["result"] = vpc_ret["result"]
                for vpc_associate in vpc_id:
                    for vpc_dhcp in vpc_ret["ret"]["Vpcs"]:
                        if (
                            vpc_ret["result"]
                            and vpc_dhcp["DhcpOptionsId"] != resource_id
                        ):
                            update_ret = (
                                await hub.exec.boto3.client.ec2.associate_dhcp_options(
                                    ctx,
                                    DhcpOptionsId=resource_id,
                                    VpcId=vpc_associate,
                                )
                            )
                            result["comment"] = update_ret["comment"]
                            result["result"] = update_ret["result"]
                            resource_updated = resource_updated or bool(
                                update_ret["ret"]
                            )
            else:
                plan_state["vpc_id"] = vpc_id

        # check if tags need to be updated
        if tags is not None and tags != result["old_state"].get("tags"):
            update_ret = await hub.exec.aws.ec2.tag.update_tags(
                ctx=ctx,
                resource_id=result["old_state"].get("resource_id"),
                old_tags=result["old_state"].get("tags"),
                new_tags=tags,
            )
            result["comment"] = result["comment"] + update_ret["comment"]
            result["result"] = result["result"] and update_ret["result"]
            resource_updated = resource_updated or bool(update_ret["result"])
            if ctx.get("test", False) and update_ret["result"]:
                plan_state["tags"] = update_ret["ret"]
    else:
        if ctx.get("test", False):
            result["new_state"] = hub.tool.aws.test_state_utils.generate_test_state(
                enforced_state={},
                desired_state={
                    "name": name,
                    "dhcp_configurations": dhcp_configurations,
                    "vpc_id": vpc_id,
                    "tags": tags,
                },
            )
            result["comment"] = hub.tool.aws.comment_utils.would_create_comment(
                resource_type="aws.ec2.dhcp_option", name=name
            )
            return result
        ret = await hub.exec.boto3.client.ec2.create_dhcp_options(
            ctx,
            DhcpConfigurations=dhcp_configurations,
            TagSpecifications=[
                {
                    "ResourceType": "dhcp-options",
                    "Tags": hub.tool.aws.tag_utils.convert_tag_dict_to_list(tags),
                }
            ]
            if tags is not None
            else None,
        )
        resource_id = ret["ret"]["DhcpOptions"]["DhcpOptionsId"]
        result["comment"] = hub.tool.aws.comment_utils.create_comment(
            resource_type="aws.ec2.dhcp_option", name=name
        )
        result["result"] = ret["result"]
        if not result["result"]:
            result["comment"] = ret["comment"]
            return result
        if result["result"] and vpc_id is not None:
            for vpc_associate in vpc_id:
                update_ret = await hub.exec.boto3.client.ec2.associate_dhcp_options(
                    ctx,
                    DhcpOptionsId=ret["ret"]["DhcpOptions"]["DhcpOptionsId"],
                    VpcId=vpc_associate,
                )
                result["comment"] = result["comment"] + update_ret["comment"]
                result["result"] = update_ret["result"]
                resource_updated = resource_updated or bool(update_ret["ret"])
                if not result["result"]:
                    result["comment"] = update_ret["comment"]
                    return result
    if ctx.get("test", False):
        result["new_state"] = plan_state
    elif (not before) or resource_updated:
        resource = hub.tool.boto3.resource.create(
            ctx, "ec2", "DhcpOptions", resource_id
        )
        after = await hub.tool.boto3.resource.describe(resource)
        convert_ret = (
            await hub.tool.aws.ec2.conversion_utils.convert_raw_dhcp_to_present(
                ctx, raw_resource=after, idem_resource_name=name
            )
        )
        result["result"] = convert_ret["result"]
        if not result["result"]:
            result["comment"] = result["comment"] + convert_ret["comment"]
            return result
        result["new_state"] = convert_ret["ret"]
    else:
        result["new_state"] = copy.deepcopy(result["old_state"])
    return result


async def absent(
    hub,
    ctx,
    name: str,
    resource_id: str = None,
) -> Dict[str, Any]:
    r"""
    **Autogenerated function**

    Deletes the specified set of DHCP options. You must disassociate the set of DHCP options before you can delete
    it. You can disassociate the set of DHCP options by associating either a new set of options or the default set
    of options with the VPC.

    Args:
        name(Text): An Idem name to identify the dhcp option resource.
        resource_id(Text, optional): AWS DHCP Option Set ID. Idem automatically considers this resource being
         absent if this field is not specified.

    Request Syntax:
        [dhcp_option-name]:
          aws.ec2.dhcp_option.absent:
          - name: 'string'
          - resource_id: 'string'

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            resource_is_absent:
              aws.ec2.dhcp_option.absent:
                - name: value
    """

    result = dict(comment=(), old_state=None, new_state=None, name=name, result=True)
    if not resource_id:
        result["comment"] = hub.tool.aws.comment_utils.already_absent_comment(
            resource_type="aws.ec2.dhcp_option", name=name
        )
        return result
    resource = hub.tool.boto3.resource.create(ctx, "ec2", "DhcpOptions", resource_id)
    before = await hub.tool.boto3.resource.describe(resource)
    if not before:
        result["comment"] = hub.tool.aws.comment_utils.already_absent_comment(
            resource_type="aws.ec2.dhcp_option", name=name
        )
        return result
    else:
        convert_ret = (
            await hub.tool.aws.ec2.conversion_utils.convert_raw_dhcp_to_present(
                ctx, raw_resource=before, idem_resource_name=name
            )
        )
        result["result"] = convert_ret["result"]
        if not result["result"]:
            result["comment"] = result["comment"] + convert_ret["comment"]
        result["old_state"] = convert_ret["ret"]
        if ctx.get("test", False):
            result["comment"] = hub.tool.aws.comment_utils.would_delete_comment(
                resource_type="aws.ec2.dhcp_option", name=name
            )
            return result
        ret = await hub.exec.boto3.client.ec2.delete_dhcp_options(
            ctx, DhcpOptionsId=resource_id
        )
        result["result"] = ret["result"]
        if not result["result"]:
            result["comment"] = ret["comment"]
            return result
        result["comment"] = hub.tool.aws.comment_utils.delete_comment(
            resource_type="aws.ec2.dhcp_option", name=name
        )
    return result


async def describe(hub, ctx) -> Dict[str, Dict[str, Any]]:
    r"""
    **Autogenerated function**

    Describe the resource in a way that can be recreated/managed with the corresponding "present" function


    Describes one or more of your DHCP options sets. For more information, see DHCP options sets in the Amazon
    Virtual Private Cloud User Guide.


    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: bash

            $ idem describe aws.ec2.dhcp_option
    """

    result = {}
    ret = await hub.exec.boto3.client.ec2.describe_dhcp_options(ctx)

    if not ret["result"]:
        hub.log.debug(f"Could not describe dhcp_options {ret['comment']}")
        return result

    for resource in ret["ret"]["DhcpOptions"]:
        resource_id = resource.get("DhcpOptionsId")
        convert_ret = (
            await hub.tool.aws.ec2.conversion_utils.convert_raw_dhcp_to_present(
                ctx, raw_resource=resource, idem_resource_name=resource_id
            )
        )
        if not convert_ret["result"]:
            hub.log.warning(
                f"Could not describe dhcp options '{resource_id}' with error {convert_ret['comment']}"
            )
            continue
        translated_resource = convert_ret["ret"]
        result[translated_resource["resource_id"]] = {
            "aws.ec2.dhcp_option.present": [
                {parameter_key: parameter_value}
                for parameter_key, parameter_value in translated_resource.items()
            ]
        }
    return result
