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

hub.exec.boto3.client.organizations.deregister_delegated_administrator
hub.exec.boto3.client.organizations.list_delegated_administrators
hub.exec.boto3.client.organizations.register_delegated_administrator
"""
from typing import Any
from typing import Dict
from typing import List

__contracts__ = ["resource"]


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

    Creates an organizational unit (OU) within a root or parent OU. An OU is a container
    for accounts that enables you to organize your accounts to apply policies according
    to your business requirements. The number of levels deep that you can nest OUs is
    dependent upon the policy types enabled for that root. For service control policies,
    the limit is five.

    Args:
        hub:
        ctx:
        name(Text): A name or ID to identify the resource.
        parent_id(str): The unique identifier (ID) of the parent root or OU that you
                                  want to create the new OU in.
        org_unit_name(str): A friendly name to assign to the ou
        tags(list,Optional): A list of tags that you want to attach to the newly created OU


    Request Syntax:
        [org-id]:
          aws.organizations.organization_unit.present:
          - parent_id: 'string'
          - org_unit_name: 'string'
          - tags:
            - Key: 'string'
              Value: 'string'

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            org_is_present:
              aws.organizations.organization_unit.present:
                - parent_id: ou-01919
                - org_unit_name: ou-new
                - tags:
                    - Key: org
                      Value: guardrails
    """

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

    ou_id = name

    before = await hub.exec.boto3.client.organizations.describe_organizational_unit(
        ctx, OrganizationalUnitId=ou_id
    )

    if ctx.get("test", False):
        if before:
            result[
                "comment"
            ] = f"Would update aws.organizations.organization_unit {name}."
            result["result"] = True
        else:
            result[
                "comment"
            ] = f"Would create aws.organizations.organization_unit {name}."
            result["result"] = True
        return result

    if not before:
        # organization unit does not exist, create
        hub.log.debug("Creating organization for this account")

        try:
            create_ret = (
                await hub.exec.boto3.client.organizations.create_organizational_unit(
                    ctx, ParentId=parent_id, Name=org_unit_name, Tags=tags
                )
            )

            result["result"] = create_ret["result"]

            if not result["result"]:
                result["comment"] = create_ret["comment"]
                return result
            ou_id = create_ret["ret"]["OrganizationalUnit"]["Id"]
            result["comment"] = f"Created aws.organizations.organization_unit {name}."
        except hub.tool.boto3.exception.ClientError as e:
            result["comment"] = f"{e.__class__.__name__}: {e}"
            result["result"] = False
    else:
        # organizational_unit exists , update
        existing_ou_name = before["ret"]["OrganizationalUnit"]["Name"]

        before["ret"].pop("ResponseMetadata", None)

        old_tags = await hub.exec.boto3.client.organizations.list_tags_for_resource(
            ctx, ResourceId=ou_id
        )

        if old_tags:
            before["ret"]["OrganizationalUnit"]["Tags"] = old_tags["ret"]["Tags"]

        result["old_state"] = before["ret"]["OrganizationalUnit"]

        try:

            if existing_ou_name != org_unit_name:

                update_ret = await hub.exec.boto3.client.organizations.update_organizational_unit(
                    ctx,
                    OrganizationalUnitId=ou_id,
                    Name=org_unit_name,
                )

                result["result"] = update_ret["result"]
                if not result["result"]:
                    result["comment"] = update_ret["comment"]
                    return result
                result[
                    "comment"
                ] = f"Updated aws.organizations.organization_unit {name}."

            if tags is not None and old_tags["result"]:
                update_tags_ret = (
                    await hub.exec.aws.organizations.organization.update_tags(
                        ctx, ou_id, old_tags["ret"].get("Tags", []), tags
                    )
                )
                if not update_tags_ret["result"]:
                    result["comment"] = "{} , {}".format(
                        result["comment"], str(update_tags_ret["comment"])
                    )
                    return result
                result["comment"] = "{} , {}".format(
                    result["comment"],
                    f"Updated tags on aws.organizations.organization_unit '{name}'. ",
                )
        except hub.tool.boto3.exception.ClientError as e:
            result["comment"] = f"{e.__class__.__name__}: {e}"
            result["result"] = False

    try:
        after = await hub.exec.boto3.client.organizations.describe_organizational_unit(
            ctx, OrganizationalUnitId=ou_id
        )

        if after.get("ret"):
            after["ret"].pop("ResponseMetadata", None)
            updated_tag = (
                await hub.exec.boto3.client.organizations.list_tags_for_resource(
                    ctx, ResourceId=ou_id
                )
            )
            if updated_tag and updated_tag.get("ret"):
                after["ret"]["OrganizationalUnit"]["Tags"] = updated_tag["ret"].get(
                    "Tags", []
                )
            result["new_state"] = after["ret"]["OrganizationalUnit"]
    except Exception as e:
        result["comment"] = str(e)
        result["result"] = False

    return result


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

    Deletes an organizational unit (OU) from a root or another OU. You must first remove all accounts
    and child OUs from the OU that you want to delete.This operation can be called only from the
    organization's management account.

    Args:
        name(Text): An ID to identify the resource.

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            resource_is_absent:
              aws.organizations.organization_unit.absent:
                - name: ou-id1011
    """

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

    ou_id = name

    before = await hub.exec.boto3.client.organizations.describe_organizational_unit(
        ctx, OrganizationalUnitId=ou_id
    )

    if ctx.get("test", False):
        if before:
            result[
                "comment"
            ] = f"Would delete aws.organizations.organization_unit {name}."
            result["result"] = True
        else:
            result[
                "comment"
            ] = f"aws.organizations.organization_unit {name} already absent"
            result["result"] = True
        return result

    if not before:
        result["comment"] = f"aws.organizations.organization_unit {name} already absent"
        result["result"] = True
    else:
        before["ret"].pop("ResponseMetadata", None)

        result["old_state"] = before["ret"]["OrganizationalUnit"]
        try:
            ret = await hub.exec.boto3.client.organizations.delete_organizational_unit(
                ctx, OrganizationalUnitId=ou_id
            )

            if not ret:
                result["comment"] = ret["comment"]
                result["result"] = False
                return result
            result["comment"] = f"aws.organizations.organization_unit {name} deleted."
            result["result"] = ret["result"]
        except hub.tool.boto3.exception.ClientError as e:
            result["comment"] = f"{e.__class__.__name__}: {e}"
            result["result"] = False

    return result


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

    Lists the organizational units (OUs) in a parent organizational unit or root.

    Idem does not support passing arguments to the describe function as of today , hence describe organizational unit
    will describe all the organizational unit one level under the root of the organization.
    In future if Idem starts supporting input arguments , we can pass any parent_id and this function will list
    all organizational units one level under the parent.


    Returns:
        Dict[str, Any]


    Examples:

        .. code-block:: bash

            $ idem describe aws.organizations.organization_unit
    """

    result = {}

    list_roots_resp = await hub.exec.boto3.client.organizations.list_roots(ctx)

    if not (list_roots_resp and list_roots_resp["ret"].get("Roots")):
        return result

    parent_id = list_roots_resp["ret"]["Roots"][0]["Id"]

    if parent_id is None:
        return result

    org_units = (
        await hub.exec.boto3.client.organizations.list_organizational_units_for_parent(
            ctx, ParentId=parent_id
        )
    )

    if not org_units:
        hub.log.debug(
            f"Could not describe organization unit {org_units['comment']} for parent_id {parent_id}"
        )
        result[
            "comment"
        ] = f"Could not describe aws.organizations.organization_unit for parent_id {parent_id}"
        result["result"] = False
        return result

    organizational_units = org_units["ret"]["OrganizationalUnits"]

    for ou in organizational_units:
        translated_resource = []
        if ou.get("Name") is not None:
            translated_resource.append({"org_unit_name": ou.get("Name")})
        translated_resource.append({"parent_id": parent_id})
        tags = await hub.exec.boto3.client.organizations.list_tags_for_resource(
            ctx, ResourceId=ou["Id"]
        )
        if tags:
            translated_resource.append({"tags": tags["ret"].get("Tags", [])})
        result[ou["Id"]] = {
            "aws.organizations.organization_unit.present": translated_resource
        }

    return result
