#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

DOCUMENTATION = r"""
---
module: cloudwatchlogs_log_group_metric_filter
version_added: 5.0.0
author:
  - "Markus Bergholz (@markuman)"
short_description: Manage CloudWatch log group metric filter
description:
  - Create, modify and delete CloudWatch log group metric filter.
  - CloudWatch log group metric filter can be use with M(community.aws.ec2_metric_alarm).
  - This module was originally added to C(community.aws) in release 1.0.0.
options:
    state:
      description:
        - Whether the rule is present or absent.
      choices: ["present", "absent"]
      required: true
      type: str
    log_group_name:
      description:
        - The name of the log group where the metric filter is applied on.
      required: true
      type: str
    filter_name:
      description:
        - A name for the metric filter you create.
      required: true
      type: str
    filter_pattern:
      description:
        - A filter pattern for extracting metric data out of ingested log events. Required when I(state=present).
      type: str
    metric_transformation:
      description:
        - A collection of information that defines how metric data gets emitted. Required when I(state=present).
      type: dict
      suboptions:
        metric_name:
          description:
            - The name of the cloudWatch metric.
          type: str
        metric_namespace:
          description:
            - The namespace of the cloudWatch metric.
          type: str
        metric_value:
          description:
            - The value to publish to the cloudWatch metric when a filter pattern matches a log event.
          type: str
        default_value:
          description:
            - The value to emit when a filter pattern does not match a log event.
          type: float
extends_documentation_fragment:
  - amazon.aws.common.modules
  - amazon.aws.region.modules
  - amazon.aws.boto3
"""

EXAMPLES = r"""
- name: set metric filter on log group /fluentd/testcase
  amazon.aws.cloudwatchlogs_log_group_metric_filter:
    log_group_name: /fluentd/testcase
    filter_name: BoxFreeStorage
    filter_pattern: '{($.value = *) && ($.hostname = "box")}'
    state: present
    metric_transformation:
        metric_name: box_free_space
        metric_namespace: fluentd_metrics
        metric_value: "$.value"

- name: delete metric filter on log group /fluentd/testcase
  amazon.aws.cloudwatchlogs_log_group_metric_filter:
    log_group_name: /fluentd/testcase
    filter_name: BoxFreeStorage
    state: absent
"""

RETURN = r"""
metric_filters:
    description: Return the origin response value
    returned: success
    type: list
    sample: [
        {
            "default_value": 3.1415,
            "metric_name": "box_free_space",
            "metric_namespace": "made_with_ansible",
            "metric_value": "$.value"
        }
    ]
"""

from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict

from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule


def metricTransformationHandler(metricTransformations, originMetricTransformations=None):
    if originMetricTransformations:
        change = False
        originMetricTransformations = camel_dict_to_snake_dict(originMetricTransformations)
        for item in ["default_value", "metric_name", "metric_namespace", "metric_value"]:
            if metricTransformations.get(item) != originMetricTransformations.get(item):
                change = True
    else:
        change = True

    defaultValue = metricTransformations.get("default_value")
    if isinstance(defaultValue, int) or isinstance(defaultValue, float):
        retval = [
            {
                "metricName": metricTransformations.get("metric_name"),
                "metricNamespace": metricTransformations.get("metric_namespace"),
                "metricValue": metricTransformations.get("metric_value"),
                "defaultValue": defaultValue,
            }
        ]
    else:
        retval = [
            {
                "metricName": metricTransformations.get("metric_name"),
                "metricNamespace": metricTransformations.get("metric_namespace"),
                "metricValue": metricTransformations.get("metric_value"),
            }
        ]

    return retval, change


def main():
    arg_spec = dict(
        state=dict(type="str", required=True, choices=["present", "absent"]),
        log_group_name=dict(type="str", required=True),
        filter_name=dict(type="str", required=True),
        filter_pattern=dict(type="str"),
        metric_transformation=dict(
            type="dict",
            options=dict(
                metric_name=dict(type="str"),
                metric_namespace=dict(type="str"),
                metric_value=dict(type="str"),
                default_value=dict(type="float"),
            ),
        ),
    )

    module = AnsibleAWSModule(
        argument_spec=arg_spec,
        supports_check_mode=True,
        required_if=[("state", "present", ["metric_transformation", "filter_pattern"])],
    )

    log_group_name = module.params.get("log_group_name")
    filter_name = module.params.get("filter_name")
    filter_pattern = module.params.get("filter_pattern")
    metric_transformation = module.params.get("metric_transformation")
    state = module.params.get("state")

    cwl = module.client("logs")

    # check if metric filter exists
    response = cwl.describe_metric_filters(logGroupName=log_group_name, filterNamePrefix=filter_name)

    if len(response.get("metricFilters")) == 1:
        originMetricTransformations = response.get("metricFilters")[0].get("metricTransformations")[0]
        originFilterPattern = response.get("metricFilters")[0].get("filterPattern")
    else:
        originMetricTransformations = None
        originFilterPattern = None
    change = False
    metricTransformation = None

    if state == "absent" and originMetricTransformations:
        if not module.check_mode:
            response = cwl.delete_metric_filter(logGroupName=log_group_name, filterName=filter_name)
        change = True
        metricTransformation = [camel_dict_to_snake_dict(item) for item in [originMetricTransformations]]

    elif state == "present":
        metricTransformation, change = metricTransformationHandler(
            metricTransformations=metric_transformation, originMetricTransformations=originMetricTransformations
        )

        change = change or filter_pattern != originFilterPattern

        if change:
            if not module.check_mode:
                response = cwl.put_metric_filter(
                    logGroupName=log_group_name,
                    filterName=filter_name,
                    filterPattern=filter_pattern,
                    metricTransformations=metricTransformation,
                )

        metricTransformation = [camel_dict_to_snake_dict(item) for item in metricTransformation]

    module.exit_json(changed=change, metric_filters=metricTransformation)


if __name__ == "__main__":
    main()
