# By: Riasat Ullah
# This file contains code for handling Microsoft Teams configuration pages.

from constants import api_paths, component_names as cnm, label_names as lnm, pages, static_vars, url_paths, var_names
from context_manager import integrations_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 integrations import microsoft_teams as ms_teams
from system_tests.test_data import test_data_services
from taskcallweb import settings
from translators import label_translator as lt
from utils import cdn_enablers, helpers, logging
from validations import request_validator
import json


@require_http_methods(['GET', 'POST'])
def authorize_microsoft_teams_integration(request):
    '''
    Handles the authorization of the Microsoft Teams integration process.
    :param request: Http request
    :return: Http response
    '''
    if request.method == 'GET':
        if 'error' in request.GET:
            logging.error('Microsoft teams account admin did not authorize the requested permissions. ' +
                          'Aborting integration and redirecting to login page.')
            return redirect(pages.login_url)
        else:
            if var_names.state in request.GET:
                region = request_validator.get_host_region(request)
                verification_token = request.GET[var_names.state]
                admin_consent = request.GET['admin_consent']
                tenant = request.GET['tenant']

                if settings.REGION != region and region == static_vars.aws_us_ohio:
                    rdr_url = ms_teams.get_web_path_us_tc_ms_teams_authorization(verification_token, tenant,
                                                                                 admin_consent)
                    return redirect(rdr_url)
                elif settings.REGION == region and region != static_vars.aws_europe_paris:
                    # Switch the token to the current server region
                    swt_body = {var_names.token: verification_token,
                                var_names.integration_type: static_vars.integ_type_microsoft_teams}
                    swt_sts, swt_out = helpers.post_api_request(api_paths.integrations_temporary_token_switch_region,
                                                                swt_body, request)
                    logging.info(swt_out)

                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_edit_perm:
                        raise exceptions.PermissionDenied

                    body = {var_names.token: verification_token}
                    if settings.TEST_MODE:
                        status, output = 200, test_data_services.microsoft_teams_authorization_data
                    else:
                        status, output = helpers.post_api_request(api_paths.integrations_microsoft_teams_authorize,
                                                                  body, request, lang=lang)

                    if status == 200:
                        output = {**output, **{var_names.token: verification_token}}
                        request.session[ms_teams.str_mst_temp_token_details] = output
                        context = integrations_context.get_microsoft_teams_authorization_context(lang)
                        return render(request, pages.integrations_microsoft_teams_authorization, context=context)
                    else:
                        context = {
                            var_names.error_code: 403,
                            var_names.error_message: lt.get_label(lnm.err_ms_teams_authorization_token_expired, lang)
                        }
                        return render(request, pages.error_page, context=context)
                else:
                    helpers.set_session_redirect_page(request)
                    return redirect(pages.login_url)
            else:
                logging.error('Expected parameter "state" is missing. Denying access to Microsoft Teams integration ' +
                              'authorization. Redirecting to login page.')
                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(lt.get_label(lnm.msg_success, lang), status=400, safe=False)
            else:
                body = json.loads(request.body.decode())
                if ms_teams.str_mst_temp_token_details in request.session and\
                        var_names.integration_name in body and var_names.service_ref_id in body:

                    token_details = request.session[ms_teams.str_mst_temp_token_details]
                    integ_name = body[var_names.integration_name]
                    serv_ref_id = body[var_names.service_ref_id]

                    post_body = {
                        var_names.service_ref_id: serv_ref_id,
                        var_names.integration_type: static_vars.integ_type_microsoft_teams,
                        var_names.integration_name: integ_name,
                        var_names.vendor_endpoint: token_details[ms_teams.str_service_url],
                        var_names.additional_info: {
                            var_names.tenant_id: token_details[ms_teams.str_tenant_id],
                            var_names.team_id: token_details[var_names.team_id],
                            var_names.channel_id: token_details[var_names.channel_id]
                        },
                        var_names.external_id: token_details[ms_teams.str_tenant_id],
                        var_names.external_info: {
                            ms_teams.str_tenant_id: token_details[ms_teams.str_tenant_id],
                        }
                    }

                    status, output = helpers.post_api_request(api_paths.services_integrations_add, post_body,
                                                              request, lang=lang)
                    if status == 200:
                        # End-date the temporary token upon successful completion of
                        # the integration so it cannot be reused
                        cnf_body = {var_names.token: token_details[var_names.token],
                                    var_names.channel_id: token_details[var_names.channel_id],
                                    var_names.vendor_endpoint: token_details[ms_teams.str_service_url]}
                        cnf_status, cnf_output = helpers.post_api_request(
                            api_paths.integrations_microsoft_teams_authorize_confirm, cnf_body, request, lang=lang)
                        if cnf_status != 200:
                            logging.error(cnf_output)

                        # If US region, combine MS Teams tenant id and channel id in a key and store it in s3. It will
                        # be used as a cache key to identify the region incoming requests should be forwarded to.
                        if settings.REGION == static_vars.aws_us_ohio:
                            cache_key = cdn_enablers.create_cdn_cache_key(
                                static_vars.integ_type_microsoft_teams, token_details[ms_teams.str_tenant_id],
                                token_details[var_names.channel_id]
                            )
                            if cache_key is not None:
                                cdn_enablers.update_external_account_maps_file(
                                    static_vars.integ_type_microsoft_teams, cache_key)

                        return JsonResponse(url_paths.configurations_services, safe=False)
                    else:
                        logging.info(lnm.err_processing_failed)
                        return JsonResponse(lt.get_label(lnm.err_processing_failed, lang), status=400,
                                            safe=False)
                else:
                    return JsonResponse(lt.get_label(lnm.err_verification_failed, lang), status=400, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def get_microsoft_teams_account_meta_data(request):
    '''
    Get the metadata necessary for setting up a Microsoft Teams conference bridge.
    :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.microsoft_teams_meta_data, status=200, safe=False)
            else:
                status, output = helpers.post_api_request(
                    api_paths.integrations_microsoft_teams_account_meta_data, dict(), 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)
