"""

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

hub.exec.boto3.client.ec2.create_security_group
hub.exec.boto3.client.ec2.delete_security_group
hub.exec.boto3.client.ec2.describe_security_groups
hub.tool.boto3.resource.exec(resource, authorize_egress, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, authorize_ingress, *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, revoke_egress, *args, **kwargs)
hub.tool.boto3.resource.exec(resource, revoke_ingress, *args, **kwargs)
"""
from collections import OrderedDict
from typing import Any
from typing import Dict

__contracts__ = ["resource"]

TREQ = {
    "present": {"require": ["aws.ec2.vpc.present"]},
}


async def present(
    hub,
    ctx,
    name: str,
    description: str,
    vpc_id: str,
    sg_rules: list,
    tags: Dict[str, str] = None,
) -> Dict[str, Any]:
    r"""
    **Autogenerated function**

    Creates a security group. A security group acts as a virtual firewall for your instance to control inbound and
    outbound traffic. For more information, see Amazon EC2 security groups in the Amazon Elastic Compute Cloud User
    Guide and Security groups for your VPC in the Amazon Virtual Private Cloud User Guide. When you create a
    security group, you specify a friendly name of your choice. You can have a security group for use in EC2-Classic
    with the same name as a security group for use in a VPC. However, you can't have two security groups for use in
    EC2-Classic with the same name or two security groups for use in a VPC with the same name. You have a default
    security group for use in EC2-Classic and a default security group for use in your VPC. If you don't specify a
    security group when you launch an instance, the instance is launched into the appropriate default security
    group. A default security group includes a default rule that grants instances unrestricted network access to
    each other. You can add or remove rules from your security groups using AuthorizeSecurityGroupIngress,
    AuthorizeSecurityGroupEgress, RevokeSecurityGroupIngress, and RevokeSecurityGroupEgress. For more information
    about VPC security group limits, see Amazon VPC Limits.

    Args:
        hub:
        ctx:
        name(str): A name or ID to identify the resource.
        description(str): Description of the security group
        vpc_id(str): Id of the VPC security group should be attached to
        sg_rules(list): Security Group rules to be applied on security group
        tags(Dict, Optional): List of Name, Value pair to tag security group

    Request Syntax:
        [security_group_id]:
          aws.ec2.security_group.present:
          - sg_rules:
            - CidrIpv4: 'string'
              FromPort: 'int'
              IpProtocol: 'string'
              IsEgress: boolean
              Tags:
                - Key: 'string'
                  Value: 'string'
              ToPort: 'int'
          - name: 'string'
          - vpc_id: 'string'

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            sg-0008bd25b7867b5cf:
              aws.ec2.security_group.present:
                  - name: isolation-securitygroup-84c9a893-844b-40ab-86e8-b565dea88b5d
                  - vpc_id: vpc-247e9a5d
                  - description: isolation-securitygroup-84c9a893-844b-40ab-86e8-b565dea88b5d
                  - sg_rules:
                    - CidrIpv4: 0.0.0.0/0
    """

    result = dict(comment="", old_state=None, new_state=None, name=name, result=True)
    created_sg_id = name
    resource = hub.tool.boto3.resource.create(ctx, "ec2", "SecurityGroup", name)
    before = await hub.tool.boto3.resource.describe(resource)
    if ctx.get("test", False):
        if before:
            result["comment"] = f"Would update aws.ec2.security_group {name}"
            result["result"] = True
        else:
            result["comment"] = f"Would create aws.ec2.security_group {name}"
            result["result"] = True
        return result
    if before:
        result["old_state"] = before
        update_ret = await hub.exec.aws.ec2.security_group.update_rules_in_sg(
            ctx, created_sg_id, sg_rules, resource
        )
        if not update_ret["result"]:
            result["comment"] = update_ret["comment"]
            result["result"] = False
    else:
        try:
            ret = await hub.exec.boto3.client.ec2.create_security_group(
                ctx,
                GroupName=name,
                Description=description,
                VpcId=vpc_id,
                TagSpecifications=[{"ResourceType": "security-group", "Tags": tags}]
                if tags is not None
                else None,
            )
            result["result"] = ret["result"]
            if not result["result"]:
                result["comment"] = ret["comment"]
                return result
            result["comment"] = f"Created '{name}'"
            created_sg_id = ret["ret"]["GroupId"]
            resource._id = created_sg_id

        except hub.tool.boto3.exception.ClientError as e:
            result["comment"] = f"{e.__class__.__name__}: {e}"

        if sg_rules is not None:
            new_rules_dict = hub.tool.aws.security_group_utils.convert_sg_rules_to_ingress_and_egress(
                sg_rules
            )
            if new_rules_dict["ingress"]:
                new_ingress_rules = hub.tool.aws.security_group_utils.remove_unwanted_attributes_from_rule(
                    new_rules_dict["ingress"]
                )
                [rule.pop("SecurityGroupRuleId", None) for rule in new_ingress_rules]
                ingress_result = (
                    await hub.exec.boto3.client.ec2.authorize_security_group_ingress(
                        ctx,
                        GroupId=created_sg_id,
                        IpPermissions=new_ingress_rules,
                    )
                )
                if not ingress_result["result"]:
                    result["comment"] = ingress_result["comment"]
                    result["result"] = False
            if new_rules_dict["egress"]:
                new_egress_rules = hub.tool.aws.security_group_utils.remove_unwanted_attributes_from_rule(
                    new_rules_dict["egress"]
                )
                [rule.pop("SecurityGroupRuleId", None) for rule in new_egress_rules]
                egress_result = (
                    await hub.exec.boto3.client.ec2.authorize_security_group_egress(
                        ctx,
                        GroupId=created_sg_id,
                        IpPermissions=new_egress_rules,
                    )
                )
                if not egress_result["result"]:
                    result["comment"] = egress_result["comment"]
                    result["result"] = False
    try:
        after = await hub.tool.boto3.resource.describe(resource)
        result["new_state"] = after
    except Exception as e:
        result["comment"] = str(e)
        result["result"] = False
    return result


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

    Deletes a security group. If you attempt to delete a security group that is associated with an instance, or is
    referenced by another security group, the operation fails with InvalidGroup.InUse in EC2-Classic or
    DependencyViolation in EC2-VPC.

    Args:
        hub:
        ctx:
        name(Text): A name, ID to identify the resource.

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            resource_is_absent:
              aws.ec2.security_group.absent:
                - name: value
    """
    result = dict(comment="", old_state=None, new_state=None, name=name, result=True)
    resource = hub.tool.boto3.resource.create(ctx, "ec2", "SecurityGroup", name)
    before = await hub.tool.boto3.resource.describe(resource)

    if not before:
        result["comment"] = f"'{name}' is already in deleted state."
    elif ctx.get("test", False):
        result["comment"] = f"Would delete aws.ec2.security_group {name}"
        return result
    else:
        result["old_state"] = before
        try:
            ret = await hub.exec.boto3.client.ec2.delete_security_group(
                ctx, GroupId=name
            )
            result["result"] = ret["result"]
            if not result["result"]:
                result["comment"] = f"'{name}' is already in deleted state."
                return result
            result["comment"] = f"Deleted '{name}'"
        except hub.tool.boto3.exception.ClientError as e:
            result["result"] = False
            result["comment"] = f"{e.__class__.__name__}: {e}"

    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 the specified security groups or all of your security groups. A security group is for use with
    instances either in the EC2-Classic platform or in a specific VPC. For more information, see Amazon EC2 security
    groups in the Amazon Elastic Compute Cloud User Guide and Security groups for your VPC in the Amazon Virtual
    Private Cloud User Guide.


    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: bash

            $ idem describe aws.ec2.security_group
    """
    result = {}

    ret = await hub.exec.boto3.client.ec2.describe_security_groups(ctx)
    if not ret["result"]:
        hub.log.debug(f"Could not describe security_group {ret['comment']}")
        result["comment"] = ret["comment"]
        result["result"] = False
        return result

    describe_parameters = OrderedDict(
        {
            "VpcId": "vpc_id",
            "Tags": "tags",
            "Description": "description",
        }
    )
    for security_group in ret["ret"]["SecurityGroups"]:
        translated_security_group = []
        security_group_id = security_group.get("GroupId")
        translated_security_group.append({"name": security_group_id})
        for parameter_old_key, parameter_new_key in describe_parameters.items():
            if security_group.get(parameter_old_key) is not None:
                translated_security_group.append(
                    {parameter_new_key: security_group.get(parameter_old_key)}
                )
        describe_sg_rules = (
            await hub.exec.boto3.client.ec2.describe_security_group_rules(
                ctx, Filters=[{"Name": "group-id", "Values": [security_group_id]}]
            )
        )
        if describe_sg_rules and describe_sg_rules["result"]:
            translated_security_group.append(
                {"sg_rules": describe_sg_rules["ret"].get("SecurityGroupRules")}
            )

        result[security_group_id] = {
            "aws.ec2.security_group.present": translated_security_group
        }
    return result
