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

hub.exec.boto3.client.organizations.attach_policy
hub.exec.boto3.client.organizations.create_policy
hub.exec.boto3.client.organizations.delete_policy
hub.exec.boto3.client.organizations.describe_policy
hub.exec.boto3.client.organizations.detach_policy
hub.exec.boto3.client.organizations.list_policies
hub.exec.boto3.client.organizations.update_policy
"""
import copy
from typing import Any
from typing import Dict

__contracts__ = ["resource"]

TREQ = {
    "present": {
        "require": [
            "aws.organizations.organization.present",
            "aws.organizations.organization_unit.present",
            "aws.organizations.account.present",
            "aws.organizations.policy.present",
        ],
    },
}


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

    Attaches a policy to a root, an organizational unit (OU), or an individual account.
    How the policy affects accounts depends on the type of policy. Supported policy type is :
    SERVICE_CONTROL_POLICY

    Args:
        name(Text): An ID to identify the resource.
        policy_id(str): The unique identifier (ID) of the policy that you want to attach to the target.
                    You can get the ID for the policy by calling the ListPolicies operation.
        target_id(str): The unique identifier (ID) of the root, OU, or account that you want to attach the policy to.

    Request Syntax:
        [policy_id-target_id]:
          aws.organizations.policy_attachment.present:
          - policy_id: 'string'
          - target_id: 'string'



    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            p-id-ou-bitz-1223:
              aws.organizations.policy_attachment.present:
              - policy_id: p-id
              - target_id: ou-bitz-1223
    """

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

    try:
        before_ret = await hub.exec.aws.organizations.policy_attachment.is_target_policy_attached(
            ctx, policy_id=policy_id, target_id=target_id
        )
    except hub.tool.boto3.exception.ClientError as e:
        result["comment"] = f"{e.__class__.__name__}: {e}"
        result["result"] = False
        return result

    # If before_ret has False result and has an error message in comment, then immediately return with the error.
    if before_ret["result"] is False and before_ret["comment"]:
        result["result"] = False
        result["comment"] = before_ret["comment"]
        return result

    if ctx.get("test", False):
        if before_ret["result"]:
            result[
                "comment"
            ] = f"aws.organizations.policy_attachment {name} already exists"
        else:
            result[
                "comment"
            ] = f"Would attach aws.organizations.policy_attachment {name}"
        return result

    if before_ret["result"]:
        result["old_state"] = before_ret["ret"]
        result["new_state"] = copy.deepcopy(before_ret["ret"])
        result["comment"] = f"'{name}' already exists"
    else:
        try:
            ret = await hub.exec.boto3.client.organizations.attach_policy(
                ctx,
                PolicyId=policy_id,
                TargetId=target_id,
            )
            result["result"] = ret["result"]
            if not result["result"]:
                result["comment"] = ret["comment"]
                return result
            result["comment"] = f"Attached '{name}'"
            result["new_state"] = {"PolicyId": policy_id}
        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, policy_id: str, target_id: str) -> Dict[str, Any]:
    r"""
    **Autogenerated function**

    Detaches a policy from a target root, organizational unit (OU), or account.
    Every root, OU, and account must have at least one SCP attached. If you want
    to replace the default FullAWSAccess policy with an SCP that limits the
    permissions that can be delegated, you must attach the replacement SCP
    before you can remove the default SCP. This is the authorization strategy
    of an "allow list ". If you instead attach a second SCP and leave the FullAWSAccess
    SCP still attached, and specify "Effect": "Deny" in the second SCP to override
    the "Effect": "Allow" in the FullAWSAccess policy (or any other attached SCP),
    you're using the authorization strategy of a "deny list ".

    Args:
        name(Text): An ID to identify the resource.
        policy_id(str): The unique identifier (ID) of the policy that you want to attach to the target.
                    You can get the ID for the policy by calling the ListPolicies operation.
        target_id(str): The unique identifier (ID) of the root, OU, or account that you want to detach the policy to.

    Request Syntax:
        [policy-target-id_detach]:
          aws.organizations.policy_attachment.absent:
          - policy_id: 'string'
          - target_id: 'string'

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            p-id-ou-bitz-1223:
              aws.organizations.policy_attachment.absent:
              - policy_id: p-id
              - target_id: ou-bitz-1223
    """

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

    try:
        before_ret = await hub.exec.aws.organizations.policy_attachment.is_target_policy_attached(
            ctx, policy_id=policy_id, target_id=target_id
        )
    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.organizations.policy_attachment {name}"
        return result
    else:
        try:
            result["old_state"] = before_ret["ret"]
            ret = await hub.exec.boto3.client.organizations.detach_policy(
                ctx,
                PolicyId=policy_id,
                TargetId=target_id,
            )
            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**

    Retrieves the list of all policies in an organization of a specified type.

    This operation can be called only from the organization's management account
    or by a member account that is a delegated administrator for an AWS service.

    Currently Idem AWS supports only SERVICE_CONTROL_POLICY for a policy type.


    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: bash

            $ idem describe aws.organizations.policy_attachment
    """

    result = {}

    ret = await hub.exec.boto3.client.organizations.list_policies(
        ctx, Filter="SERVICE_CONTROL_POLICY"
    )

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

    all_policies = ret["ret"].get("Policies", [])

    if all_policies:

        for policy in all_policies:

            policy_attachments_ret = (
                await hub.exec.boto3.client.organizations.list_targets_for_policy(
                    ctx, PolicyId=policy["Id"]
                )
            )

            if not policy_attachments_ret["result"]:
                hub.log.warning(
                    f"Could not get attached target list with policy {policy['Id']} with error"
                    f" {policy_attachments_ret['comment']} . Describe will skip this policy and continue."
                )
            else:
                targets = policy_attachments_ret["ret"].get("Targets", [])

                if not targets:
                    hub.log.warning(
                        f"Attached target list with policy {policy['Id']} is empty."
                        f"Describe will skip this policy and continue."
                    )
                    continue

                for target in targets:
                    resource_name = f"{target['TargetId']}-{policy['Id']}"
                    translated_target = list()
                    translated_target.append({"policy_id": policy["Id"]})
                    translated_target.append({"target_id": target["TargetId"]})

                    result[resource_name] = {
                        "aws.organizations.policy_attachment.present": translated_target
                    }

    return result
