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

from data_syncers import syncer_services, syncer_task_instances
from dbqueries import db_integrations
from exceptions.user_exceptions import InvalidRequest
from integrations import crowdstrike
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


@api_view(['POST'])
def process_incoming_webhook(request, integration_key, conn=None, cache=None):
    '''
    Processes the incoming webhook from CrowdStrike.
    :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)

            meta_body = request.data[crowdstrike.var_meta]
            data_body = request.data[crowdstrike.var_data]
            internal_det_type_id = crowdstrike.get_internal_detection_type_id(meta_body, data_body)

            if internal_det_type_id in [crowdstrike.new_detection_type_id, crowdstrike.reopened_detection_type_id]:

                crd_severity = data_body[crowdstrike.var_data_detections_severity]\
                    if crowdstrike.var_data_detections_severity in data_body else ''
                crd_host_name = data_body[crowdstrike.var_data_devices_hostname]\
                    if crowdstrike.var_data_devices_hostname in data_body else ''
                crd_status = data_body[crowdstrike.var_data_detections_status]\
                    if crowdstrike.var_data_detections_status in data_body else ''
                crd_det_action = data_body[crowdstrike.var_data_detections_action_taken]\
                    if crowdstrike.var_data_detections_action_taken in data_body else ''

                alert_title = ' - '.join(['CrowdStrike', crd_host_name, crd_status, crd_det_action, crd_severity])
                alert_body = str(request.data)
                alert_tags = [x.lstrip().rstrip() for x in data_body[crowdstrike.var_data_devices_tags].split(',')]\
                    if crowdstrike.var_data_devices_tags in data_body else None
                urgency = crowdstrike.severity_map[crd_severity] if crd_severity != '' else constants.critical_urgency

                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, tags=alert_tags
                )
                Router(conn, cache, payload).start()

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

                alert_detection_id = crowdstrike.get_standardized_detection_id_from_event_url(meta_body)
                alert_status = data_body[crowdstrike.var_data_detections_status]\
                    if crowdstrike.var_data_detections_status in data_body else crowdstrike.status_new

                for inst_id, task_id, trig_info in integ_insts:
                    if trig_info is not None:
                        source_payload = trig_info[var_names.source_payload]
                        source_detection_id = crowdstrike.get_standardized_detection_id_from_event_url(
                            source_payload[crowdstrike.var_meta])

                        if alert_detection_id == source_detection_id:

                            if alert_status == crowdstrike.status_closed or alert_status == crowdstrike.status_ignored:
                                event = ResolveEvent(inst_id, current_time, constants.integrations_api)
                                syncer_task_instances.resolve(conn, cache, event, org_id, is_sys_action=True)
                            else:
                                logging.error('CrowdStrike: Unknown alert status received - ' + alert_status)

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