# By: Riasat Ullah
# This file contains all Microsoft Azure integration related views.

from data_syncers import syncer_services, syncer_task_instances
from dbqueries import db_integrations
from exceptions.user_exceptions import InvalidRequest, UnauthorizedRequest
from integrations import azure
from modules.router import Router
from objects.events import ResolveEvent
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, key_manager, logging, times, var_names
from utils.db_connection import CACHE_CLIENT, CONN_POOL
from validations import request_validator
import configuration
import jwt


@api_view(['POST'])
def process_azure_alerts(request, integration_key, conn=None, cache=None):
    '''
    Processes incoming webhook from Microsoft Azure.
    :param request: Http request
    :param integration_key: integration key passed in the url
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    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

            unmasked_integ_key = key_manager.unmask_reference_key(integration_key)
            current_time = times.get_current_timestamp()
            integ_id, serv_id, org_id = syncer_services.get_integration_key_details(
                conn, cache, current_time, unmasked_integ_key)

            schema_id = request.data[azure.var_schema_id]
            data = request.data[azure.var_data]
            essentials = data[azure.var_essentials]
            alert_context = data[azure.var_alert_context]

            if schema_id not in azure.acceptable_schema:
                err = 'Schema (' + schema_id + ') not recognized. Expecting - Common Alert Schema.'
                logging.error(err)
                return Response(err, status=400)

            # alert values
            alert_id = essentials[azure.var_ess_origin_alert_id]
            alert_rule = essentials[azure.var_ess_alert_rule]
            description = essentials[azure.var_ess_description]
            monitor_condition = essentials[azure.var_ess_monitor_condition]
            monitoring_service = essentials[azure.var_ess_monitoring_service]
            signal_type = essentials[azure.var_ess_signal_type]
            urgency = azure.azure_urgency_map[essentials[azure.var_ess_severity]]

            body = description + '\n\n' + str(alert_context)

            if monitor_condition == azure.fired_monitor_condition:
                payload = TaskPayload(
                    current_time, org_id, current_time.date(), alert_rule, configuration.standard_timezone,
                    current_time.time(), text_msg=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
                )
                Router(conn, cache, payload).start()
            elif monitor_condition == azure.resolved_monitor_condition:
                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:
                    trig_essentials = trig_info[var_names.source_payload][azure.var_data][azure.var_essentials]
                    trig_alert_id = trig_essentials[azure.var_ess_origin_alert_id]
                    trig_monitoring_service = trig_essentials[azure.var_ess_monitoring_service]
                    trig_signal_type = trig_essentials[azure.var_ess_signal_type]

                    if trig_info is not None and trig_alert_id == alert_id and\
                            trig_monitoring_service == monitoring_service and trig_signal_type == signal_type:
                        match_count += 1
                        event = ResolveEvent(inst_id, current_time, constants.integrations_api)
                        syncer_task_instances.resolve(conn, cache, event, org_id, is_sys_action=True)

                if match_count == 0:
                    logging.warning(errors.err_unknown_resource)
            else:
                err = 'Unknown monitor condition received from Azure - ' + monitor_condition
                logging.error(err)
                return Response(err, status=400)

            return Response(info.msg_internal_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)
