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

hub.exec.boto3.client.ec2.create_placement_group
hub.exec.boto3.client.ec2.delete_placement_group
hub.exec.boto3.client.ec2.describe_placement_groups
resource = hub.tool.boto3.resource.create(ctx, "ec2", "PlacementGroup", resource_id)
hub.tool.boto3.resource.exec(resource, delete, *args, **kwargs)
"""
import copy
from typing import Any
from typing import Dict

__contracts__ = ["resource"]


async def present(
    hub,
    ctx,
    name: str,
    resource_id: str = None,
    strategy: str = None,
    partition_count: int = None,
    tags: Dict[str, str] = None,
    spread_level: str = None,
) -> Dict[str, Any]:
    r"""
    **Autogenerated function**

    Creates a placement group in which to launch instances. The strategy of the placement group determines how the
    instances are organized within the group.  A cluster placement group is a logical grouping of instances within a
    single Availability Zone that benefit from low network latency, high network throughput. A spread placement
    group places instances on distinct hardware. A partition placement group places groups of instances in different
    partitions, where instances in one partition do not share the same hardware with instances in another partition.
    For more information, see Placement groups in the Amazon EC2 User Guide.

    Args:
        name(Text): An Idem name of the resource and the GroupName of the placement group.
        resource_id(Text, optional): The GroupId of the placement group
        strategy(Text, optional): The placement strategy. Defaults to None.
        partition_count(int, optional): The number of partitions. Valid only when Strategy is set to partition. Defaults to None.
        tags(Dict[str, str], optional): The tags to apply to the resource. Defaults to None.
            * Key (str, optional): The key of the tag. Constraints: Tag keys are case-sensitive and accept a maximum of 127 Unicode
            characters. May not begin with aws:.
            * Value (str, optional): The value of the tag. Constraints: Tag values are case-sensitive and accept a maximum of 256
            Unicode characters.
        spread_level(str, optional): Determines how placement groups spread instances.    Host – You can use host only with Outpost
            placement groups.   Rack – No usage restrictions. Defaults to None.

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            resource_is_present:
              aws.ec2.placement_group.present:
                - name: value
    """

    result = dict(comment=(), old_state=None, new_state=None, name=name, result=True)
    before = None
    resource_updated = False

    if resource_id:
        before = await hub.exec.aws.ec2.placement_group.get(
            ctx, name=name, resource_id=resource_id
        )
        if not before["result"] or not before["ret"]:
            result["result"] = False
            result["comment"] = before["comment"]
            return result

        result["old_state"] = copy.deepcopy(before["ret"])
        plan_state = copy.deepcopy(result["old_state"])
        old_tags = result["old_state"].get("tags")

        if tags is not None and tags != old_tags:
            group_id = before["ret"]["group_id"]
            update_ret = await hub.exec.aws.ec2.tag.update_tags(
                ctx,
                resource_id=group_id,
                old_tags=old_tags,
                new_tags=tags,
            )

            result["comment"] += list(update_ret["comment"])
            result["result"] = update_ret["result"]

            resource_updated = resource_updated or bool(update_ret["ret"])
            if ctx.get("test", False) and update_ret["ret"]:
                plan_state["tags"] = update_ret["ret"]

            if not update_ret["result"]:
                return result

        if ctx.get("test", False) and resource_updated:
            plan_state["tags"] = update_ret["ret"]

            result["new_state"] = plan_state
            result["comment"] += hub.tool.aws.comment_utils.would_update_comment(
                "aws.ec2.placement_group", name
            )
            return result
        if not resource_updated:
            result["comment"] = hub.tool.aws.comment_utils.already_exists_comment(
                "aws.ec2.placement_group", name
            )
    else:
        if ctx.get("test", False):
            result["comment"] = hub.tool.aws.comment_utils.would_create_comment(
                resource_type="aws.ec2.placement_group", name=name
            )
            result["new_state"] = hub.tool.aws.test_state_utils.generate_test_state(
                enforced_state={},
                desired_state={
                    "name": name,
                    "resource_id": None,
                    "group_name": name,
                    "strategy": strategy,
                    "partition_count": partition_count,
                    "spread_level": spread_level,
                    "tags": tags,
                },
            )
            return result

        boto_tags = hub.tool.aws.tag_utils.convert_tag_dict_to_list(tags)
        boto_tag_specification = [
            {"ResourceType": "placement-group", "Tags": boto_tags}
        ]
        ret = await hub.exec.boto3.client.ec2.create_placement_group(
            ctx,
            **{
                "GroupName": name,
                "Strategy": strategy,
                "PartitionCount": partition_count,
                "TagSpecifications": boto_tag_specification,
                "SpreadLevel": spread_level,
            },
        )

        result["result"] = ret["result"]
        if not result["result"]:
            result["comment"] = ret["comment"]
            return result
        result["comment"] = hub.tool.aws.comment_utils.create_comment(
            resource_type="aws.ec2.placement_group", name=name
        )

    if ctx.get("test", False):
        result["new_state"] = plan_state
    elif (not before) or resource_updated:
        after = await hub.exec.aws.ec2.placement_group.get(
            ctx, name=name, resource_id=resource_id
        )
        if not after["result"]:
            result["comment"] = after["comment"]
            result["result"] = after["result"]
            return result
        result["new_state"] = copy.deepcopy(after["ret"])
    else:
        result["new_state"] = copy.deepcopy(result["old_state"])

    return result


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

    Deletes the specified placement group. You must terminate all instances in the placement group before you can
    delete the placement group. For more information, see Placement groups in the Amazon EC2 User Guide.

    Args:
        name(Text): An Idem name of the resource and the GroupName of the placement group
        resource_id(Text): The GroupName of the placement group. Idem automatically considers this resource being absent if this field is not specified.

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            resource_is_absent:
              aws.ec2.placement_group.absent:
                - name: value
                - resource_id: 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.placement_group", name=name
        )
        return result

    before = await hub.exec.aws.ec2.placement_group.get(
        ctx, name=name, resource_id=resource_id
    )

    if not before["result"]:
        result["comment"] = before["comment"]
        result["result"] = False
        return result

    if not before["ret"]:
        result["comment"] = hub.tool.aws.comment_utils.already_absent_comment(
            resource_type="aws.ec2.placement_group", name=name
        )
    elif ctx.get("test", False):
        result["old_state"] = copy.deepcopy(before["ret"])
        result["comment"] = hub.tool.aws.comment_utils.would_delete_comment(
            resource_type="aws.ec2.placement_group", name=name
        )
        return result
    else:
        result["old_state"] = copy.deepcopy(before["ret"])
        ret = await hub.exec.boto3.client.ec2.delete_placement_group(
            ctx, **{"GroupName": 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.placement_group", 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

    Args:

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: bash

            $ idem describe aws.ec2.placement_group
    """

    result = {}
    ret = await hub.exec.aws.ec2.placement_group.list(ctx, name=None, filters=None)

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

    for placement_group in ret["ret"]:
        resource_id = placement_group.get("group_name", None)
        if resource_id:
            result[resource_id] = {
                "aws.ec2.placement_group.present": [
                    {parameter_key: parameter_value}
                    for parameter_key, parameter_value in placement_group.items()
                ]
            }

    return result
