# By: Riasat Ullah
# This file contains views related to the custom endpoint integration.

from cache_queries import cache_services
from dbqueries import db_integrations, db_services
from dbqueries.integrations import db_custom_endpoint
from exceptions.user_exceptions import InvalidRequest, UnauthorizedRequest
from rest_framework.decorators import api_view
from rest_framework.response import Response
from translators import label_translator as _lt
from utils import errors, info, integration_type_names as intt, key_manager, logging, permissions, times, tokenizer,\
    var_names
from utils.db_connection import CACHE_CLIENT, CONN_POOL
from validations import request_validator
import jwt


@api_view(['POST'])
def get_custom_endpoint_meta_data(request, conn=None):
    '''
    Get the list of headers of a custom action (just the keys).
    :param request: Http request
    :param conn: db connection
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.integration_key]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)
            integ_key = request.data[var_names.integration_key]

            if permissions.has_org_permission(org_perm, permissions.ORG_CUSTOM_ACTION_PERMISSION):
                details = db_custom_endpoint.get_custom_endpoint_and_headers(
                    conn, times.get_current_timestamp(), org_id, integ_key)
                return Response(details)
            else:
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
        except InvalidRequest as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def reauthorize_custom_endpoint_integration(request, conn=None, cache=None):
    '''
    Allows an organization admin or those with the right permissions to reauthorize a custom endpoint integration.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http Response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.service_ref_id, var_names.integration_key, var_names.vendor_endpoint]
        optional_fields = [var_names.secret_token, var_names.conditions_map]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields, optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.can_user_edit_components(user_perm, org_perm):
                do_adv_check, do_comp_check, do_team_check =\
                    permissions.get_user_advanced_check_status(user_perm, org_perm)

                serv_ref = key_manager.unmask_reference_key(request.data[var_names.service_ref_id])
                integ_key = request.data[var_names.integration_key]
                vendor_endpoint = request.data[var_names.vendor_endpoint]
                secret_token = request.data[var_names.secret_token] if var_names.secret_token in request.data else None
                cond_map = request.data[var_names.conditions_map] if var_names.conditions_map in request.data else None

                # existing integration details
                current_time = times.get_current_timestamp()
                integ_details = db_integrations.get_comprehensive_integration_details(
                    conn, current_time, org_id, integration_key=integ_key)[0]
                integ_type = integ_details[var_names.integration_type]

                # If integration is for a custom action, then confirm that the account has the correct permission
                if integ_type in [intt.custom_endpoint, intt.rundeck] and not permissions.has_org_permission(
                        org_perm, permissions.ORG_CUSTOM_ACTION_PERMISSION):
                    return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                if integ_type == intt.rundeck and secret_token is None:
                    raise InvalidRequest(errors.err_invalid_request)

                db_custom_endpoint.reauthorize_custom_endpoint_integration(
                    conn, current_time, org_id, user_id, integ_key, vendor_endpoint, secret_token=secret_token,
                    headers=cond_map, check_adv_perm=do_adv_check, has_comp_perm=do_comp_check,
                    has_team_perm=do_team_check
                )

                serv_dict = db_services.get_service(conn, current_time, service_ref_id=serv_ref, organization_id=org_id)
                if len(serv_dict) > 0:
                    serv = list(serv_dict.values())[0]
                    cache_services.store_service(cache, serv)

                return Response(_lt.get_label(info.msg_service_integration_reauthorized, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        except InvalidRequest as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)
