# By: Riasat Ullah
# This file contains Logic Monitor integration related views.

from data_syncers import syncer_services, syncer_task_instances
from dbqueries import db_integrations
from dbqueries.integrations import db_logic_monitor
from exceptions.user_exceptions import InvalidRequest, UnauthorizedRequest
from integrations import logic_monitor
from modules.router import Router
from objects.events import AcknowledgeEvent, CustomActionEvent, ResolveEvent, UrgencyAmendmentEvent
from objects.task_payload import TaskPayload
from rest_framework.decorators import api_view
from rest_framework.response import Response
from translators import label_translator as _lt
from utils import constants, errors, info, integration_type_names as intt, key_manager, logging, times, tokenizer, \
    var_names
from utils.db_connection import CACHE_CLIENT, CONN_POOL
from validations import request_validator
import configuration
import jwt


@api_view(['POST'])
def update_logic_monitor_account_info(request, conn=None):
    '''
    Updates the credentials of a LogicMonitor integration. These credentials are used to make API calls to LogicMonitor
    and sync up actions from TaskCall in LogicMonitor.
    :param request: Http request
    :param conn: db connection
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.service_ref_id, var_names.integration_key,
                           var_names.vendor_endpoint_name, var_names.secret_token]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            current_time = times.get_current_timestamp()
            success = db_logic_monitor.update_logic_monitor_account(
                conn, current_time, org_id, request.data[var_names.service_ref_id],
                request.data[var_names.integration_key], request.data[var_names.vendor_endpoint_name],
                request.data[var_names.secret_token]
            )
            return Response(success)

        except InvalidRequest as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def process_incoming_webhook(request, integration_key, conn=None, cache=None):
    '''
    Processes the incoming webhook from Logic Monitor.
    :param request: Http request
    :param integration_key: integration key passed in the url
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    logging.info(request.data)
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache

            lgm_host = request.data[logic_monitor.var_host]
            lgm_data_source = request.data[logic_monitor.var_data_source]
            lgm_data_point = request.data[logic_monitor.var_data_point]
            lgm_value = request.data[logic_monitor.var_value]
            lgm_agent_description = request.data[logic_monitor.var_agent_description]
            lgm_alert_id = request.data[logic_monitor.var_alert_id]
            lgm_alert_type = request.data[logic_monitor.var_alert_type]
            lgm_alert_status = request.data[logic_monitor.var_alert_status]
            lgm_level = request.data[logic_monitor.var_level]
            lgm_internal_id = request.data[logic_monitor.var_internal_id]\
                if logic_monitor.var_internal_id in request.data else None
            dedup_key = request.data[var_names.dedup_key] if var_names.dedup_key in request.data else None

            alert_body = request.data[logic_monitor.var_message] + '\n\n' + str(request.data)
            urgency = logic_monitor.severity_map[lgm_level]\
                if lgm_level in logic_monitor.severity_map else constants.critical_urgency

            # try to find the alert title and the body
            ati_list = []
            if lgm_agent_description is not None and lgm_agent_description != '':
                ati_list.append(lgm_agent_description)
            if lgm_host is not None and lgm_host != '':
                ati_list.append(lgm_host)
            if lgm_data_source is not None and lgm_data_source != '':
                ati_list.append(lgm_data_source)
            if lgm_data_point is not None and lgm_data_point != '':
                ati_list.append(lgm_data_point)
            if lgm_value is not None and lgm_value != '':
                ati_list.append(lgm_value)

            if len(ati_list) > 0:
                alert_title = '(' + lgm_alert_type + ') ' + ' - '.join(ati_list)
            else:
                alert_title = '(' + lgm_alert_type + ') ' + logic_monitor.general_alert_name

            current_time = times.get_current_timestamp()
            org_id, org_perm, serv_id, integ_id, integ_type_id, integ_details = \
                db_integrations.get_integration_details(conn, current_time, integration_key, intt.logic_monitor)

            integ_insts = db_integrations.get_integration_open_instances_trigger_info(
                conn, current_time, org_id, serv_id, integ_id)

            match_count = 0
            for inst_id, task_id, trig_info in integ_insts:
                if trig_info is not None:
                    source_payload = trig_info[var_names.source_payload]

                    if source_payload[logic_monitor.var_alert_id] == lgm_alert_id and \
                            source_payload[logic_monitor.var_alert_type] == lgm_alert_type:
                        match_count += 1

                        if lgm_alert_status == logic_monitor.ack:
                            event = AcknowledgeEvent(inst_id, current_time, constants.integrations_api, None)
                            syncer_task_instances.acknowledge(conn, cache, event, org_id, is_sys_action=True)

                        elif lgm_alert_status == logic_monitor.clear:
                            event = ResolveEvent(inst_id, current_time, constants.integrations_api)
                            syncer_task_instances.resolve(conn, cache, event, org_id, is_sys_action=True)

                        elif lgm_alert_status == logic_monitor.update and\
                                source_payload[logic_monitor.var_level] == lgm_level:
                            event = UrgencyAmendmentEvent(inst_id, current_time, constants.integrations_api, urgency)
                            syncer_task_instances.amend_urgency(conn, cache, [event], org_id, is_sys_action=True)

                        else:
                            # Group the alert if one already exists
                            payload = TaskPayload(
                                current_time, org_id, current_time.date(), alert_title, configuration.standard_timezone,
                                current_time.time(), text_msg=alert_body, urgency_level=urgency,
                                trigger_method=constants.integrations_api, trigger_info=request.data,
                                integration_id=integ_id, integration_key=integration_key, service_id=serv_id,
                                instantiate=False, alert=False, related_task_id=task_id,
                                task_status=constants.grouped_state
                            )
                            Router(conn, cache, payload).start()

            if match_count == 0 and lgm_alert_status != logic_monitor.clear:
                dedup_key = key_manager.generate_alphanumeric_key(30)
                msg = {var_names.dedup_key: dedup_key}

                payload = TaskPayload(
                    current_time, org_id, current_time.date(), alert_title, configuration.standard_timezone,
                    current_time.time(), text_msg=alert_body, urgency_level=urgency,
                    trigger_method=constants.integrations_api, trigger_info=request.data, integration_id=integ_id,
                    integration_key=integration_key, service_id=serv_id, dedup_key=dedup_key
                )
                inst_id = Router(conn, cache, payload).run()

                if inst_id is not None:
                    event = CustomActionEvent(
                        inst_id, current_time, constants.internal, integration_id=integ_id,
                        integration_type_id=integ_type_id, vendor_id=str(lgm_alert_id), vendor_url=None, is_synced=True
                    )
                    syncer_task_instances.execute_custom_action(conn, cache, event, org_id=org_id, is_sys_action=True)
            else:
                msg = info.msg_internal_success
            return Response(msg)
        except InvalidRequest as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_invalid_request, lang), status=400)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)
