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

hub.exec.boto3.client.ec2.create_vpc
hub.exec.boto3.client.ec2.delete_vpc
hub.exec.boto3.client.ec2.describe_vpcs
resource = hub.tool.boto3.resource.create(ctx, "ec2", "Vpc", name)
hub.tool.boto3.resource.exec(resource, associate_dhcp_options, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, attach_classic_link_instance, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, attach_internet_gateway, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, create_network_acl, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, create_route_table, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, create_security_group, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, create_subnet, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, create_tags, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, delete, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, describe_attribute, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, detach_classic_link_instance, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, detach_internet_gateway, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, disable_classic_link, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, enable_classic_link, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, modify_attribute, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, request_vpc_peering_connection, *args, **kwargs)
"""
import copy
from typing import Any
from typing import Dict
from typing import List

import dict_tools.differ as differ

__contracts__ = ["resource"]


async def present(
    hub,
    ctx,
    name: str,
    cidr_block: str,
    amazon_provided_ipv6_cidr_block: bool = None,
    ipv6_pool: str = None,
    ipv6_cidr_block: str = None,
    instance_tenancy: str = None,
    ipv6_cidr_block_network_border_group: str = None,
    tag_specifications: List = None,
) -> Dict[str, Any]:
    r"""
    **Autogenerated function**

    Creates a VPC with the specified IPv4 CIDR block. The smallest VPC you can create uses a /28 netmask (16 IPv4
    addresses), and the largest uses a /16 netmask (65,536 IPv4 addresses). For more information about how large to
    make your VPC, see Your VPC and subnets in the Amazon Virtual Private Cloud User Guide. You can optionally
    request an IPv6 CIDR block for the VPC. You can request an Amazon-provided IPv6 CIDR block from Amazon's pool of
    IPv6 addresses, or an IPv6 CIDR block from an IPv6 address pool that you provisioned through bring your own IP
    addresses (BYOIP). By default, each instance you launch in the VPC has the default DHCP options, which include
    only a default DNS server that we provide (AmazonProvidedDNS). For more information, see DHCP options sets in
    the Amazon Virtual Private Cloud User Guide. You can specify the instance tenancy value for the VPC when you
    create it. You can't change this value for the VPC after you create it. For more information, see Dedicated
    Instances in the Amazon Elastic Compute Cloud User Guide.

    Args:
        name(Text): A name, ID, or JMES search path to identify the resource.
        cidr_block(Text): The IPv4 network range for the VPC, in CIDR notation. For example, 10.0.0.0/16. We modify the
            specified CIDR block to its canonical form; for example, if you specify 100.68.0.18/18, we
            modify it to 100.68.0.0/18.
        amazon_provided_ipv6_cidr_block(bool, optional): Requests an Amazon-provided IPv6 CIDR block with a /56 prefix length for the VPC. You cannot
            specify the range of IP addresses, or the size of the CIDR block. Defaults to None.
        ipv6_pool(Text, optional): The ID of an IPv6 address pool from which to allocate the IPv6 CIDR block. Defaults to None.
        ipv6_cidr_block(Text, optional): The IPv6 CIDR block from the IPv6 address pool. You must also specify Ipv6Pool in the request.
            To let Amazon choose the IPv6 CIDR block for you, omit this parameter. Defaults to None.
        instance_tenancy(Text, optional): The tenancy options for instances launched into the VPC. For default, instances are launched
            with shared tenancy by default. You can launch instances with any tenancy into a shared tenancy
            VPC. For dedicated, instances are launched as dedicated tenancy instances by default. You can
            only launch instances with a tenancy of dedicated or host into a dedicated tenancy VPC.
            Important: The host value cannot be used with this parameter. Use the default or dedicated
            values only. Default: default. Defaults to None.
        ipv6_cidr_block_network_border_group(Text, optional): The name of the location from which we advertise the IPV6 CIDR block. Use this parameter to
            limit the address to this location.  You must set AmazonProvidedIpv6CidrBlock to true to use
            this parameter. Defaults to None.
        tag_specifications(List, optional): The tags to assign to the VPC. Defaults to None.

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            resource_is_present:
              aws_auto.ec2.vpc.present:
                - name: value
                - cidr_block: value
    """
    result = dict(comment="", changes=None, name=name, result=True)
    ret = await hub.exec.boto3.client.ec2.vpc.search(ctx, jmes_path=name)
    if ret["result"]:
        # name is now the first id that matched the JMES search path
        name = ret["ret"]

    resource = hub.tool.boto3.resource.create(ctx, "ec2", "Vpc", name)
    before = await hub.tool.boto3.resource.describe(resource)

    if before:
        result["comment"] = f"'{name}' already exists"
    else:
        try:
            ret = await hub.exec.boto3.client.ec2.create_vpc(
                ctx,
                DryRun=ctx.test,
                **{
                    "CidrBlock": cidr_block,
                    "AmazonProvidedIpv6CidrBlock": amazon_provided_ipv6_cidr_block,
                    "Ipv6Pool": ipv6_pool,
                    "Ipv6CidrBlock": ipv6_cidr_block,
                    "InstanceTenancy": instance_tenancy,
                    "Ipv6CidrBlockNetworkBorderGroup": ipv6_cidr_block_network_border_group,
                    "TagSpecifications": tag_specifications,
                },
            )
            result["result"] = ret["result"]
            if not result["result"]:
                result["comment"] = ret["comment"]
                return result
            ret["comment"] = f"Created '{name}'"

            if ret["result"]:
                resource._id = ret["ret"]["Vpc"]["VpcId"]
        except hub.tool.boto3.exception.ClientError as e:
            result["comment"] = f"{e.__class__.__name__}: {e}"

    # TODO perform other modifications as needed here
    ...

    try:
        after = await hub.tool.boto3.resource.describe(resource)
        result["changes"] = differ.deep_diff(before, after)
    except Exception as e:
        result["comment"] = str(e)
        result["result"] = False
    return result


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

    Deletes the specified VPC. You must detach or delete all gateways and resources that are associated with the VPC
    before you can delete it. For example, you must terminate all instances running in the VPC, delete all security
    groups associated with the VPC (except the default one), delete all route tables associated with the VPC (except
    the default one), and so on.

    Args:
        name(Text): The ID of the VPC or a name, ID, or JMES search path to identify the resource.

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            resource_is_absent:
              aws_auto.ec2.vpc.absent:
                - name: value
                - vpc_id: value
    """

    result = dict(comment="", changes=None, name=name, result=True)
    ret = await hub.exec.boto3.client.ec2.vpc.search(ctx, jmes_path=name)
    if ret["result"]:
        # name is now the first id that matched the JMES search path
        name = ret["ret"]

    resource = hub.tool.boto3.resource.create(ctx, "ec2", "Vpc", name)

    before = await hub.tool.boto3.resource.describe(resource)

    if not before:
        result["comment"] = f"'{name}' already absent"
    else:
        try:
            ret = await hub.exec.boto3.client.ec2.delete_vpc(
                ctx, DryRun=ctx.test, **{"VpcId": name}
            )
            result["result"] = ret["result"]
            if not result["result"]:
                result["comment"] = ret["comment"]
                return result
            result["comment"] = f"Deleted '{name}'"
        except hub.tool.boto3.exception.ClientError as e:
            result["comment"] = f"{e.__class__.__name__}: {e}"

    try:
        after = await hub.tool.boto3.resource.describe(resource)
        result["changes"] = differ.deep_diff(before, after)
    except Exception as e:
        result["comment"] = str(e)
        result["result"] = False
    return result


