"""
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 collections import OrderedDict
from typing import Any
from typing import Dict

__contracts__ = ["resource"]

TREQ = {
    "absent": {
        "require": [
            "aws.ec2.subnet.absent",
            "aws.ec2.vpc.absent",
            "aws.iam.role.absent",
            "aws.iam.role_policy_attachment.absent",
            "aws.eks.cluster.absent",
        ],
    },
    "present": {
        "require": [
            "aws.ec2.subnet.present",
            "aws.ec2.vpc.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,
    service_account_role_arn: str = None,
    resolve_conflicts: str = "OVERWRITE",
    tags: Dict = None,
) -> Dict[str, Any]:
    r"""
    **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): A name, ID to identify the resource.
        cluster_name(Text, required): The name of the cluster to create the add-on for
        addon_version(Text, required): 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

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            kube-proxy:
              aws.eks.addon.present:
              - cluster_name: {{ cluster }}
              - addon_version: v1.19.8-eksbuild.1
    """

    result = dict(comment="", old_state=None, new_state=None, name=name, result=True)
    is_not_changed = True
    before = await hub.exec.boto3.client.eks.describe_addon(
        ctx, clusterName=cluster_name, addonName=name
    )
    if ctx.get("test", False):
        if before:
            result["comment"] = f"Would update aws.eks.addon {name}"
            result["result"] = True
        else:
            result["comment"] = f"Would create aws.eks.addon {name}"
            result["result"] = True
        return result

    if before:
        result["comment"] = f"'{name}' already exists"
        result["old_state"] = before["ret"]["addon"]
        arn = before["ret"]["addon"]["addonArn"]
        if before["ret"]["addon"].get("clientRequestToken"):
            client_request_token = before["ret"]["addon"]["clientRequestToken"]
        else:
            client_request_token = None
        # change depends on addonVersion, serviceAccountRoleArn
        if (
            addon_version
            and before["ret"]["addon"].get("addonVersion") != addon_version
        ) or (
            service_account_role_arn
            and before["ret"]["addon"].get("serviceAccountRoleArn")
            != service_account_role_arn
        ):
            ret = await hub.exec.boto3.client.eks.update_addon(
                ctx,
                clusterName=cluster_name,
                addonName=name,
                addonVersion=addon_version,
                serviceAccountRoleArn=service_account_role_arn,
                resolveConflicts=resolve_conflicts,
                clientRequestToken=client_request_token,
                tags=tags,
            )
            result["result"] = ret["result"]
            if not result["result"]:
                result["comment"] = ret["comment"]
                return result
            try:
                await hub.tool.boto3.client.wait(
                    ctx,
                    "eks",
                    "addon_active",
                    None,
                    addonName=name,
                    clusterName=cluster_name,
                )
            except Exception as e:
                result["comment"] = str(e)
                result["result"] = False
                return result
            is_not_changed = False
        # Update tags
        old_tags = (
            copy.deepcopy(before["ret"]["addon"].get("tags"))
            if before["ret"]["addon"].get("tags")
            else {}
        )
        update_tags_ret = await hub.exec.aws.eks.tag.update_eks_tags(
            ctx=ctx,
            resource_arn=arn,
            old_tags=old_tags,
            new_tags=tags,
        )
        if not update_tags_ret["result"]:
            result["comment"] = update_tags_ret["comment"]
            result["result"] = False
            return result
        if update_tags_ret["ret"]:
            is_not_changed = False
        if not is_not_changed:
            result["comment"] = f"Updated '{name}'"

    else:
        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
            await hub.tool.boto3.client.wait(
                ctx,
                "eks",
                "addon_active",
                None,
                addonName=name,
                clusterName=cluster_name,
            )
            result["comment"] = f"Created '{name}'"
        except Exception as e:
            result["comment"] = str(e)
            result["result"] = False
            return result

    try:
        if is_not_changed:
            after = await hub.exec.boto3.client.eks.describe_addon(
                ctx, clusterName=cluster_name, addonName=name
            )
            result["new_state"] = after["ret"]["addon"]
        else:
            result["new_state"] = copy.deepcopy(result["old_state"])
    except Exception as e:
        result["comment"] = str(e)
        result["result"] = False
    return result


async def absent(
    hub,
    ctx,
    name: str,
    cluster_name: str,
    preserve: bool = False,
) -> 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): A name, ID to identify the resource.
        cluster_name(Text, required): The name of the cluster to delete the add-on from.
        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.

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            kube-proxy:
              aws.eks.addon.absent:
              - cluster_name: {{ cluster }}
              - preserve: True
    """

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

    before = await hub.exec.boto3.client.eks.describe_addon(
        ctx, clusterName=cluster_name, addonName=name
    )

    if not before:
        result["comment"] = f"'{name}' already absent"
    elif ctx.get("test", False):
        result["comment"] = f"Would delete aws.eks.addon {name}"
        return result
    else:
        result["old_state"] = before["ret"]["addon"]
        try:
            ret = await hub.exec.boto3.client.eks.delete_addon(
                ctx, clusterName=cluster_name, addonName=name, preserve=preserve
            )
            result["result"] = ret["result"]
            if not result["result"]:
                result["comment"] = ret["comment"]
                result["result"] = False
                return result
            try:
                await hub.tool.boto3.client.wait(
                    ctx,
                    "eks",
                    "addon_deleted",
                    None,
                    addonName=name,
                    clusterName=cluster_name,
                )
            except Exception as e:
                result["comment"] = str(e)
                result["result"] = False
                return result
            result["comment"] = f"Deleted '{name}'"
        except hub.tool.boto3.exception.ClientError as e:
            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"]:
                result["comment"] = addon_ret["comment"]
                return result
            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

    describe_parameters = OrderedDict(
        {
            "clusterName": "cluster_name",
            "addonArn": "addon_arn",
            "addonVersion": "addon_version",
            "releaseVersion": "release_version",
            "status": "status",
            "serviceAccountRoleArn": "service_account_role_arn",
        }
    )

    for cluster_addon in cluster_addons:
        cluster_name = cluster_addon["name"]
        current_addon = cluster_addon["addon"]
        describe_ret = await hub.exec.boto3.client.eks.describe_addon(
            ctx, clusterName=cluster_name, addonName=current_addon
        )
        add_on = describe_ret["ret"]["addon"]
        new_addon = []
        for parameter_old_key, parameter_new_key in describe_parameters.items():
            if add_on.get(parameter_old_key) is not None:
                new_addon.append({parameter_new_key: add_on.get(parameter_old_key)})
        if add_on.get("tags"):
            new_addon.append({"tags": add_on.get("tags").copy()})

        result[current_addon] = {"aws.eks.addon.present": new_addon}
    return result
