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

hub.exec.boto3.client.iam.attach_user_policy
hub.exec.boto3.client.iam.detach_user_policy
hub.exec.boto3.client.iam.list_user_policies
"""
from typing import Any
from typing import Dict

__contracts__ = ["resource"]


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

    Attaches the specified managed policy to the specified user.
    You use this operation to attach a managed policy to a user. To embed an inline policy in a user, use PutUserPolicy .

    Args:
        hub:
        ctx:
        name(Text): The name (friendly name, not ARN) of the IAM user to attach the policy to.
        user_name(Text): The name (friendly name, not ARN) of the IAM user to detach the policy from.
        This parameter allows (through its regex pattern ) a string of characters consisting of upper and lowercase alphanumeric characters with no spaces. You can also include any of the following characters: _+=,.@-
        policy_arn(Text): The Amazon Resource Name (ARN) of the IAM policy you want to attach.

    Request Syntax:
        [iam-attach-user-policy-name]:
          aws.iam.user_policy_attachment.present:
          - user_name: 'string'
          - policy_arn: 'string'

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls
        serverless-arn:aws:iam::aws:policy/AdministratorAccess:
          aws.iam.user_policy_attachment.present:
          - user_name: serverless
          - policy_arn: arn:aws:iam::aws:policy/AdministratorAccess

    """
    result = dict(comment="", old_state=None, new_state=None, name=name, result=True)
    try:
        before_ret = await hub.exec.aws.iam.user_policy_attachment.get_policy_if_attached_to_user(
            ctx, user_name=user_name, policy_arn=policy_arn
        )
    except hub.tool.boto3.exception.ClientError as e:
        result["comment"] = f"{e.__class__.__name__}: {e}"
        result["result"] = False
        return result
    if ctx.get("test", False):
        if before_ret["result"]:
            result["comment"] = f"aws.iam.user_policy_attachment {name} already exists"
        else:
            result["comment"] = f"Would attach aws.iam.user_policy_attachment {name}"
        return result

    if before_ret["result"] is False and before_ret["comment"]:
        result["result"] = False
        result["comment"] = before_ret["comment"]
        return result

    if before_ret["result"]:
        result["old_state"] = before_ret["ret"]
        result["new_state"] = before_ret["ret"]
        result["comment"] = f"'{name}' already exists"
    else:
        try:
            ret = await hub.exec.boto3.client.iam.attach_user_policy(
                ctx,
                UserName=user_name,
                PolicyArn=policy_arn,
            )
            result["result"] = ret["result"]
            if not result["result"]:
                result["comment"] = ret["comment"]
                return result
            result["comment"] = f"Attached '{name}'"
            result["new_state"] = {"PolicyArn": policy_arn}
        except hub.tool.boto3.exception.ClientError as e:
            result["comment"] = f"{e.__class__.__name__}: {e}"
            result["result"] = False
    return result


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

    Removes the specified managed policy from the specified user.
    A user can also have inline policies embedded with it. To delete an inline policy, use DeleteUserPolicy

    Args:
        name(Text): The name (friendly name, not ARN) of the IAM user to attach the policy to.
        user_name(Text): The name (friendly name, not ARN) of the IAM user to detach the policy from.
        This parameter allows (through its regex pattern ) a string of characters consisting of upper and lowercase alphanumeric characters with no spaces. You can also include any of the following characters: _+=,.@-
        policy_arn(Text): The Amazon Resource Name (ARN) of the IAM policy you want to attach.

    Request Syntax:
        [iam-user-policy-name]:
          aws.iam.user_policy.absent:
          - user_name: 'string'
          - policy_arn: 'string'

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

        serverless-arn:aws:iam::aws:policy/AdministratorAccess:
          aws.iam.user_policy_attachment.absent:
          - user_name: serverless
          - policy_arn: arn:aws:iam::aws:policy/AdministratorAccess
    """

    result = dict(comment="", old_state=None, new_state=None, name=name, result=True)
    try:
        before_ret = await hub.exec.aws.iam.user_policy_attachment.get_policy_if_attached_to_user(
            ctx, user_name=user_name, policy_arn=policy_arn
        )
    except hub.tool.boto3.exception.ClientError as e:
        result["comment"] = f"{e.__class__.__name__}: {e}"
        result["result"] = False
        return result

    if before_ret["result"] is False and before_ret["comment"]:
        result["result"] = False
        result["comment"] = before_ret["comment"]
        return result
    if not before_ret["result"]:
        result["comment"] = f"'{name}' already absent"
    elif ctx.get("test", False):
        result["comment"] = f"Would detach aws.iam.user_policy_attachment {name}"
        return result
    else:
        try:
            result["old_state"] = before_ret["ret"]
            ret = await hub.exec.boto3.client.iam.detach_user_policy(
                ctx, UserName=user_name, PolicyArn=policy_arn
            )
            result["result"] = ret["result"]
            if not result["result"]:
                result["comment"] = ret["comment"]
                result["result"] = False
                return result
            result["comment"] = f"Detached '{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 all managed policies that are attached to the specified IAM user. Lists all managed policies that are attached to the specified IAM user.



    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: bash

            $ idem describe aws_auto.iam.user_policy_attachment
    """

    result = {}
    # Fetch all users and then policies for each of them
    users = await hub.exec.boto3.client.iam.list_users(ctx)
    if not users["result"]:
        hub.log.debug(f"Could not describe user {users['comment']}")
        return {}
    user_names = [user.get("UserName") for user in users["ret"]["Users"]]
    for user_name in user_names:
        ret_attached_policies = (
            await hub.exec.boto3.client.iam.list_attached_user_policies(
                ctx=ctx, UserName=user_name
            )
        )
        if not ret_attached_policies["result"]:
            hub.log.warning(
                f"Could not get attached policy list with user {user_name} with error"
                f" {ret_attached_policies['comment']} . Describe will skip this user and continue."
            )
        else:
            resources = ret_attached_policies["ret"].get("AttachedPolicies")
            for resource in resources:
                resource_name = f"{user_name}-{resource.get('PolicyArn')}"
                resource_translated = list()
                resource_translated.append({"user_name": user_name})
                resource_translated.append({"policy_arn": resource.get("PolicyArn")})
                result[resource_name] = {
                    "aws.iam.user_policy_attachment.present": resource_translated
                }
    return result