async def describe(hub, ctx) -> Dict[str, Dict[str, Any]]:
    result = {}
    ret = await hub.exec.boto3.client.ec2.describe_vpcs(ctx)

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

    for vpc in ret["ret"]["Vpcs"]:
        new_vpc = [
            {"cidr_block": vpc["CidrBlock"]},
            {
                "amazon_provided_ipv6_cidr_block": bool(
                    vpc["Ipv6CidrBlockAssociationSet"]
                )
            },
            {"instance_tenancy": vpc["InstanceTenancy"]},
            {"tag_specifications": vpc["Tags"]},
        ]
        result[vpc["VpcId"]] = {"aws.ec2.vpc.present": new_vpc}
        for i, data in enumerate(vpc["Ipv6CidrBlockAssociationSet"]):
            sub_vpc = copy.deepcopy(new_vpc)
            sub_vpc.append({"ipv6_cidr_block": data["Ipv6CidrBlock"]})
            sub_vpc.append(
                {"ipv6_cidr_block_network_border_group": data["NetworkBorderGroup"]}
            )
            sub_vpc.append({"ipv6_pool": data["Ipv6Pool"]})
            # The id needs to be in the name
            sub_vpc.append({"name": vpc["VpcId"]})
            # Create a new state for this association set
            result[f"{vpc['VpcId']}-{i}"] = {"aws.ec2.vpc.present": sub_vpc}
    return result
