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


"""
from collections import OrderedDict
from typing import Any
from typing import Dict

from idem_azure_auto.helpers.exc import DescribeError
from idem_azure_auto.helpers.returns import StateReturn

__contracts__ = ["resource"]


async def present(
    hub,
    ctx,
    name: str,
    scope: str,
    policy_assignment_name: str,
    parameters: dict = {},
    force_update: bool = False,
) -> StateReturn:
    r"""
    **Autogenerated function**

    Create or update Policy Assignments

    Args:
        name(str): The identifier for this state.
        scope(str): The scope of the policy assignment. Valid scopes are: management group (format: '/providers/Microsoft.Management/managementGroups/{managementGroup}'), subscription (format: '/subscriptions/{subscriptionId}'), resource group (format: '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}', or resource (format: '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/[{parentResourcePath}/]{resourceType}/{resourceName}'.
        policy_assignment_name(str): The name of the policy assignment.
        parameters(dict, optional): API request payload parameters. Defaults to {}.
        force_update(bool, optional): If PUT operation should be used instead of PATCH operation during resource update. Defaults to False.

    Returns:
        StateReturn

    Examples:

        .. code-block:: sls

            resource_is_present:
              azure.policy.policy_assignments.present:
                - name: value
                - scope: value
                - policy_assignment_name: value
    """

    subscription_id = ctx.acct.subscription_id
    if "{subscriptionId}" in scope:
        scope = scope.replace("{subscriptionId}", subscription_id)
    response_get = await hub.exec.request.json.get(
        ctx,
        url=f"https://management.azure.com/{scope}/providers/Microsoft.Authorization/policyAssignments/{policy_assignment_name}?api-version=2021-06-01",
        success_codes=[200],
        headers=ctx.acct.headers,
    )

    if force_update:
        if ctx.get("test", False):
            return StateReturn(
                name=name,
                result=True,
                comment="Would force to update azure.policy.policy_assignments",
            )
        response_force_put = await hub.exec.request.json.put(
            ctx,
            url=f"https://management.azure.com/{scope}/providers/Microsoft.Authorization/policyAssignments/{policy_assignment_name}?api-version=2021-06-01",
            success_codes=[201],
            headers=ctx.acct.headers,
            json=parameters,
        )
        if response_force_put["result"]:
            old_resource = response_get["ret"] if response_get["result"] else None
            return StateReturn(
                name=name,
                result=True,
                old_obj=old_resource,
                new_obj=response_force_put["ret"],
                comment=response_force_put["comment"],
            )
        else:
            hub.log.debug(
                f"Could not force to update Policy Assignments {response_force_put['comment']} {response_force_put['ret']}"
            )
            return StateReturn(
                name=name,
                result=False,
                comment=response_force_put["comment"],
                error=response_force_put["ret"],
            )

    if not response_get["result"]:
        if ctx.get("test", False):
            return StateReturn(
                name=name,
                result=True,
                comment="Would create azure.policy.policy_assignments",
            )

        if response_get["status"] == 404:
            # PUT operation to create a resource
            response_put = await hub.exec.request.json.put(
                ctx,
                url=f"https://management.azure.com/{scope}/providers/Microsoft.Authorization/policyAssignments/{policy_assignment_name}?api-version=2021-06-01",
                success_codes=[201],
                headers=ctx.acct.headers,
                json=parameters,
            )

            if not response_put["result"]:
                hub.log.debug(
                    f"Could not create Policy Assignments {response_put['comment']} {response_put['ret']}"
                )
                return StateReturn(
                    name=name,
                    result=False,
                    comment=response_put["comment"],
                    error=response_put["ret"],
                )

            return StateReturn(
                name=name,
                result=True,
                old_obj=None,
                new_obj=response_put["ret"],
                comment=response_put["comment"],
            )
        else:
            hub.log.debug(
                f"Could not get Policy Assignments {response_get['comment']} {response_get['ret']}"
            )
            return StateReturn(
                name=name,
                result=False,
                comment=response_get["comment"],
                error=response_get["ret"],
            )

    else:
        # PATCH operation to update a resource
        patch_parameters = {"identity": "identity", "location": "location"}
        existing_resource = response_get["ret"]
        new_parameters = hub.tool.azure.utils.patch_json_content(
            patch_parameters, existing_resource, parameters, force_update_parameters={}
        )
        if ctx.get("test", False):
            return StateReturn(
                name=name,
                result=True,
                comment=f"Would update azure.policy.policy_assignments with parameters: {new_parameters}",
            )

        if not new_parameters:
            return StateReturn(
                name=name,
                result=True,
                old_obj=existing_resource,
                new_obj=existing_resource,
                comment=f"'{name}' has no property need to be updated.",
            )

        response_patch = await hub.exec.request.json.patch(
            ctx,
            url=f"https://management.azure.com/{scope}/providers/Microsoft.Authorization/policyAssignments/{policy_assignment_name}?api-version=2021-06-01",
            success_codes=[200],
            headers=ctx.acct.headers,
            json=new_parameters,
        )

        if not response_patch["result"]:
            hub.log.debug(
                f"Could not update Policy Assignments {response_patch['comment']} {response_patch['ret']}"
            )
            return StateReturn(
                name=name,
                result=False,
                comment=response_patch["comment"],
                error=response_patch["ret"],
            )

        return StateReturn(
            name=name,
            result=True,
            old_obj=existing_resource,
            new_obj=response_patch["ret"],
            comment=response_patch["comment"],
        )


async def absent(
    hub, ctx, name: str, scope: str, policy_assignment_name: str
) -> StateReturn:
    r"""
    **Autogenerated function**

    Delete Policy Assignments

    Args:
        name(str): The identifier for this state.
        scope(str): The scope of the policy assignment. Valid scopes are: management group (format: '/providers/Microsoft.Management/managementGroups/{managementGroup}'), subscription (format: '/subscriptions/{subscriptionId}'), resource group (format: '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}', or resource (format: '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/[{parentResourcePath}/]{resourceType}/{resourceName}'.
        policy_assignment_name(str): The name of the policy assignment to delete.

    Returns:
        StateReturn

    Examples:

        .. code-block:: sls

            resource_is_absent:
              azure.policy.policy_assignments.absent:
                - name: value
                - scope: value
                - policy_assignment_name: value
    """

    subscription_id = ctx.acct.subscription_id
    if "{subscriptionId}" in scope:
        scope = scope.replace("{subscriptionId}", subscription_id)
    response_get = await hub.exec.request.json.get(
        ctx,
        url=f"https://management.azure.com/{scope}/providers/Microsoft.Authorization/policyAssignments/{policy_assignment_name}?api-version=2021-06-01",
        success_codes=[200],
        headers=ctx.acct.headers,
    )
    if response_get["result"]:
        if ctx.get("test", False):
            return StateReturn(
                name=name,
                result=True,
                comment="Would delete azure.policy.policy_assignments",
            )

        existing_resource = response_get["ret"]
        response_delete = await hub.exec.request.raw.delete(
            ctx,
            url=f"https://management.azure.com/{scope}/providers/Microsoft.Authorization/policyAssignments/{policy_assignment_name}?api-version=2021-06-01",
            success_codes=[200, 204],
            headers=ctx.acct.headers,
        )

        if not response_delete["result"]:
            hub.log.debug(
                f"Could not delete Policy Assignments {response_delete['comment']} {response_delete['ret']}"
            )
            return StateReturn(
                name=name,
                result=False,
                comment=response_delete["comment"],
                error=response_delete["ret"],
            )

        return StateReturn(
            name=name,
            result=True,
            old_obj=existing_resource,
            new_obj={},
            comment=response_delete["comment"],
        )
    elif response_get["status"] == 404:
        # If Azure returns 'Not Found' error, it means the resource has been absent.
        return StateReturn(
            name=name,
            result=True,
            old_obj=None,
            new_obj=None,
            comment=f"'{name}' already absent",
        )
    else:
        hub.log.debug(
            f"Could not get Policy Assignments {response_get['comment']} {response_get['ret']}"
        )
        return StateReturn(
            name=name,
            result=False,
            comment=response_get["comment"],
            error=response_get["ret"],
        )


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


    List all Policy Assignments under the same subscription


    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: bash

            $ idem describe azure.policy.policy_assignments
    """

    result = {}
    subscription_id = ctx.acct.subscription_id
    uri_parameters = OrderedDict({"policyAssignments": "policy_assignment_name"})
    try:
        async for page_result in hub.tool.azure.request.paginate(
            ctx,
            url=f"https://management.azure.com/subscriptions/{subscription_id}/providers/Microsoft.Authorization/policyAssignments?api-version=2021-06-01",
            success_codes=[200],
            headers=ctx.acct.headers,
        ):
            resource_list = page_result.get("value", None)
            if resource_list:
                for resource in resource_list:
                    uri_parameter_values = (
                        hub.tool.azure.utils.get_uri_parameter_value_from_uri(
                            resource["id"], uri_parameters
                        )
                    )
                    if uri_parameter_values is None:
                        uri_parameter_values = list()
                    uri_parameter_values.insert(
                        0, {"scope": resource.get("properties").get("scope")}
                    )
                    result[resource["id"]] = {
                        f"azure.policy.policy_assignments.present": uri_parameter_values
                        + [{"parameters": resource}]
                    }
    except ValueError as e:
        raise DescribeError(f"Error on describing Policy Assignments: {str(e)}")
    return result
