# By: Riasat Ullah
# This file contains views for handling sentry authorization pages.

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.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 sentry
from taskcallweb import settings
from translators import label_translator as lt
from utils import cdn_enablers, helpers, logging, s3
from validations import request_validator
import json
import requests


@require_http_methods(['GET', 'POST'])
def authorize_sentry_integration(request):
    '''
    Handles the authorization of the Sentry integration process.
    :param request: Http request
    :return: Http response
    '''
    if request.method == 'GET':
        region = request_validator.get_host_region(request)
        if settings.REGION != region and region == static_vars.aws_us_ohio:
            if 'code' in request.GET and 'installationId' in request.GET and 'orgSlug' in request.GET:
                code = request.GET['code']
                installation_id = request.GET['installationId']
                org_slug = request.GET['orgSlug']
                rdr_url = sentry.get_web_path_us_tc_sentry_authorization(code, installation_id, org_slug)
                return redirect(rdr_url)

        if ('code' not in request.GET or 'installationId' not in request.GET or 'orgSlug' not in request.GET) and\
                (sentry.str_sentry_code not in request.session or
                 sentry.str_sentry_installation_id not in request.session or
                 sentry.str_sentry_org_slug not in request.session):
            logging.error('Expected parameters "code", "installationId" or "orgSlug" is missing. ' +
                          'Denying access to Sentry integration authorization. Redirecting to login page.')
            return redirect(pages.login_url)
        else:
            if 'code' in request.GET:
                code = request.GET['code']
                installation_id = request.GET['installationId']
                org_slug = request.GET['orgSlug']

                request.session[sentry.str_sentry_code] = code
                request.session[sentry.str_sentry_installation_id] = installation_id
                request.session[sentry.str_sentry_org_slug] = org_slug

            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

                context = integrations_context.get_sentry_authorization_context(lang)
                return render(request, pages.integrations_sentry_authorization, 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(lt.get_label(lnm.msg_success, lang), status=400, safe=False)
            else:
                body = json.loads(request.body.decode())
                if sentry.str_sentry_code in request.session and\
                    sentry.str_sentry_installation_id in request.session and\
                    sentry.str_sentry_org_slug in request.session and\
                        var_names.integration_name in body and var_names.service_ref_id in body:

                    try:
                        # variables sent from Sentry that have been stored in the session
                        code = request.session[sentry.str_sentry_code]
                        installation_id = request.session[sentry.str_sentry_installation_id]
                        org_slug = request.session[sentry.str_sentry_org_slug]

                        # integration details that have been received with this request
                        integ_name = body[var_names.integration_name]
                        serv_ref_id = body[var_names.service_ref_id]

                        sentry_creds = s3.read_json(sentry.sentry_s3_bucket, sentry.sentry_s3_key)
                        sentry_oauth_url = sentry.sentry_oauth_path_format.format(installation_id)

                        post_body = {
                            'grant_type': 'authorization_code',
                            'code': code,
                            'client_id': sentry_creds[sentry.str_sentry_client_id],
                            'client_secret': sentry_creds[sentry.str_sentry_client_secret],
                        }

                        resp = requests.post(sentry_oauth_url, json=post_body)
                        data = resp.json()
                    except Exception as e:
                        logging.exception(str(e))
                        return JsonResponse(lt.get_label(lnm.err_verification_failed, lang), status=400, safe=False)

                    sentry_token = data[sentry.str_sentry_token]
                    sentry_refresh_token = data[sentry.str_sentry_refresh_token]

                    if resp.status_code == 201:
                        sentry_verification_url = sentry.sentry_installation_verification_path_format.format(
                            installation_id)
                        header_params = {static_vars.authorization_attribute: 'Bearer ' + " " + sentry_token}
                        resp_2 = requests.put(sentry_verification_url, headers=header_params,
                                              json={'status': 'installed'})

                        if resp_2.status_code == 200:
                            post_body = {
                                var_names.service_ref_id: serv_ref_id,
                                var_names.integration_type: static_vars.integ_type_sentry,
                                var_names.integration_name: integ_name,
                                var_names.access_token: sentry_token,
                                var_names.secret_token: sentry_refresh_token,
                                var_names.additional_info: {
                                    sentry.str_sentry_installation_id: installation_id,
                                    sentry.str_sentry_org_slug: org_slug
                                }
                            }

                            status, output = helpers.post_api_request(api_paths.services_integrations_add, post_body,
                                                                      request, lang=lang)
                            if status == 200:
                                redirect_to_sentry_url = sentry.sentry_redirect_url.format(org_slug)

                                # If US region, store the installation ID 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_sentry, installation_id
                                    )
                                    if cache_key is not None:
                                        cdn_enablers.update_external_account_maps_file(
                                            static_vars.integ_type_sentry, cache_key)

                                return JsonResponse(redirect_to_sentry_url, safe=False)
                            else:
                                logging.info(lnm.err_processing_failed)
                                return JsonResponse(lt.get_label(lnm.err_processing_failed, lang), status=400,
                                                    safe=False)
                        else:
                            logging.error(lnm.err_processing_failed)
                            logging.error(resp_2.json())
                            return JsonResponse(lt.get_label(lnm.err_processing_failed, lang), status=400, safe=False)
                    else:
                        logging.error(lnm.err_processing_failed)
                        logging.error(data)
                        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)
