# By: Riasat Ullah
# This file contains views for services.

from constants import api_paths, label_names as lnm, pages, static_vars, var_names
from constants import component_names as cnm
from context_manager import configurations_context, tutorials_context
from django.core import exceptions
from django.http import JsonResponse
from django.shortcuts import redirect, render
from django.views.decorators.http import require_http_methods
from taskcallweb import settings
from system_tests.test_data import test_data_services
from translators import label_translator as lt
from utils import helpers
from validations import request_validator
import json
import random


@require_http_methods(['GET', 'POST'])
def get_services_list(request):
    '''
    Returns the list of all services.
    :param request: Http request
    :return: Http response
    '''
    if request.method == 'GET':
        if request_validator.user_in_session(request):
            lang = request_validator.get_user_language(request)
            nav_bar_components = request_validator.get_nav_bar_components(request)

            has_view_perm, has_edit_perm = request_validator.get_session_permission(
                request, cnm.dis_com_services, nav_bar_components
            )
            if not has_view_perm:
                raise exceptions.PermissionDenied

            context = configurations_context.get_service_list_context(lang, nav_bar_components)
            context[var_names.has_edit_permission] = has_edit_perm
            context[var_names.has_business_service_permission] = request_validator.has_view_permission(
                request, cnm.dis_com_business_services, nav_bar_components
            )
            context[var_names.has_team_permission] = request_validator.get_team_permission_status(request)
            return render(request, pages.service_list_page, context=context)
        else:
            helpers.set_session_redirect_page(request)
            return redirect(pages.login_url)
    elif request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            if settings.TEST_MODE:
                return JsonResponse(test_data_services.services_list, safe=False)
            else:
                body = dict()
                status, output = helpers.post_api_request(api_paths.services_list, 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(['GET', 'POST'])
def get_service_details(request, service_reference_id):
    '''
    GET: Gets the service details html page.
    POST: Gets the details of a service.
    :param request: Http request
    :param service_reference_id: reference ID of the service
    :return: GET: Http response  |  POST: JSON response
    '''
    if request.method == 'GET':
        if request_validator.user_in_session(request):
            lang = request_validator.get_user_language(request)
            nav_bar_components = request_validator.get_nav_bar_components(request)
            component_features = request_validator.get_component_features(request)

            has_view_perm, has_edit_perm = request_validator.get_session_permission(
                request, cnm.dis_com_services, nav_bar_components
            )
            if not has_view_perm:
                raise exceptions.PermissionDenied

            context = configurations_context.get_service_details_context(lang, nav_bar_components)
            context[var_names.context] = json.dumps({var_names.service_ref_id: service_reference_id})
            context[var_names.has_edit_permission] = has_edit_perm
            context[var_names.has_component_flexible_role] = \
                True if cnm.feat_users_component_flexible_role in component_features else False
            context[var_names.has_workflows_permission] = \
                True if cnm.feat_incidents_workflows in component_features else False
            context[var_names.has_recent_changes_permission] =\
                True if cnm.feat_incidents_recent_changes in component_features else False
            context[var_names.has_secondary_integrations_permission] =\
                True if cnm.feat_integrations_secondary in component_features else False
            context[var_names.has_custom_action_permission] = \
                True if cnm.feat_integrations_custom_action in component_features else False
            context[var_names.has_customer_service_integrations_permission] =\
                True if cnm.feat_integrations_customer_service in component_features else False
            context[var_names.has_itsm_integrations_permission] =\
                True if cnm.feat_integrations_itsm in component_features else False
            context[var_names.has_contextual_search_permission] = request_validator.has_edit_permission(
                request, cnm.dis_com_tags)
            context[var_names.has_team_permission] = request_validator.get_team_permission_status(request)
            context = {**context, **tutorials_context.get_onboarding_integration_context(lang)}

            if 'tab' in request.GET:
                context[var_names.tab_name] = request.GET.get('tab')
            if 'modal' in request.GET:
                modal_name = request.GET.get('modal')
                context[var_names.modal_name] = modal_name
            if 'integration' in request.GET:
                context[var_names.integration_name] = request.GET.get('integration')
            if 'error' in request.GET:
                context[var_names.error_name] = request.GET.get('error')
            if 'message' in request.GET:
                context[var_names.message_name] = request.GET.get('message')

            if 'flow' in request.GET:
                context[var_names.flow_id] = request.GET.get('flow')
            if 'step' in request.GET:
                context[var_names.step_number] = request.GET.get('step')
            if 'tutorial' in request.GET:
                context[var_names.tutorial_name] = request.GET.get('tutorial')

            return render(request, pages.service_details_page, context=context)
        else:
            helpers.set_session_redirect_page(request)
            return redirect(pages.login_url)
    elif request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            if settings.TEST_MODE:
                return JsonResponse(test_data_services.service_details[service_reference_id], safe=False)
            else:
                body = {var_names.service_ref_id: service_reference_id}
                status, output = helpers.post_api_request(api_paths.services_details, 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(['GET'])
def get_new_service(request):
    '''
    Gets the new service (create service) html page.
    :param request: Http request
    :return: Http response
    '''
    if request.method == 'GET':
        if request_validator.user_in_session(request):
            lang = request_validator.get_user_language(request)
            nav_bar_components = request_validator.get_nav_bar_components(request)

            has_edit_perm = request_validator.has_edit_permission(request, cnm.dis_com_services)
            if not has_edit_perm:
                raise exceptions.PermissionDenied

            context = configurations_context.get_service_new_context(lang, nav_bar_components)
            context[var_names.has_workflows_permission] = \
                True if cnm.feat_incidents_workflows in request_validator.get_component_features(request) else False
            context = {**context, **tutorials_context.get_onboarding_service_context(lang)}

            if 'flow' in request.GET:
                context[var_names.flow_id] = request.GET.get('flow')
            if 'step' in request.GET:
                context[var_names.step_number] = request.GET.get('step')
            if 'tutorial' in request.GET:
                context[var_names.tutorial_name] = request.GET.get('tutorial')

            return render(request, pages.service_new_page, context=context)
        else:
            helpers.set_session_redirect_page(request)
            return redirect(pages.login_url)


@require_http_methods(['POST'])
def create_service(request):
    '''
    Creates a new service.
    :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(test_data_services.services_basic_list[0][1], safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_create, 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 edit_service(request):
    '''
    Edits an existing service.
    :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('Service has been edited', safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_edit, 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 delete_service(request):
    '''
    Delete an existing service.
    :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('Action performed successfully', safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_delete, 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 enable_service(request):
    '''
    Enable/disable a service.
    :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('Action performed successfully', safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_enable, 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_service_maintenance_windows(request):
    '''
    Gets the list of all service maintenance windows that are upcoming.
    :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):
            if settings.TEST_MODE:
                return JsonResponse(test_data_services.service_maintenance_windows, safe=False)
            else:
                body = dict()
                status, output = helpers.post_api_request(api_paths.services_maintenance_windows_list, 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 create_maintenance(request):
    '''
    Create a new maintenance for a service.
    :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(random.randint(1, 1000), safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_maintenance_windows_create, 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 delete_maintenance(request):
    '''
    Delete a scheduled maintenance of a service.
    :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('Action performed successfully', safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_maintenance_windows_delete, 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_integrations(request):
    '''
    Get the details of all integrations of a service.
    :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:
                ref_id = body[var_names.service_ref_id]
                return JsonResponse(test_data_services.service_details[ref_id][var_names.integrations], safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_integrations_list, 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 create_integration(request):
    '''
    Create a new integration.
    :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 it is an integration that requires additional steps like o-auth,
            # then save the integration details and redirect to the correct site
            if body[var_names.integration_type] in [static_vars.integ_type_jira_cloud, static_vars.integ_type_monday,
                                                    static_vars.integ_type_slack, static_vars.integ_type_zendesk]:
                # save the data in the session first
                request.session[var_names.services] = body
                return JsonResponse(lt.get_label(lnm.msg_success, lang), safe=False)

            if settings.TEST_MODE:
                return JsonResponse('Action performed successfully', safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_integrations_add, 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 edit_integration(request):
    '''
    Edits the details of an existing integration.
    :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('Action performed successfully', safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_integrations_edit, 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 delete_integration(request):
    '''
    Delete an integration.
    :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('Action performed successfully', safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_integrations_delete, 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 transfer_integration(request):
    '''
    Transfers an integration from one service to another.
    :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('Action performed successfully', safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_integrations_transfer, 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_incident_custom_action_integrations(request):
    '''
    Get the list of integrations that require instances to be synchronized with another vendor.
    :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:
                ref_id = body[var_names.service_ref_id]
                test_integ = test_data_services.service_details[ref_id][var_names.integrations]
                sync_integs = []
                for i in range(0, len(test_integ)):
                    if test_integ[i][var_names.integration_type] == static_vars.integ_type_jira_cloud:
                        sync_integs.append({var_names.integration_key: test_integ[i][var_names.integration_key],
                                            var_names.configuration_name: 'Create Jira Issue'})
                return JsonResponse(sync_integs, safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.integrations_incident_custom_actions, 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(['GET', 'POST'])
def get_service_dependencies(request):
    '''
    Gets all the system (service and business) dependencies of an organization.
    :param request: Http request
    :return: Http response
    '''
    if request.method == 'GET':
        if request_validator.user_in_session(request):
            lang = request_validator.get_user_language(request)
            nav_bar_components = request_validator.get_nav_bar_components(request)

            has_view_perm, has_edit_perm = request_validator.get_session_permission(
                request, cnm.dis_com_dependency_graph, nav_bar_components
            )
            if not has_view_perm:
                raise exceptions.PermissionDenied

            context = configurations_context.get_dependency_graph_context(lang, nav_bar_components)
            context[var_names.has_edit_permission] = has_edit_perm
            context[var_names.has_team_permission] = request_validator.get_team_permission_status(request)
            if 'service' in request.GET:
                context[var_names.filter_by] = request.GET.get('service')
            return render(request, pages.service_dependencies_graph_page, context=context)
        else:
            helpers.set_session_redirect_page(request)
            return redirect(pages.login_url)
    elif request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            if settings.TEST_MODE:
                return JsonResponse(test_data_services.dependencies, safe=False)
            else:
                body = dict()
                status, output = helpers.post_api_request(api_paths.services_dependencies, 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_service_specific_technical_dependencies(request):
    '''
    Get the technical dependencies of a service.
    :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(test_data_services.technical_dependencies, safe=False)
            else:
                status, output = helpers.post_api_request(
                    api_paths.services_dependencies_technical, 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 add_service_dependency(request):
    '''
    Add a new service dependency (technical or business)
    :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('Success', safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_dependencies_add, 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 delete_service_dependency(request):
    '''
    Delete a service dependency (technical or business).
    :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('Success', safe=False)
            else:
                status, output = helpers.post_api_request(
                    api_paths.services_dependencies_delete, 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)
