# By: Riasat Ullah
# This file contains code for handling Freshdesk integration related views.

from constants import api_paths, component_names as cnm, label_names as lnm, pages, static_vars, var_names
from context_manager import integrations_context
from django.http import JsonResponse
from django.shortcuts import redirect, render
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from integrations import freshdesk
from taskcallweb import settings
from translators import label_translator as lt
from utils import helpers, logging
from validations import request_validator
import datetime
import json


@require_http_methods(['POST'])
def get_freshdesk_account_info(request):
    '''
    Get the domain and api key of the Freshdesk account associated to an integration.
    This will be displayed on the Freshdesk integration modal.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            body = json.loads(request.body.decode())
            if settings.TEST_MODE:
                return JsonResponse([{var_names.vendor_endpoint_name: 'taskcallapp.freshdesk.com',
                                      var_names.secret_token: 'api_key_xx'}], safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.integrations_freshdesk_account, body,
                                                          request, lang=lang)
                return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def update_freshdesk_account_info(request):
    '''
    Updates the Freshdesk domain and api key stored for a Freshdesk integration.
    :param request: Http request
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            body = json.loads(request.body.decode())
            if settings.TEST_MODE:
                return JsonResponse('Success', safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.integrations_freshdesk_account_update, body,
                                                          request, lang=lang)
                return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def get_freshdesk_ticket_types(request):
    '''
    Get the ticket types allowed on a Freshdesk account. This will be displayed on the Freshdesk integration modal.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            body = json.loads(request.body.decode())
            if settings.TEST_MODE:
                return JsonResponse([['ACSC', 'ACSC'], ['Surveys', 'Surveys'],
                                     ['Development', 'Development'], ['Threat Alert', 'Threat Alert']], safe=False)
            else:
                status, output = freshdesk.get_freshdesk_ticket_types(body[var_names.domain], body[var_names.key])
                return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['GET', 'POST'])
def login_freshdesk_user(request):
    '''
    Log in a Freshdesk user.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'GET':
        lang = request_validator.get_user_language(request)
        if 'state' not in request.GET and 'domain' not in request.GET:
            logging.error('Expected parameter "state" or "domain" is missing.'
                          'Denying access to Freshdesk user log in. Redirecting to login page.')
            context = {
                var_names.error_code: 403,
                var_names.error_message: lt.get_label(lnm.err_invalid_request, lang)
            }
            return render(request, pages.error_page, context=context)
        else:
            # Make sure the request originates from Freshdesk.
            # Get the Origin and state, and save them in the session, so they can be accessed from the POST request.
            request.session[freshdesk.str_freshdesk_ticket_id] = request.GET.get('state')
            request.session[freshdesk.str_freshdesk_origin] = request.GET.get('domain')

            if request_validator.user_in_session(request):
                nav_bar_components = request_validator.get_nav_bar_components(request)
                has_incident_view_perm, has_incident_edit_perm = request_validator.get_session_permission(
                    request, cnm.dis_com_incidents, nav_bar_components
                )
                has_dashboard_view_perm, has_dashboard_edit_perm = request_validator.get_session_permission(
                    request, cnm.dis_com_status_dashboard, nav_bar_components
                )

                if cnm.feat_integrations_customer_service not in request_validator.get_component_features(request):
                    context = {
                        var_names.error_code: 403,
                        var_names.error_message: lt.get_label(lnm.err_freshdesk_organization_permission, lang)
                    }
                    return render(request, pages.error_page, context=context)

                if not has_incident_edit_perm or not has_dashboard_view_perm:
                    context = {
                        var_names.error_code: 403,
                        var_names.error_message: lt.get_label(lnm.err_freshdesk_user_permission, lang)
                    }
                    return render(request, pages.error_page, context=context)

                context = integrations_context.get_freshdesk_user_login_context(lang)
                resp = render(request, pages.integrations_freshdesk_user_login, context=context)
                resp[static_vars.cross_origin_opener_policy] = static_vars.unsafe_none
                return resp
            else:
                helpers.set_session_redirect_page(request)
                return redirect(pages.login_url)

    elif request.method == 'POST':
        lang = request_validator.get_user_language(request)
        ajax_body = json.loads(request.body.decode())

        if request_validator.user_in_session(request) and var_names.is_enabled in ajax_body:
            # retrieve the Freshdesk ticket id and origin domain from the session
            ticket_id = request.session[freshdesk.str_freshdesk_ticket_id]
            origin = request.session[freshdesk.str_freshdesk_origin]
            url_to_send = freshdesk.freshdesk_ticket_path_format.format(origin, ticket_id)

            # Deny login if the user does not explicitly allow it
            if not ajax_body[var_names.is_enabled]:
                return JsonResponse(url_to_send, safe=False)

            if settings.TEST_MODE:
                status, output = 200, {
                    var_names.access_token: 'access_token',
                    var_names.refresh_token: 'refresh_token',
                    var_names.display_name: 'Adam Smith',
                    var_names.language: 'en',
                    var_names.expires_on: datetime.datetime.now() + datetime.timedelta(days=2),
                    var_names.valid_end: datetime.datetime.now() + datetime.timedelta(days=10)
                }
            else:
                body = {var_names.domain: origin}
                status, output = helpers.post_api_request(api_paths.integrations_freshdesk_login, body,
                                                          request, lang=lang)

            if status == 200 and freshdesk.str_freshdesk_origin in request.session\
                    and freshdesk.str_freshdesk_ticket_id in request.session:

                # Delete the session data that was stored
                del request.session[freshdesk.str_freshdesk_ticket_id]
                del request.session[freshdesk.str_freshdesk_origin]

                # redirect the user to Freshdesk without completing the JSON request sent from the web app
                resp = JsonResponse(url_to_send, safe=False)
                resp.set_cookie(freshdesk.str_freshdesk_access_token, output[var_names.access_token],
                                expires=output[var_names.expires_on], secure=True, httponly=True, samesite='None')
                resp.set_cookie(freshdesk.str_freshdesk_refresh_token, output[var_names.refresh_token],
                                expires=output[var_names.valid_end], secure=True, httponly=True, samesite='None')
                resp.set_cookie(freshdesk.str_freshdesk_display_name, output[var_names.display_name],
                                expires=output[var_names.valid_end], secure=True, httponly=True, samesite='None')
                return resp
            else:
                err = output if status != 200 else lt.get_label(lnm.err_processing_failed, lang)
                return JsonResponse(err, status=400, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['GET'])
