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

hub.exec.boto3.client.ce.create_anomaly_monitor
hub.exec.boto3.client.ce.delete_anomaly_monitor
hub.exec.boto3.client.ce.get_anomaly_monitors
hub.exec.boto3.client.ce.update_anomaly_monitor
resource = hub.exec.boto3.client.ce.create_anomaly_monitor(ctx, AnomalyMonitor)
"""
import copy
from dataclasses import field
from dataclasses import make_dataclass
from typing import Any
from typing import Dict
from typing import List

__contracts__ = ["resource"]


async def present(
    hub,
    ctx,
    name: str,
    monitor_name: str,
    monitor_type: str,
    monitor_dimension: str = None,
    monitor_specification: make_dataclass(
        "Expression",
        [
            (
                "Or",
                List[
                    make_dataclass(
                        "Expression",
                        [
                            ("Or", List["Expression"], field(default=None)),
                            ("And", List["Expression"], field(default=None)),
                            ("Not", "Expression", field(default=None)),
                            (
                                "Dimensions",
                                make_dataclass(
                                    "DimensionValues",
                                    [
                                        ("Key", str, field(default=None)),
                                        ("Values", List[str], field(default=None)),
                                        (
                                            "MatchOptions",
                                            List[str],
                                            field(default=None),
                                        ),
                                    ],
                                ),
                                field(default=None),
                            ),
                            (
                                "Tags",
                                make_dataclass(
                                    "TagValues",
                                    [
                                        ("Key", str, field(default=None)),
                                        ("Values", List[str], field(default=None)),
                                        (
                                            "MatchOptions",
                                            List[str],
                                            field(default=None),
                                        ),
                                    ],
                                ),
                                field(default=None),
                            ),
                            (
                                "CostCategories",
                                make_dataclass(
                                    "CostCategoryValues",
                                    [
                                        ("Key", str, field(default=None)),
                                        ("Values", List[str], field(default=None)),
                                        (
                                            "MatchOptions",
                                            List[str],
                                            field(default=None),
                                        ),
                                    ],
                                ),
                                field(default=None),
                            ),
                        ],
                    )
                ],
                field(default=None),
            ),
            ("And", List["Expression"], field(default=None)),
            ("Not", "Expression", field(default=None)),
            ("Dimensions", "DimensionValues", field(default=None)),
            ("Tags", Any, field(default=None)),
            ("CostCategories", Any, field(default=None)),
        ],
    ) = None,
    resource_id: str = None,
) -> Dict[str, Any]:
    r"""
    **Autogenerated function**

    Creates a new cost anomaly detection monitor with the requested type and monitor specification.

    Args:
        name(Text): An Idem name of the resource.
        resource_id(Text): Monitor ARN to identify the resource.
        monitor_name: Name of anomaly monitor.
        monitor_type(Text): Possible type values. Valid Values: DIMENSIONAL | CUSTOM
        monitor_dimension(Text): The dimensions to evaluate : SERVICE
        monitor_specification(Dict[str, Any], optional): Use Expression to filter by cost or by usage.
            There are two patterns:
                Simple dimension values
                    - You can set the dimension name and values for the filters that you plan to use. For example,
                    you can filter for REGION==us-east-1 OR REGION==us-west-1. For GetRightsizingRecommendation, the
                    Region is a full name (for example, REGION==US East (N. Virginia). The Expression example is as
                    follows:  { "Dimensions": { "Key": "REGION", "Values": [ "us-east-1", “us-west-1” ] } }  The
                    list of dimension values are OR'd together to retrieve cost or usage data. You can create
                    Expression and DimensionValues objects using either with* methods or set* methods in multiple
                    lines.
                Compound dimension values with logical operations
                    - You can use multiple Expression types and the logical operators AND/OR/NOT to create a list of one or more Expression objects.
                    By doing this, you can filter on more advanced options. For example, you can filter on ((REGION
                    == us-east-1 OR REGION == us-west-1) OR (TAG.Type == Type1)) AND (USAGE_TYPE != DataTransfer).
                    The Expression for that is as follows:  { "And": [ {"Or": [ {"Dimensions": { "Key": "REGION",
                    "Values": [ "us-east-1", "us-west-1" ] }}, {"Tags": { "Key": "TagName", "Values": ["Value1"] } }
                    ]}, {"Not": {"Dimensions": { "Key": "USAGE_TYPE", "Values": ["DataTransfer"] }}} ] }    Because
                    each Expression can have only one operator, the service returns an error if more than one is
                    specified. The following example shows an Expression object that creates an error.    { "And": [
                    ... ], "DimensionValues": { "Dimension": "USAGE_TYPE", "Values": [ "DataTransfer" ] } }      For
                    the GetRightsizingRecommendation action, a combination of OR and NOT isn't supported. OR isn't
                    supported between different dimensions, or dimensions and tags. NOT operators aren't supported.
                    Dimensions are also limited to LINKED_ACCOUNT, REGION, or RIGHTSIZING_TYPE. For the
                    GetReservationPurchaseRecommendation action, only NOT is supported. AND and OR aren't supported.
                    Dimensions are limited to LINKED_ACCOUNT.
                * Or (List[Dict[str, Any]], optional): Return results that match either Dimension object.
                    * Or (List[Dict[str, Any]], optional): Return results that match either Dimension object.
                    * And (List[Dict[str, Any]], optional): Return results that match both Dimension objects.
                    * Not (Dict[str, Any], optional): Return results that don't match a Dimension object.
                    * Dimensions (Dict[str, Any], optional): The specific Dimension to use for Expression.
                        * Key (str, optional): The names of the metadata types that you can use to filter and group your results. For example,
                            AZ returns a list of Availability Zones.
                        * Values (List[str], optional): The metadata values that you can use to filter and group your results. You can use
                            GetDimensionValues to find specific values.
                        * MatchOptions (List[str], optional): The match options that you can use to filter your results. MatchOptions is only applicable for
                            actions related to Cost Category. The default values for MatchOptions are EQUALS and
                            CASE_SENSITIVE.
                    * Tags (Dict[str, Any], optional): The specific Tag to use for Expression.
                        * Key (str, optional): The key for the tag.
                        * Values (List[str], optional): The specific value of the tag.
                        * MatchOptions (List[str], optional): The match options that you can use to filter your results. MatchOptions is only applicable for
                            actions related to Cost Category. The default values for MatchOptions are EQUALS and
                            CASE_SENSITIVE.
                    * CostCategories (Dict[str, Any], optional): The filter that's based on CostCategory values.
                        * Key (str, optional): The unique name of the Cost Category.
                        * Values (List[str], optional): The specific value of the Cost Category.
                        * MatchOptions (List[str], optional): The match options that you can use to filter your results. MatchOptions is only applicable for
                            actions related to cost category. The default values for MatchOptions is EQUALS and
                            CASE_SENSITIVE.
                * And (List[Dict[str, Any]], optional): Return results that match both Dimension objects.
                * Not (Dict[str, Any], optional): Return results that don't match a Dimension object.
                * Dimensions (Dict[str, Any], optional): The specific Dimension to use for Expression.
                * Tags (Dict[str, Any], optional): The specific Tag to use for Expression.
                * CostCategories (Dict[str, Any], optional): The filter that's based on CostCategory values.
    Request Syntax:
        [monitor-resource-id]:
          aws.costexplorer.anomaly_monitor.present:
          - resource_id: 'string'
          - monitor_name: 'string'
          - monitor_type: 'string'
          - monitor_specification:
            - Dimensions: 'dict'

    Returns:
        Dict[str, str]

    Examples:

        .. code-block:: sls

            cost_monitor1234:
              aws.costexplorer.anomaly_monitor.present:
              - name: cost_monitor1234
              - resource_id: cost_monitor1234
              - monitor_specification:
                Dimensions:
                  Key: LINKED_ACCOUNT
                  Values:
                    - '820272282974'
              - monitor_type: CUSTOM
    """
    result = dict(comment=(), old_state=None, new_state=None, name=name, result=True)
    before = None
    resource_updated = False

    if resource_id:
        before = await hub.exec.boto3.client.ce.get_anomaly_monitors(
            ctx, MonitorArnList=[resource_id]
        )

    if before and before["ret"].get("AnomalyMonitors"):
        before = before["ret"]["AnomalyMonitors"][0]
    else:
        before = None

    if not before:
        if ctx.get("test", False):
            result["new_state"] = hub.tool.aws.test_state_utils.generate_test_state(
                enforced_state={},
                desired_state={
                    "name": name,
                    "anomaly_monitor": {
                        "monitor_name": monitor_name,
                        "monitor_specification": monitor_specification,
                        "monitor_type": monitor_type,
                        "monitor_dimension": monitor_dimension,
                    },
                },
            )
            result["comment"] = (
                f"Would create aws.costexplorer.anomaly_monitor {name}",
            )
            return result

        monitor = None
        if monitor_specification:
            monitor = {
                "MonitorName": monitor_name,
                "MonitorSpecification": monitor_specification,
                "MonitorType": monitor_type,
            }
        else:
            monitor = {
                "MonitorName": monitor_name,
                "MonitorDimension": monitor_dimension,
                "MonitorType": monitor_type,
            }
        ret = await hub.exec.boto3.client.ce.create_anomaly_monitor(
            ctx,
            AnomalyMonitor=monitor,
        )
        result["result"] = ret["result"]
        if not result["result"]:
            result["comment"] = ret["comment"]
            return result
        result["comment"] = result["comment"] + (
            f"Created aws.costexplorer.anomaly_monitor '{name}'",
        )
        resource_id = ret["ret"]["MonitorArn"]
    else:

        result[
            "old_state"
        ] = hub.tool.aws.costexplorer.conversion_utils.convert_raw_monitor_to_present(
            ctx, raw_resource=before, idem_resource_name=name
        )
        plan_state = copy.deepcopy(result["old_state"])
        resource_id = before.get("MonitorArn")
        update_ret = await hub.exec.aws.costexplorer.anomaly_monitor.update_monitor(
            ctx, before=before, monitor_name=monitor_name, monitor_arn=resource_id
        )
        result["comment"] = result["comment"] + update_ret["comment"]
        result["result"] = update_ret["result"]
        resource_updated = resource_updated or bool(update_ret["ret"])
        if update_ret["ret"] and ctx.get("test", False):
            if "monitor_name" in update_ret["ret"]:
                plan_state["monitor_name"] = update_ret["ret"]["monitor_name"]

        if not resource_updated:
            result["comment"] = result["comment"] + (f"{name} already exists",)

    try:
        if ctx.get("test", False):
            result["new_state"] = plan_state
        elif (not before) or resource_updated:
            after = await hub.exec.boto3.client.ce.get_anomaly_monitors(
                ctx, MonitorArnList=[resource_id]
            )
            result[
                "new_state"
            ] = hub.tool.aws.costexplorer.conversion_utils.convert_raw_monitor_to_present(
                ctx,
                raw_resource=after["ret"]["AnomalyMonitors"][0],
                idem_resource_name=name,
            )
        else:
            result["new_state"] = copy.deepcopy(result["old_state"])
    except Exception as e:
        result["comment"] = result["comment"] + (str(e),)
        result["result"] = False
    return result


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

    Deletes a cost anomaly monitor by the specified monitor ARN as resource_id.

    Args:
        name(Text): The Idem name of the anomaly monitor.
        resource_id(Text): Monitor ARN to identify the resource.

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            cost_monitor1234:
              aws.costexplorer.anomaly_monitor.absent:
                - name: value
                - resource_id: cost_monitor1234
    """
    result = dict(comment=(), old_state=None, new_state=None, name=name, result=True)
    before = await hub.exec.boto3.client.ce.get_anomaly_monitors(
        ctx, MonitorArnList=[resource_id]
    )

    if before and before["ret"].get("AnomalyMonitors"):
        before = before["ret"]["AnomalyMonitors"][0]
    else:
        before = None

    if not before:
        result["comment"] = (
            f"aws.costexplorer.anomaly_monitor '{name}' already absent",
        )
    elif ctx.get("test", False):
        result[
            "old_state"
        ] = hub.tool.aws.costexplorer.conversion_utils.convert_raw_monitor_to_present(
            ctx, raw_resource=before, idem_resource_name=name
        )
        result["comment"] = (f"Would delete aws.costexplorer.anomaly_monitor {name}",)
        return result
    else:
        result[
            "old_state"
        ] = hub.tool.aws.costexplorer.conversion_utils.convert_raw_monitor_to_present(
            ctx, raw_resource=before, idem_resource_name=name
        )

        ret = await hub.exec.boto3.client.ce.delete_anomaly_monitor(
            ctx, MonitorArn=resource_id
        )
        result["result"] = ret["result"]
        if not result["result"]:
            result["comment"] = ret["comment"]
            return result
        result["comment"] = (f"Deleted aws.costexplorer.anomaly_monitor '{name}'",)

    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


    Returns a list of aws cost anomaly monitors. If a monitor arn or name is specified, the list contains only
    the description of that monitor.


    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: bash

            $ idem describe aws.costexplorer.anomaly_monitor
    """
    result = {}
    ret = await hub.exec.boto3.client.ce.get_anomaly_monitors(ctx)

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

    for monitor in ret["ret"]["AnomalyMonitors"]:
        resource_id = monitor.get("MonitorArn")
        resource_translated = (
            hub.tool.aws.costexplorer.conversion_utils.convert_raw_monitor_to_present(
                ctx, raw_resource=monitor, idem_resource_name=resource_id
            )
        )
        result[resource_id] = {
            "aws.costexplorer.anomaly_monitor.present": [
                {parameter_key: parameter_value}
                for parameter_key, parameter_value in resource_translated.items()
            ]
        }
    return result
