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

hub.exec.boto3.client.ce.create_cost_category_definition
hub.exec.boto3.client.ce.delete_cost_category_definition
hub.exec.boto3.client.ce.describe_cost_category_definition
hub.exec.boto3.client.ce.update_cost_category_definition
"""
import copy
from typing import Any
from typing import Dict
from typing import List

__contracts__ = ["resource"]


async def present(
    hub,
    ctx,
    name: str,
    rules: List[Dict[str, Any]],
    cost_category_name: str,
    rule_version: str,
    resource_id: str = None,
    split_charge_rules: List[Dict[str, Any]] = None,
    default_value: str = None,
    tags: Dict[str, Any] = None,
) -> Dict[str, Any]:
    r"""
    **Autogenerated function**

    Creates a new Cost Category with the requested name and rules.

    Args:
        name(Text): The unique name of the Cost Category.
        rules(List[Dict[str, Any]]): The Cost Category rules used to categorize costs.
        cost_category_name(Text): Name of Cost Category.
        rule_version(Text): The rule schema version in this particular Cost Category.
        resource_id(Text, Optional): Cost Category ARN to identify the resource.
        split_charge_rules(List[Dict[str, Any]], Optional): The split charge rules used to allocate your charges between your Cost Category values.
        default_value(Text, Optional): The default value for the cost category.
        tags (List[Dict[str, Any]], Optional): Each tag consists of a key and a value, and each key must be unique for the resource.

    Request Syntax:
        [monitor-resource-id]:
          aws.costexplorer.cost_category.present:
          - resource_id: 'string'
          - tags: 'dict'
          - cost_category_name: 'string'
          - effective_start: 'string'
          - rules:
                - Rule:
                    Dimensions:
                      Key: 'string'
                      MatchOptions:
                      - EQUALS
                      Values:
                      - 'string'
                  Type: 'string'
                  Value: 'string'
          - split_charge_rules:
                - Method: 'string'
                  Parameters:
                  - Type: 'string'
                    Values:
                    - 'string'
                    - 'string'
                  Source: 'string'
                  Targets:
                  - 'string'
              - processing_status:
                - Component: 'string'
                  Status: 'string'
              - default_value: 'string'

    Returns:
        Dict[str, str]

    Examples:

        .. code-block:: sls

            arn:aws:ce::1234567891012:costcategory/4e9662f0-5533-4fdf-8224-9bb9f82d0a39:
              aws.costexplorer.cost_category.present:
              - resource_id: arn:aws:ce::1234567891012:costcategory/4e9662f0-5533-4fdf-8224-9bb9f82d0a39
              - tags:
                  name: test_category
              - cost_category_name: test_category
              - effective_start: '2022-06-01T00:00:00Z'
              - rule_version: CostCategoryExpression.v1
              - rules:
                - Rule:
                    Dimensions:
                      Key: LINKED_ACCOUNT
                      MatchOptions:
                      - EQUALS
                      Values:
                      - '107488843946'
                  Type: REGULAR
                  Value: Alpha
                - Rule:
                    Dimensions:
                      Key: LINKED_ACCOUNT
                      MatchOptions:
                      - EQUALS
                      Values:
                      - 011922870716
                  Type: REGULAR
                  Value: Beta
                - Rule:
                    Dimensions:
                      Key: LINKED_ACCOUNT
                      MatchOptions:
                      - EQUALS
                      Values:
                      - '332986752459'
                  Type: REGULAR
                  Value: Gamma
              - split_charge_rules:
                - Method: FIXED
                  Parameters:
                  - Type: ALLOCATION_PERCENTAGES
                    Values:
                    - '40'
                    - '60'
                  Source: Alpha
                  Targets:
                  - Beta
                  - Gamma
              - processing_status:
                - Component: COST_EXPLORER
                  Status: PROCESSING
              - default_value: Other

    """
    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.describe_cost_category_definition(
            ctx, CostCategoryArn=resource_id
        )
        if not before["result"]:
            result["result"] = False
            result["comment"] = before["comment"]
            return result

    if before:
        result[
            "old_state"
        ] = await hub.tool.aws.costexplorer.conversion_utils.convert_raw_cost_category_to_present(
            ctx,
            raw_resource=before["ret"]["CostCategory"],
            idem_resource_name=name,
        )
        plan_state = copy.deepcopy(result["old_state"])

        update_ret = await hub.exec.aws.costexplorer.cost_category.update_cost_category_definition(
            ctx,
            before=before["ret"]["CostCategory"],
            rules=rules,
            default_value=default_value,
            split_charge_rules=split_charge_rules,
        )
        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):
            plan_state = update_ret["ret"]

        if tags is not None and tags != result["old_state"].get("tags"):
            # Update tags
            update_ret = await hub.exec.aws.costexplorer.cost_category.update_tags(
                ctx,
                resource_id=resource_id,
                old_tags=hub.tool.aws.tag_utils.convert_tag_dict_to_list(
                    result["old_state"].get("tags")
                ),
                new_tags=hub.tool.aws.tag_utils.convert_tag_dict_to_list(tags),
            )
            result["result"] = result["result"] and update_ret["result"]
            result["comment"] = result["comment"] + update_ret["comment"]
            resource_updated = resource_updated or bool(update_ret["ret"])
            if ctx.get("test", False) and update_ret["ret"] is not None:
                plan_state["tags"] = hub.tool.aws.tag_utils.convert_tag_list_to_dict(
                    update_ret["ret"].get("tags")
                )

        if resource_updated:
            if ctx.get("test", False):
                result["comment"] += hub.tool.aws.comment_utils.would_update_comment(
                    resource_type="aws.costexplorer.cost_category", name=name
                )
            else:
                result["comment"] += hub.tool.aws.comment_utils.update_comment(
                    resource_type="aws.costexplorer.cost_category", name=name
                )
    else:
        if ctx.get("test", False):
            result["new_state"] = hub.tool.aws.test_state_utils.generate_test_state(
                enforced_state={},
                desired_state={
                    "name": name,
                    "cost_category_name": cost_category_name,
                    "rules": rules,
                    "split_charge_rules": split_charge_rules,
                    "default_value": default_value,
                    "tags": tags,
                    "rule_version": rule_version,
                },
            )
            result["comment"] = hub.tool.aws.comment_utils.would_create_comment(
                resource_type="aws.costexplorer.cost_category", name=name
            )
            return result

        ret = await hub.exec.boto3.client.ce.create_cost_category_definition(
            ctx,
            Name=cost_category_name,
            RuleVersion=rule_version,
            Rules=rules,
            DefaultValue=default_value,
            SplitChargeRules=split_charge_rules,
            ResourceTags=hub.tool.aws.tag_utils.convert_tag_dict_to_list(tags),
        )
        result["result"] = ret["result"]
        if not result["result"]:
            result["comment"] = ret["comment"]
            return result
        result["comment"] = hub.tool.aws.comment_utils.create_comment(
            resource_type="aws.costexplorer.cost_category", name=name
        )
        resource_id = ret["ret"]["CostCategoryArn"]

    try:
        if ctx.get("test", False):
            result["new_state"] = plan_state
        elif (not before) or resource_updated:
            after = await hub.exec.boto3.client.ce.describe_cost_category_definition(
                ctx, CostCategoryArn=resource_id
            )
            if not after["result"]:
                result["result"] = False
                result["comment"] = after["comment"]
                return result
            result[
                "new_state"
            ] = await hub.tool.aws.costexplorer.conversion_utils.convert_raw_cost_category_to_present(
                ctx,
                raw_resource=after["ret"]["CostCategory"],
                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 = None) -> Dict[str, Any]:
    """
    **Autogenerated function**

    Deletes a cost category.

    Args:
        name(Text): An Idem name of the resource.
        resource_id(Text, Optional): Cost Category ARN to identify the resource. Idem automatically considers this resource being absent if this field is not specified.

    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: sls

            resource_is_absent:
              aws.costexplorer.cost_category.absent:
                - name: value
                - resource_id: value
    """
    result = dict(comment=(), old_state=None, new_state=None, name=name, result=True)

    if not resource_id:
        result["comment"] = hub.tool.aws.comment_utils.already_absent_comment(
            resource_type="aws.costexplorer.cost_category", name=name
        )
        return result

    before = await hub.exec.boto3.client.ce.describe_cost_category_definition(
        ctx, CostCategoryArn=resource_id
    )

    if not before:
        result["comment"] = hub.tool.aws.comment_utils.already_absent_comment(
            resource_type="aws.costexplorer.cost_category", name=name
        )
    elif ctx.get("test", False):
        result[
            "old_state"
        ] = await hub.tool.aws.costexplorer.conversion_utils.convert_raw_cost_category_to_present(
            ctx, raw_resource=before["ret"]["CostCategory"], idem_resource_name=name
        )
        result["comment"] = hub.tool.aws.comment_utils.would_delete_comment(
            resource_type="aws.costexplorer.cost_category", name=name
        )
        return result
    else:
        result[
            "old_state"
        ] = await hub.tool.aws.costexplorer.conversion_utils.convert_raw_cost_category_to_present(
            ctx, raw_resource=before["ret"]["CostCategory"], idem_resource_name=name
        )
        ret = await hub.exec.boto3.client.ce.delete_cost_category_definition(
            ctx, CostCategoryArn=resource_id
        )
        result["result"] = ret["result"]
        if not result["result"]:
            result["comment"] = ret["comment"]
            result["result"] = False
            return result
        result["comment"] = hub.tool.aws.comment_utils.delete_comment(
            resource_type="aws.costexplorer.cost_category", name=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 categories.


    Returns:
        Dict[str, Any]

    Examples:

        .. code-block:: bash

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

    if not ret["result"]:
        hub.log.debug(f"Could not list Cost Category Definitions {ret['comment']}")
        return {}

    for costcategory in ret["ret"]["CostCategoryReferences"]:
        resource_id = costcategory.get("CostCategoryArn")
        ret = await hub.exec.boto3.client.ce.describe_cost_category_definition(
            ctx, CostCategoryArn=resource_id
        )

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

        resource_translated = await hub.tool.aws.costexplorer.conversion_utils.convert_raw_cost_category_to_present(
            ctx,
            raw_resource=ret["ret"].get("CostCategory"),
            idem_resource_name=resource_id,
        )
        result[resource_id] = {
            "aws.costexplorer.cost_category.present": [
                {parameter_key: parameter_value}
                for parameter_key, parameter_value in resource_translated.items()
            ]
        }
    return result