def logout_freshdesk_user(request):
    '''
    Log out a Freshdesk user.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'GET':
        lang = request_validator.get_user_language(request)
        if 'state' not in request.GET and 'domain' not in request.GET:
            logging.error('Expected parameter "state" or "domain" is missing.'
                          'Denying Freshdesk user logout. Redirecting to login page.')
            context = {
                var_names.error_code: 403,
                var_names.error_message: lt.get_label(lnm.err_invalid_request, lang)
            }
            return render(request, pages.error_page, context=context)
        else:
            # Make sure the request originates from Freshdesk.
            # Get the Origin and state, so that the user can be redirected to the same page they were sent from.
            ticket_id = request.GET.get('state')
            origin = request.GET.get('domain')

            access_token = None
            if freshdesk.str_freshdesk_access_token in request.COOKIES:
                access_token = request.COOKIES.get(freshdesk.str_freshdesk_access_token)

            url_to_send = freshdesk.freshdesk_ticket_path_format.format(origin, ticket_id)
            resp = redirect(url_to_send)
            resp.delete_cookie(freshdesk.str_freshdesk_access_token)
            resp.delete_cookie(freshdesk.str_freshdesk_refresh_token)
            resp.delete_cookie(freshdesk.str_freshdesk_display_name)

            if access_token is not None and not settings.TEST_MODE:
                helpers.post_api_request(api_paths.integrations_freshdesk_logout, dict(), None, lang=lang)
            resp[static_vars.cross_origin_opener_policy] = static_vars.unsafe_none
            return resp


@xframe_options_exempt
@require_http_methods(['GET'])
def get_freshdesk_taskcall_token(request):
    '''
    Get the access token for a Freshdesk user if they are logged in. Otherwise, send 'undefined' as the value.
    :param request: Http request
    :return: Http response
    '''
    if request.method == 'GET':
        access_token, token_expiry, display_name = freshdesk.get_token_details_for_freshdesk(request)
        context = {
            var_names.token: access_token if access_token is not None else freshdesk.str_undefined,
            var_names.display_name: display_name if display_name is not None else ''
        }
        resp = render(request, pages.integrations_freshdesk_get_token, context=context)
        if access_token is not None:
            resp.set_cookie(freshdesk.str_freshdesk_access_token, access_token, token_expiry,
                            secure=True, httponly=True, samesite='None')

        return resp


@csrf_exempt
@require_http_methods(['POST'])
def process_ticket_actions(request, action):
    '''
    Process the actions triggered from the Freshdesk TaskCall app.
    :param request: Http request
    :param action: the type of action to perform
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        access_token = helpers.extract_token_from_header(request)
        body = json.loads(request.body.decode())
        url = None

        if action == freshdesk.cmd_acknowledge:
            body[var_names.access_method] = static_vars.integrations_api
            url = api_paths.incidents_acknowledge

        elif action == freshdesk.cmd_add_responders:
            body[var_names.access_method] = static_vars.integrations_api
            url = api_paths.incidents_add_responders

        elif action == freshdesk.cmd_create_incident:
            url = api_paths.integrations_freshdesk_create_incident

        elif action == freshdesk.cmd_link:
            body[var_names.integration_type] = static_vars.integ_type_freshdesk
            url = api_paths.incidents_link

        elif action == freshdesk.cmd_linked_incidents:
            body[var_names.integration_type] = static_vars.integ_type_freshdesk
            url = api_paths.incidents_linked_incidents

        elif action == freshdesk.cmd_list_policies:
            body = {var_names.data_type: [var_names.policies, var_names.users]}
            url = api_paths.org_list_maker

        elif action == freshdesk.cmd_list_response_sets:
            body = {var_names.data_type: [var_names.response_sets]}
            url = api_paths.org_list_maker

        elif action == freshdesk.cmd_list_services:
            body = {var_names.data_type: [var_names.services]}
            url = api_paths.org_list_maker

        elif action == freshdesk.cmd_notate:
            body[var_names.access_method] = static_vars.integrations_api
            url = api_paths.incidents_notate

        elif action == freshdesk.cmd_reassign:
            body[var_names.access_method] = static_vars.integrations_api
            url = api_paths.incidents_reassign

        elif action == freshdesk.cmd_resolve:
            body[var_names.access_method] = static_vars.integrations_api
            url = api_paths.incidents_resolve

        elif action == freshdesk.cmd_run_response_set:
            body[var_names.access_method] = static_vars.integrations_api
            url = api_paths.incidents_run_response_set

        elif action == freshdesk.cmd_status_dashboard:
            url = api_paths.status_dashboard

        elif action == freshdesk.cmd_subscribe:
            body[var_names.access_method] = static_vars.integrations_api
            body[var_names.subscribers] = None
            url = api_paths.incidents_add_subscribers

        elif action == freshdesk.cmd_unacknowledge:
            body[var_names.access_method] = static_vars.integrations_api
            url = api_paths.incidents_un_acknowledge

        elif action == freshdesk.cmd_unlink:
            body[var_names.integration_type] = static_vars.integ_type_freshdesk
            url = api_paths.incidents_unlink

        elif action == freshdesk.cmd_unsubscribe:
            body[var_names.access_method] = static_vars.integrations_api
            body[var_names.subscribers] = None
            url = api_paths.incidents_remove_subscribers

        elif action == freshdesk.cmd_update_status:
            body[var_names.access_method] = static_vars.integrations_api
            url = api_paths.incidents_update_status

        elif action == freshdesk.cmd_view_incidents:
            body[var_names.status] = static_vars.open_state
            url = api_paths.incidents_list

        if access_token is None:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)
        elif url is None:
            return JsonResponse(lt.get_label(lnm.err_invalid_request, lang), status=401, safe=False)
        else:
            status, output = helpers.send_post_request(url, body, access_token, lang=lang)
            return JsonResponse(output, status=status, safe=False)
