# By: Riasat Ullah
# This file contains views related to the Rundeck integration.

from data_syncers import syncer_task_instances
from dbqueries import db_integrations, db_services
from exceptions.user_exceptions import InvalidRequest
from integrations import rundeck
from modules.router import Router
from objects.events import CustomActionEvent, NotateEvent, 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, integration_type_names as intt, key_manager, logging, times
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 incoming webhooks from Rundeck.
    :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)

            exec_id = str(request.data['executionId'])
            alert_title = request.data['execution']['job']['name'] +\
                ' [' + request.data['execution']['project'] + '] - ' + request.data['status']
            alert_status = request.data['status']
            alert_url = request.data['execution']['href']
            alert_description = str(request.data)
            alert_note = request.data['execution']['job']['name'] + ' ' + alert_status + ': ' + alert_url
            urgency = constants.critical_urgency if alert_status == rundeck.sts_failed else constants.high_urgency

            # get the integration details
            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.rundeck)

            synced_insts = db_integrations.get_vendor_synced_open_instance_ids(
                conn, current_time, org_id, integ_id, integ_type_id, exec_id, synced_only=False)

            # Create a new task if it is a new issue.
            if len(synced_insts) == 0:
                payload = TaskPayload(
                    current_time, org_id, current_time.date(), alert_title, configuration.standard_timezone,
                    current_time.time(), text_msg=alert_description, urgency_level=urgency,
                    trigger_method=constants.integrations_api, trigger_info=request.data, integration_id=integ_id,
                    service_id=serv_id, vendor_incident_url=alert_url
                )
                inst_id = Router(conn, cache, payload).run()

                event = CustomActionEvent(inst_id, current_time, constants.rundeck, integration_id=integ_id,
                                          integration_type_id=integ_type_id, vendor_id=exec_id, vendor_url=alert_url,
                                          is_synced=True)

                syncer_task_instances.execute_custom_action(conn, cache, event, org_id=org_id, is_sys_action=True)
            else:
                for inst_id, task_id, in_sync in synced_insts:
                    event = NotateEvent(inst_id, current_time, constants.rundeck, None, alert_note)
                    syncer_task_instances.notate(conn, cache, event, org_id, org_perm=org_perm, is_sys_action=True)
                    if in_sync and alert_status == rundeck.sts_succeeded:
                        event = ResolveEvent(inst_id, current_time, constants.integrations_api)
                        syncer_task_instances.resolve(conn, cache, event, org_id, is_sys_action=True)

            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)
