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

hub.exec.boto3.client.eks.create_addon
hub.exec.boto3.client.eks.delete_addon
hub.exec.boto3.client.eks.describe_addon
hub.exec.boto3.client.eks.list_addons
hub.exec.boto3.client.eks.update_addon
"""
import copy
from dataclasses import field
from dataclasses import make_dataclass
from typing import Any
from typing import Dict

__contracts__ = ["resource"]

TREQ = {
    "absent": {
        "require": [
            "aws.ec2.subnet.absent",
            "aws.iam.role.absent",
            "aws.iam.role_policy_attachment.absent",
            "aws.eks.cluster.absent",
        ],
    },
    "present": {
        "require": [
            "aws.ec2.subnet.present",
            "aws.iam.role.present",
            "aws.iam.role_policy_attachment.present",
            "aws.eks.cluster.present",
        ],
    },
}


async def present(
    hub,
    ctx,
    name: str,
    cluster_name: str,
    addon_version: str,
    resource_id: str = None,
    service_account_role_arn: str = None,
    resolve_conflicts: str = "OVERWRITE",
    tags: Dict[str, str] = None,
    timeout: make_dataclass(
        "Timeout",
        [
            (
                "create",
                make_dataclass(
                    "CreateTimeout",
                    [
                        ("delay", int, field(default=10)),
                        ("max_attempts", int, field(default=60)),
                    ],
                ),
                field(default=None),
            ),
            (
                "update",
                make_dataclass(
                    "UpdateTimeout",
                    [
                        ("delay", int, field(default=10)),
                        ("max_attempts", int, field(default=60)),
                    ],
                ),
                field(default=None),
            ),
        ],
    ) = None,
) -> Dict[str, Any]:
    """
    **Autogenerated function**

    Creates an Amazon EKS add-on. Amazon EKS add-ons help to automate the provisioning and lifecycle management of
    common operational software for Amazon EKS clusters. Amazon EKS add-ons require clusters running version 1.18 or
    later because Amazon EKS add-ons rely on the Server-side Apply Kubernetes feature, which is only available in
    Kubernetes 1.18 and later. For more information, see Amazon EKS add-ons in the Amazon EKS User Guide.

    Args:
        name(Text): An Idem name of the EKS addon resource.
        resource_id(Text, optional): AWS EKS addon name.
        cluster_name(Text): The name of the cluster to create the add-on for
        addon_version(Text): The version of the add-on. The version must match one of the versions returned
            by ` DescribeAddonVersions
        service_account_role_arn(Text, optional):The Amazon Resource Name (ARN) of an existing IAM role to bind to the add-on's
            service account. The role must be assigned the IAM permissions required by the add-on. If you don't specify
            an existing IAM role, then the add-on uses the permissions assigned to the node IAM role.
        resolve_conflicts(Text, optional): How to resolve parameter value conflicts when migrating an existing add-on
            to an Amazon EKS add-on
        tags(Dict, optional): The metadata to apply to the cluster to assist with categorization and organization.
            Each tag consists of a key and an optional value. You define both
        timeout(Dict, optional): Timeout configuration for creating or updating addon.
            * create (Dict) -- Timeout configuration for creating addon
                * delay(int, default=10) -- The amount of time in seconds to wait between attempts.
                * max_attempts(int, default=60) -- Customized timeout configuration containing delay and max attempts.
            * update (string) -- Timeout configuration for updating addon
                * delay(int, default=10) -- The amount of time in seconds to wait between attempts.
                * max_attempts(int, default=60) -- Customized timeout configuration containing delay and max attempts.
    Request Syntax:

        [eks-addon-name]:
              aws.eks.addon.present:
              - cluster_name: 'string'
              - addon_version: 'string'
              - resource_id: 'string'
              - service_account_role_arn: 'string'
              - resolve_conflicts: 'string'
              - tags:
                - Key: 'string'
                  Value: 'string'
              - timeout:
                   create:
                      delay: 'integer'
                      max_attempts: 'integer'
                   update:
                      delay: 'integer'
                      max_attempts: 'integer

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            kube-proxy:
              aws.eks.addon.present:
              - cluster_name: eks-12j44i4k
              - addon_version: v1.19.8-eksbuild.1
              - resource_id: kube-proxy
              - service_account_role_arn: arn:role-ejwew124
              - resolve_conflicts: "OVERWRITE"
              - tags:
                - Key: Name
                  Value: eks-addon-name
    """

    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.boto3.client.eks.describe_addon(
            ctx, clusterName=cluster_name, addonName=name
        )
        if not before["result"]:
            if not ("ResourceNotFoundException" in before["comment"][0]):
                result["result"] = False
                result["comment"] = before["comment"]
                return result

    if before and before["ret"]:
        try:
            result[
                "old_state"
            ] = hub.tool.aws.eks.conversion_utils.convert_raw_addon_to_present(
                raw_resource=before["ret"]["addon"], idem_resource_name=name
            )
            plan_state = copy.deepcopy(result["old_state"])
            client_request_token = result["old_state"].get("client_request_token", None)

            update_ret = await hub.exec.aws.eks.addon.update_addon(
                ctx=ctx,
                name=name,
                before=result["old_state"],
                addon_version=addon_version,
                service_account_role_arn=service_account_role_arn,
                resolve_conflicts=resolve_conflicts,
                client_request_token=client_request_token,
                timeout=timeout,
            )
            result["comment"] = update_ret["comment"]
            result["result"] = update_ret["result"]
            resource_updated = bool(update_ret["ret"])

            if update_ret["ret"] and ctx.get("test", False):
                result["comment"] = result["comment"] + (
                    f"Would update aws.eks.addon '{name}'",
                )
                for addon_param in update_ret["ret"]:
                    plan_state[addon_param] = update_ret["ret"][addon_param]

            if tags is not None:
                # Update tags
                update_tags_ret = await hub.exec.aws.eks.tag.update_eks_tags(
                    ctx=ctx,
                    resource_arn=result["old_state"].get("addon_arn"),
                    old_tags=result["old_state"].get("tags"),
                    new_tags=tags,
                )

            result["comment"] = result["comment"] + update_tags_ret["comment"]
            result["result"] = result["result"] and update_tags_ret["result"]
            resource_updated = resource_updated or bool(update_tags_ret["ret"])
            if ctx.get("test", False) and update_tags_ret["ret"]:
                plan_state["tags"] = update_tags_ret["ret"].get("tags")
        except hub.tool.boto3.exception.ClientError as e:
            result["comment"] = result["comment"] + (f"{e.__class__.__name__}: {e}",)
            result["result"] = False
    else:
        if ctx.get("test", False):
            result["new_state"] = hub.tool.aws.test_state_utils.generate_test_state(
                enforced_state={},
                desired_state={
                    "name": name,
                    "cluster_name": cluster_name,
                    "addon_version": addon_version,
                    "service_account_role_arn": service_account_role_arn,
                    "resolve_conflicts": resolve_conflicts,
                    "tags": tags,
                },
            )
            result["comment"] = hub.tool.aws.comment_utils.would_create_comment(
                resource_type="aws.eks.addon", name=name
            )
            return result
        try:
            ret = await hub.exec.boto3.client.eks.create_addon(
                ctx,
                clusterName=cluster_name,
                addonName=name,
                addonVersion=addon_version,
                serviceAccountRoleArn=service_account_role_arn,
                resolveConflicts=resolve_conflicts,
                tags=tags,
            )
            result["result"] = ret["result"]
            if not result["result"]:
                result["comment"] = ret["comment"]
                return result

            resource_id = ret["ret"]["addon"]["addonName"]
            waiter_config = hub.tool.aws.waiter_utils.create_waiter_config(
                default_delay=60,
                default_max_attempts=40,
                timeout_config=timeout.get("create") if timeout else None,
            )
            hub.log.debug(f"Waiting on creating aws.eks.addon '{name}'")
            try:
                await hub.tool.boto3.client.wait(
                    ctx,
                    "eks",
                    "addon_active",
                    addonName=resource_id,
                    clusterName=cluster_name,
                    WaiterConfig=waiter_config,
                )
            except Exception as e:
                result["comment"] = result["comment"] + (str(e),)
                result["result"] = False
            result["comment"] = hub.tool.aws.comment_utils.create_comment(
                resource_type="aws.eks.addon", name=name
            )
        except Exception as e:
            result["comment"] = result["comment"] + (f"{e.__class__.__name__}: {e}",)
            result["result"] = False
            return result

    try:
        if ctx.get("test", False):
            result["new_state"] = plan_state
        elif (not before) or resource_updated:
            after = await hub.exec.boto3.client.eks.describe_addon(
                ctx, clusterName=cluster_name, addonName=resource_id
            )
            result[
                "new_state"
            ] = hub.tool.aws.eks.conversion_utils.convert_raw_addon_to_present(
                raw_resource=after["ret"]["addon"], idem_resource_name=name
            )
        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,
    cluster_name: str,
    resource_id: str = None,
    preserve: bool = False,
    timeout: Dict = None,
) -> Dict[str, Any]:
    r"""
    **Autogenerated function**

    Delete an Amazon EKS add-on. When you remove the add-on, it will also be deleted from the cluster. You can
    always manually start an add-on on the cluster using the Kubernetes API.

    Args:
        name(Text): An Idem name of the EKS addon resource.
        cluster_name(Text): The name of the cluster to delete the add-on from.
        resource_id(Text, optional): AWS EKS addon name. Idem automatically considers this resource being absent
         if this field is not specified.
        preserve(Boolean, optional): Specifying this option preserves the add-on software on your cluster but Amazon
            EKS stops managing any settings for the add-on. If an IAM account is associated with the add-on,
            it is not removed.
        timeout(Dict, optional): Timeout configuration for creating or updating cluster.
            * delete (Dict) -- Timeout configuration for deleting cluster
                * delay -- The amount of time in seconds to wait between attempts.
                * max_attempts -- Customized timeout configuration containing delay and max attempts.

    Request syntax:

        [idem-eks-addon-name]:
              aws.eks.addon.absent:
              - cluster_name: 'string'
              - resource_id: 'string'
              - preserve: boolean

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            kube-proxy:
              aws.eks.addon.absent:
              - cluster_name: eks-cluster-1
              - resource_id: kube-proxy
              - preserve: True
    """

    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.eks.addon", name=name
        )
        return result
    before = await hub.exec.boto3.client.eks.describe_addon(
        ctx, clusterName=cluster_name, addonName=resource_id
    )

    if not before["ret"]:
        result["comment"] = hub.tool.aws.comment_utils.already_absent_comment(
            resource_type="aws.eks.addon", name=name
        )
    elif ctx.get("test", False):
        result[
            "old_state"
        ] = hub.tool.aws.eks.conversion_utils.convert_raw_addon_to_present(
            raw_resource=before["ret"]["addon"], idem_resource_name=name
        )
        result["comment"] = hub.tool.aws.comment_utils.would_delete_comment(
            resource_type="aws.eks.addon", name=name
        )
        return result
    else:
        result[
            "old_state"
        ] = hub.tool.aws.eks.conversion_utils.convert_raw_addon_to_present(
            raw_resource=before["ret"]["addon"], idem_resource_name=name
        )
        try:
            ret = await hub.exec.boto3.client.eks.delete_addon(
                ctx, clusterName=cluster_name, addonName=resource_id, preserve=preserve
            )
            result["result"] = ret["result"]
            if not result["result"]:
                result["comment"] = ret["comment"]
                result["result"] = False
                return result
            else:
                waiter_config = hub.tool.aws.waiter_utils.create_waiter_config(
                    default_delay=60,
                    default_max_attempts=40,
                    timeout_config=timeout.get("delete") if timeout else None,
                )
                try:
                    await hub.tool.boto3.client.wait(
                        ctx,
                        "eks",
                        "addon_deleted",
                        addonName=resource_id,
                        clusterName=cluster_name,
                        WaiterConfig=waiter_config,
                    )
                except Exception as e:
                    result["comment"] = result["comment"] + (str(e),)
                    result["result"] = False
            result["comment"] = result[
                "comment"
            ] + hub.tool.aws.comment_utils.delete_comment(
                resource_type="aws.eks.addon", 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


    Lists the available add-ons.


    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: bash

            $ idem describe aws.eks.addon
    """

    result = {}
    cluster_ret = await hub.exec.boto3.client.eks.list_clusters(ctx)
    if not cluster_ret["result"]:
        hub.log.debug(f"Could not describe cluster {cluster_ret['comment']}")
        return {}
    cluster_addons = []
    try:
        for name in cluster_ret["ret"]["clusters"]:
            addon_ret = await hub.exec.boto3.client.eks.list_addons(
                ctx, clusterName=name
            )
            if not addon_ret["result"]:
                hub.log.debug(
                    f"Could not describe cluster addons for cluster {name}, Error:  {addon_ret['comment']}"
                )
                continue
            for addon in addon_ret["ret"]["addons"]:
                cluster_addons.append({"name": name, "addon": addon})
    except Exception as e:
        result["comment"] = str(e)
        result["result"] = False
        return result

    for cluster_addon in cluster_addons:
        cluster_name = cluster_addon["name"]
        current_addon = cluster_addon["addon"]
        resource_id = f"{cluster_name}-{current_addon}"
        describe_ret = await hub.exec.boto3.client.eks.describe_addon(
            ctx, clusterName=cluster_name, addonName=current_addon
        )
        if not describe_ret["result"] or not describe_ret["ret"]:
            hub.log.debug(
                f"Could not describe addon {name}, Error:  {describe_ret['comment']}"
            )
            continue
        add_on = describe_ret["ret"]["addon"]
        resource_translated = (
            hub.tool.aws.eks.conversion_utils.convert_raw_addon_to_present(
                raw_resource=add_on, idem_resource_name=resource_id
            )
        )
        result[resource_id] = {
            "aws.eks.addon.present": [
                {parameter_key: parameter_value}
                for parameter_key, parameter_value in resource_translated.items()
            ]
        }

    return result
