# By: Riasat Ullah
# This file contains views specific to the Monday.com integration.

from constants import api_paths, label_names as lnm, pages, static_vars, url_paths, var_names
from django.http import JsonResponse
from django.shortcuts import redirect
from django.views.decorators.http import require_http_methods
from integrations import monday
from system_tests.test_data import test_data_services
from taskcallweb import settings
from translators import label_translator as lt
from utils import helpers, logging, s3
from validations import request_validator
import json
import requests


@require_http_methods(['GET'])
def redirect_to_monday_authorization_page(request):
    '''
    Redirects to the Monday.com authorization page.
    :param request: Http request
    :return: Http response
    '''
    if request.method == 'GET':
        try:
            srv_ref = request.session[var_names.services][var_names.service_ref_id]
            monday_creds = s3.read_json(monday.monday_s3_bucket, monday.monday_s3_key)
            monday_oauth_url = monday.monday_oauth_path_format.format(
                monday_creds[monday.str_monday_client_id], srv_ref)
            return redirect(monday_oauth_url)
        except Exception as e:
            logging.exception(str(e))
            return redirect(pages.login_url)


@require_http_methods(['GET'])
def authorize_monday_integration(request):
    '''
    Handles the authorization of the Monday.com integration process.
    :param request: Http request
    :return: Http response
    '''
    if request.method == 'GET':
        if 'code' not in request.GET or not request_validator.user_in_session(request) or \
                (var_names.services not in request.session
                 and var_names.service_ref_id not in request.session[var_names.services]
                 and var_names.integration_name not in request.session[var_names.services]):

            logging.error('Expected parameters "code" is missing or service session variables were not found.' +
                          'Denying access to Monday.com integration authorization. Redirecting to login page.')
            return redirect(pages.login_url)
        else:
            lang = request_validator.get_user_language(request)
            code = request.GET['code']
            state = request.GET['state']
            serv_session = request.session[var_names.services]
            srv_ref = serv_session[var_names.service_ref_id]
            failed = True

            if state == srv_ref:
                try:
                    monday_creds = s3.read_json(monday.monday_s3_bucket, monday.monday_s3_key)
                    post_body = {
                        monday.str_monday_client_id: monday_creds[monday.str_monday_client_id],
                        monday.str_monday_client_secret: monday_creds[monday.str_monday_client_secret],
                        monday.str_monday_code: code,
                        monday.str_monday_redirect_uri: monday.monday_taskcall_callback_url
                    }

                    # Get Monday.com authorization and access token.
                    oauth_resp = requests.post(monday.monday_token_retrieval_path, json=post_body)
                    logging.info(oauth_resp)
                    if oauth_resp.status_code == 200:
                        oauth_data = oauth_resp.json()
                        logging.info(oauth_data)

                        access_token = oauth_data[monday.str_monday_access_token]

                        # Get the account ID associated to this Monday.com account.
                        account_id_resp = requests.post(
                            monday.monday_api_url,
                            headers={"Authorization": "Bearer " + access_token, "Content-Type": "application/json"},
                            json={"query": "query { account { id } }"}
                        )
                        if account_id_resp.status_code == 200:
                            account_id_data = account_id_resp.json()

                            # The account ID is int, but we have to convert it to str
                            # in order to match with our convention for external IDs.
                            account_id = account_id_data['data']['account']['id']

                            # Only if the Monday.com account ID is not already associated to this organization,
                            # then create an entry in the organization_integration_type_details. Do not duplicate.
                            dupe_post_body = {var_names.external_id: account_id,
                                              var_names.access_token: access_token}
                            dupe_check_status, dupe_check_output = helpers.post_api_request(
                                api_paths.integrations_monday_tokens_update, dupe_post_body, request, lang=lang
                            )

                            serv_session[var_names.vendor_endpoint_name] = account_id
                            if dupe_check_status == 200 and not dupe_check_output:
                                serv_session[var_names.external_id] = account_id
                                serv_session[var_names.external_info] = {
                                    var_names.access_token: access_token
                                }

                            request.session[var_names.services] = serv_session
                            failed = False
                except Exception as e:
                    logging.exception(str(e))

            if failed:
                logging.exception(lnm.err_verification_failed)
                return redirect(url_paths.configurations_services + '/' + srv_ref + '?error=' +
                                lt.get_label(lnm.err_unauthorized_access, lang))
            else:
                return redirect(url_paths.configurations_services + '/' + srv_ref +
                                '?tab=integrations&modal=monday&integration=' +
                                serv_session[var_names.integration_name])


@require_http_methods(['POST'])
def get_monday_boards(request):
    '''
    Get available boards from Monday.com.
    :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 var_names.integration_key in body:
                post_body = body
            else:
                # This way of handling the process ensures that only one access token is maintained per Monday account.
                serv_session = request.session[var_names.services]
                post_body = {var_names.external_id: serv_session[var_names.vendor_endpoint_name]}

                if var_names.external_info in serv_session:
                    post_body[var_names.access_token] = serv_session[var_names.external_info][var_names.access_token]

            if settings.TEST_MODE:
                return JsonResponse(test_data_services.monday_boards, safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.integrations_monday_boards,
                                                          post_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_monday_integration(request):
    '''
    Creates a new Monday.com 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) and var_names.services in request.session and\
            var_names.integration_type in request.session[var_names.services] and\
            request.session[var_names.services][var_names.integration_type] == static_vars.integ_type_monday and\
            var_names.service_ref_id in request.session[var_names.services] and\
                var_names.integration_name in request.session[var_names.services]:

            req_body = json.loads(request.body.decode())
            serv_session = request.session[var_names.services]

            post_body = {
                var_names.service_ref_id: serv_session[var_names.service_ref_id],
                var_names.integration_type: static_vars.integ_type_monday,
                var_names.integration_name: serv_session[var_names.integration_name],
                var_names.vendor_endpoint_name: serv_session[var_names.vendor_endpoint_name],
                var_names.additional_info: req_body[var_names.additional_info]
            }
            if var_names.external_id in serv_session:
                post_body[var_names.external_id] = serv_session[var_names.external_id]
                post_body[var_names.external_info] = serv_session[var_names.external_info]

            if settings.TEST_MODE:
                return JsonResponse('Action performed successfully', safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.services_integrations_add, post_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_monday_integration(request):
    '''
    Edits the configuration of an existing Monday.com 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)
