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

hub.exec.boto3.client.elasticache.create_cache_subnet_group
hub.exec.boto3.client.elasticache.delete_cache_subnet_group
hub.exec.boto3.client.elasticache.describe_cache_subnet_groups
hub.exec.boto3.client.elasticache.modify_cache_subnet_group
"""
import copy
from typing import Any
from typing import Dict
from typing import List


__contracts__ = ["resource"]
TREQ = {
    "present": {
        "require": [
            "aws.ec2.subnet.present",
        ],
    },
}


async def present(
    hub,
    ctx,
    name: str,
    subnet_ids: List,
    cache_subnet_group_description: str,
    resource_id: str = None,
    tags: List[Dict[str, Any]] or Dict[str, Any] = None,
) -> Dict[str, Any]:
    r"""
    **Autogenerated function**

    Creates a new cache subnet group. Use cache subnet group parameter only when you are creating a cluster in an Amazon Virtual
    Private Cloud (Amazon VPC).

    Args:
        name(Text): An Idem name of the resource.
        cache_subnet_group_description(Text): Description of the cache subnet group
        subnet_ids(list): A list of VPC subnet IDs for the cache subnet group.
        resource_id(Text, optional): AWS Elasticache subnet group name to identify the resource
        tags(List or Dict, optional): list of tags in the format of [{"Key": tag-key, "Value": tag-value}] or dict in the format of
                {tag-key: tag-value} The tags to assign to the cache_subnet_group. Defaults to None.

    Request Syntax:
        [cache_subnet_group_name]:
          aws.elasticache.cache_subnet_group.present:
          - name: 'string'
          - cache_subnet_group_description: 'string'
          - subnet_ids: 'List'
          - tags:
            - Key: 'string'
              Value: 'string'

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            cache_subnet_group_name:
              aws.elasticache.cache_subnet_group.present:
                - cache_subnet_group_description: "testing demo"
                - subnet_ids:
                    - subnet-239e4b44
                - tags:
                    - Key: Name
                      Value: test-elasticache
    """

    result = dict(comment=(), name=name, old_state=None, new_state=None, result=True)
    before = None
    resource_updated = False
    are_tags_updated = False
    resource_arn = str
    if resource_id:
        before = await hub.exec.boto3.client.elasticache.describe_cache_subnet_groups(
            ctx, CacheSubnetGroupName=resource_id
        )
    if isinstance(tags, List):
        tags = hub.tool.aws.tag_utils.convert_tag_list_to_dict(tags)

    try:
        if before and before["result"] and before["ret"]["CacheSubnetGroups"]:
            convert_ret = await hub.tool.aws.elasticache.conversion_utils.convert_raw_elasticache_subnet_to_present(
                ctx=ctx,
                raw_resource=before["ret"]["CacheSubnetGroups"][0],
                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"])
            if cache_subnet_group_description != result["old_state"].get(
                "cache_subnet_group_description"
            ) or not hub.tool.aws.state_comparison_utils.are_lists_identical(
                subnet_ids, result["old_state"].get("subnet_ids")
            ):
                if not ctx.get("test", False):
                    update_ret = await hub.exec.boto3.client.elasticache.modify_cache_subnet_group(
                        ctx=ctx,
                        CacheSubnetGroupName=name,
                        CacheSubnetGroupDescription=cache_subnet_group_description,
                        SubnetIds=subnet_ids,
                    )
                    result["comment"] = result["comment"] + update_ret["comment"]
                    result["result"] = update_ret["result"]
                    resource_updated = resource_updated or bool(update_ret["ret"])
                else:
                    if cache_subnet_group_description is not None:
                        plan_state[
                            "cache_subnet_group_description"
                        ] = cache_subnet_group_description
                    if subnet_ids is not None:
                        plan_state["subnet_ids"] = subnet_ids
            resource_arn = before["ret"]["CacheSubnetGroups"][0]["ARN"]
            if tags is not None and tags != result["old_state"].get("tags"):
                # Update tags
                update_ret = await hub.exec.aws.elasticache.tag.update_tags(
                    ctx=ctx,
                    resource_arn=resource_arn,
                    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"]
                are_tags_updated = bool(update_ret["result"])
                resource_updated = resource_updated or are_tags_updated
                if ctx.get("test", False) and are_tags_updated:
                    plan_state["tags"] = update_ret["ret"]
                    result["comment"] = result["comment"] + (
                        f"Would update tags for aws.elasticache.cache_subnet_group {name}",
                    )
        else:
            if ctx.get("test", False):
                result["new_state"] = hub.tool.aws.test_state_utils.generate_test_state(
                    enforced_state={},
                    desired_state={
                        "name": name,
                        "cache_subnet_group_description:": cache_subnet_group_description,
                        "subnet_ids": subnet_ids,
                        "tags": tags,
                    },
                )
                result["comment"] = hub.tool.aws.comment_utils.would_create_comment(
                    resource_type="aws.elasticache.cache_subnet_group", name=name
                )
                return result

            ret = await hub.exec.boto3.client.elasticache.create_cache_subnet_group(
                ctx,
                CacheSubnetGroupName=name,
                CacheSubnetGroupDescription=cache_subnet_group_description,
                SubnetIds=subnet_ids,
                Tags=hub.tool.aws.tag_utils.convert_tag_dict_to_list(tags)
                if tags
                else None,
            )
            resource_id = name
            result["result"] = ret["result"]
            if not result["result"]:
                result["comment"] = ret["comment"]
                return result
            resource_arn = ret["ret"]["CacheSubnetGroup"]["ARN"]
            result["comment"] = hub.tool.aws.comment_utils.create_comment(
                resource_type="aws.elasticache.cache_subnet_group", name=name
            )
    except hub.tool.boto3.exception.ClientError as e:
        result["result"] = False
        result["comment"] = result["comment"] + (f"{e.__class__.__name__}: {e}",)
    try:
        if ctx.get("test", False):
            result["new_state"] = plan_state
        elif (not before) or resource_updated:
            after = (
                await hub.exec.boto3.client.elasticache.describe_cache_subnet_groups(
                    ctx, CacheSubnetGroupName=resource_id
                )
            )
            if after and after.get("ret"):
                convert_ret = await hub.tool.aws.elasticache.conversion_utils.convert_raw_elasticache_subnet_to_present(
                    ctx=ctx,
                    raw_resource=after["ret"]["CacheSubnetGroups"][0],
                    idem_resource_name=name,
                )
                result["result"] = convert_ret["result"]
                if not result["result"]:
                    result["comment"] = result["comment"] + convert_ret["comment"]
                result["new_state"] = convert_ret.get("ret")
            else:
                result["result"] = result["result"] and after["result"]
                if not result["result"]:
                    result["comment"] = result["comment"] + after["comment"]
                    return result
        else:
            result["new_state"] = copy.deepcopy(result["old_state"])
    except Exception as e:
        result["comment"] = result["comment"] + (str(e),)
        result["result"] = False
    return result


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

    Deletes a cache subnet group.  You cannot delete a default cache subnet group or one that is associated with any
    clusters.

    Args:
        name(Text): An Idem name of the resource.
        resource_id(Text, optional): AWS Elasticache subnet group name to identify the resource.

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            resource_is_absent:
              aws.elasticache.cache_subnet_group.absent:
                - name: value
    """

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

    if not resource_id:
        result["comment"] = hub.tool.aws.comment_utils.already_absent_comment(
            resource_type="aws.elasticache.cache_subnet_group", name=name
        )
        return result

    before = await hub.exec.boto3.client.elasticache.describe_cache_subnet_groups(
        ctx, CacheSubnetGroupName=resource_id
    )
    if not before or not before["result"] or not before["ret"].get("CacheSubnetGroups"):
        result["comment"] = hub.tool.aws.comment_utils.already_absent_comment(
            resource_type="aws.elasticache.cache_subnet_group", name=name
        )
        return result
    else:
        convert_ret = await hub.tool.aws.elasticache.conversion_utils.convert_raw_elasticache_subnet_to_present(
            ctx=ctx,
            raw_resource=before["ret"]["CacheSubnetGroups"][0],
            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.elasticache.cache_subnet_group", name=name
            )
            return result
        try:
            ret = await hub.exec.boto3.client.elasticache.delete_cache_subnet_group(
                ctx, CacheSubnetGroupName=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.elasticache.cache_subnet_group", name=name
            )
        except hub.tool.boto3.exception.ClientError as e:
            result["comment"] = 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


    Returns a list of cache subnet group descriptions. If a subnet group name is specified, the list contains only
    the description of that group. This is applicable only when you have ElastiCache in VPC setup. All ElastiCache
    clusters now launch in VPC by default.


    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: bash

            $ idem describe aws.elasticache.cache_subnet_group
    """

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

    for resource in ret["ret"]["CacheSubnetGroups"]:
        resource_id = resource.get("CacheSubnetGroupName")
        convert_ret = await hub.tool.aws.elasticache.conversion_utils.convert_raw_elasticache_subnet_to_present(
            ctx=ctx,
            raw_resource=resource,
            idem_resource_name=resource_id,
        )
        if not convert_ret["result"]:
            hub.log.warning(
                f"Could not describe elasticache subnet group '{resource_id}' with error {convert_ret['comment']}"
            )
            continue
        resource_translated = convert_ret.get("ret")
        result[resource_id] = {
            "aws.elasticache.cache_subnet_group.present": [
                {parameter_key: parameter_value}
                for parameter_key, parameter_value in resource_translated.items()
            ]
        }
    return result
