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

from data_syncers import syncer_services
from dbqueries import db_integrations
from dbqueries.integrations import db_google_chat
from exceptions.user_exceptions import UnauthorizedRequest
from integrations import google_chat
from modules.router import Router
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 cdn_enablers, constants, errors, info, integration_type_names as intt, logging, permissions,\
    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 authorize_google_chat_integration(request, conn=None):
    '''
    Authorizes a Google Chat integration. After the app installation on Google Chat, users are required to
    authorize the integration to allow us to map it to an organization and service. The users are provided with a
    button which directs them to taskcall web. From there the request is made to this view.
    :param request: Http request
    :param conn: db conn
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.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)

            if permissions.is_user_admin(user_perm):
                current_time = times.get_current_timestamp()
                token_details = db_integrations.get_temporary_verification_token_details(
                    conn, current_time, request.data[var_names.token], intt.google_chat)
                if token_details is not None:
                    return Response(token_details)
                else:
                    return Response(_lt.get_label(errors.err_unknown_resource, lang), status=400)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        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 confirm_google_chat_integration(request, conn=None):
    '''
    Confirms that a Google Chat authorization has been confirmed. This will invalidate the temporary token
    that was issued for the authorization process.
    :param request: Http request
    :param conn: db conn
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.token, var_names.channel_id]
        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)

            if permissions.is_user_admin(user_perm):
                current_time = times.get_current_timestamp()
                db_integrations.confirm_temporary_token_verification(
                    conn, current_time, request.data[var_names.token], intt.google_chat)

                # send a note to the Google Chat space saying that the authorization has completed
                message = google_chat.get_simple_text_reply(
                    _lt.get_label(info.msg_google_chat_authorization_succeeded, lang)
                )
                google_chat.create_google_chat_message(request.data[var_names.channel_id], message)

                return Response(_lt.get_label(info.msg_success, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        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_google_chat_actions(request, conn=None, cache=None):
    '''
    Handles user actions taken on messages from TaskCall's Google Chat app.
    Calls to this function come from requests made directly from Google Chat.
    :param request: Http request
    :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

            # parse through the payload
            event_type = request.data['type']
            domain_id = request.data['user']['domainId']
            space_name = request.data['space']['name']
            gc_user_name = request.data['user']['name']
            current_time = times.get_current_timestamp()

            # Installation
            if event_type == google_chat.payload_type_added_to_space:

                temporary_token = google_chat.get_google_chat_authorization_verification_token(
                    conn, domain_id, space_name)
                if temporary_token is None:
                    return Response(google_chat.get_simple_text_reply(
                        _lt.get_label(errors.err_system_error, lang)
                    ))
                else:
                    return Response(google_chat.get_google_chat_welcome_card(temporary_token))

            # Uninstallation
            elif event_type == google_chat.payload_type_remove_from_space:
                org_id, service_id, integ_id, external_info = db_google_chat.get_google_chat_integration_details(
                    conn, current_time, domain_id, space_name)

                if service_id is not None and external_info is not None and var_names.users in external_info \
                        and gc_user_name in external_info[var_names.users]:
                    taskcall_user_id = external_info[var_names.users][gc_user_name]
                    integ_key = db_integrations.get_integration_key_from_id(conn, current_time, integ_id)

                    cdn_key_info = (
                        intt.google_chat, cdn_enablers.create_cdn_cache_key(intt.google_chat, domain_id, space_name)
                    )

                    syncer_services.delete_service_integration(
                        conn, cache, current_time, org_id, taskcall_user_id, integ_key,
                        check_adv_perm=False, has_comp_perm=False, has_team_perm=False, cdn_key_info=cdn_key_info
                    )

                return Response(google_chat.get_simple_text_reply(_lt.get_label(info.msg_success, lang)))

            # Message
            elif event_type == google_chat.payload_type_message:
                message = request.data['message']
                if 'text' in message:
                    text_list = message['text'].split(' ')

                    if len(text_list) < 1:
                        err = _lt.get_label(errors.err_unknown_command, lang)
                        logging.error(err)
                        return Response(google_chat.get_simple_text_reply(err))

                    command = text_list[0]
                    if command not in google_chat.gc_valid_commands:
                        err = _lt.get_label(errors.err_unknown_command, lang)
                        logging.error(err)
                        return Response(google_chat.get_simple_text_reply(err))

                    else:
                        if command == google_chat.gc_request_authorization:
                            existing_integ = db_google_chat.get_google_chat_integration_details(
                                conn, current_time, domain_id, space_name)
                            if existing_integ[0] is None:
                                temporary_token = google_chat.get_google_chat_authorization_verification_token(
                                    conn, domain_id, space_name)
                                if temporary_token is None:
                                    return Response(google_chat.get_simple_text_reply(
                                        _lt.get_label(errors.err_system_error, lang)
                                    ))
                                else:
                                    return Response(google_chat.get_google_chat_welcome_card(temporary_token))
                            else:
                                return Response(google_chat.get_simple_text_reply(
                                    _lt.get_label(info.msg_google_chat_integration_exists, lang)),
                                )

                        elif command == google_chat.gc_verify_user_cmd:
                            if len(text_list) != 2:
                                return Response(google_chat.get_simple_text_reply(
                                    _lt.get_label(errors.err_invalid_request, lang)))
                            else:
                                taskcall_pref_name = text_list[1]
                                resp = google_chat.verify_google_chat_user(conn, domain_id, space_name, gc_user_name,
                                                                           taskcall_pref_name, lang)
                                return Response(resp)

                        elif command == google_chat.gc_remove_user_cmd:
                            resp = google_chat.remove_google_chat_user(conn, domain_id, space_name, gc_user_name, lang)
                            return Response(resp)

                        elif command == google_chat.gc_get_user_cmd:
                            resp = google_chat.get_google_chat_user_info(conn, domain_id, space_name, gc_user_name,
                                                                         lang)
                            return Response(resp)

                        elif command == google_chat.gc_create_incident_cmd:
                            if google_chat.is_request_dialog_event(request):
                                org_id = db_google_chat.get_google_chat_integration_details(
                                    conn, current_time, domain_id, space_name)[0]

                                resp = google_chat.get_new_incident_dialog(conn, org_id, lang)
                                return Response(resp)
                        else:
                            return Response(google_chat.get_simple_text_reply(
                                _lt.get_label(info.msg_google_chat_help, lang))
                            )

            elif event_type == google_chat.payload_type_card_clicked:
                gc_display_name = request.data['user']['displayName']
                invoked_function = request.data['common']['invokedFunction']

                if invoked_function == google_chat.func_create_incident:
                    if google_chat.is_submit_dialog_event(request):

                        org_id, service_id, integ_id, external_info = \
                            db_google_chat.get_google_chat_integration_details(
                                conn, current_time, domain_id, space_name)

                        if service_id is not None and external_info is not None and var_names.users in external_info \
                                and gc_user_name in external_info[var_names.users]:

                            form_inputs = request.data['common']['formInputs']
                            incident_title = form_inputs[var_names.task_title]['stringInputs']['value'][0]
                            service_ref_id = form_inputs[var_names.service_ref_id]['stringInputs']['value'][0]
                            urgency_level = int(form_inputs[var_names.urgency_level]['stringInputs']['value'][0])
                            text_msg = form_inputs[var_names.text_msg]['stringInputs']['value'][0]

                            try:
                                payload = TaskPayload(current_time, org_id, current_time.date(), incident_title,
                                                      configuration.standard_timezone, current_time.time(),
                                                      text_msg=text_msg, trigger_method=constants.integrations_api,
                                                      urgency_level=urgency_level, service_ref_id=service_ref_id,
                                                      integration_id=integ_id)

                                Router(conn, cache, payload).start()

                                google_chat.create_google_chat_message(
                                    space_name, google_chat.get_simple_text_reply(
                                        _lt.get_label(info.msg_incident_created, lang)
                                    )
                                )

                                return Response(google_chat.get_simple_dialog_reply())
                            except Exception as e:
                                logging.exception(str(e))
                                err = _lt.get_label(errors.err_system_error, lang)

                                google_chat.create_google_chat_message(
                                    space_name, google_chat.get_simple_text_reply(err))

                                return Response(google_chat.get_simple_dialog_reply(err))
                        else:
                            err = _lt.get_label(info.msg_google_chat_user_unverified_or_integration_missing, lang)

                            google_chat.create_google_chat_message(space_name, google_chat.get_simple_text_reply(err))

                            return Response(google_chat.get_simple_dialog_reply(err))
                else:
                    current_card = request.data['message']['cardsV2']
                    action_value = request.data['common']['parameters']
                    action_message_id = request.data['message']['name']

                    resp = google_chat.process_google_chat_incident_actions(
                        conn, domain_id, space_name, gc_user_name, gc_display_name, action_value,
                        action_message_id, current_card, lang=constants.lang_en
                    )
                    return Response(resp)

            return Response(google_chat.get_simple_text_reply(_lt.get_label(info.msg_success, lang)))
        except KeyError:
            logging.error(errors.err_malicious_source_restriction)
            return Response(_lt.get_label(errors.err_authorization, lang), status=403)
        except Exception as e:
            logging.exception(str(e))
            return Response(google_chat.get_simple_text_reply(_lt.get_label(errors.err_system_error, lang)))
        finally:
            CONN_POOL.put_db_conn(conn)
