# By: Riasat Ullah
# This file contains configuration views.

from data_syncers import syncer_routing
from dbqueries import db_routing
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, 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 list_conditional_routing_rules(request, conn=None):
    '''
    Gets the list of all the conditional routing directive of an organization.
    Only contains the basic information.
    :param request: Http request
    :param conn: db connection
    :return: Http response -> dict of details
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        optional_fields = [var_names.row_limit, var_names.row_offset]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, [], optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            row_limit = request.data[var_names.row_limit] if var_names.row_limit in request.data else None
            row_offset = request.data[var_names.row_offset] if var_names.row_offset in request.data else None

            if permissions.has_org_permission(org_perm, permissions.ORG_ROUTING_PERMISSION):
                if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_VIEW_PERMISSION):
                    current_time = times.get_current_timestamp()
                    rules = db_routing.list_conditional_routing(
                        conn, current_time, org_id, row_limit=row_limit, row_offset=row_offset
                    )
                    return Response(rules)
                else:
                    return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            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 get_conditional_routing_details(request, conn=None):
    '''
    Gets all the details of a given conditional routing directive.
    :param request: Http request
    :param conn: db connection
    :return: Http response -> dict of details
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.routing_ref_id]
        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)

            if permissions.has_org_permission(org_perm, permissions.ORG_ROUTING_PERMISSION):
                if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_VIEW_PERMISSION):

                    route_ref_id = request.data[var_names.routing_ref_id]
                    current_time = times.get_current_timestamp()
                    route = db_routing.get_conditional_routing(conn, current_time, org_id=org_id,
                                                               routing_ref_id=route_ref_id, id_on_ref=True)[0]
                    return Response(route.to_dict())
                else:
                    return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            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 create_conditional_routing(request, conn=None, cache=None):
    '''
    Creates a new conditional routing directive.
    :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.is_enabled, var_names.rule_name, var_names.rule_description, var_names.valid_start,
                           var_names.valid_end, var_names.rule_start_time, var_names.rule_end_time, var_names.repeat,
                           var_names.rule_application_count, var_names.routing_rules, var_names.routing_actions,
                           var_names.timezone, var_names.allow_multiple]
        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)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.has_org_permission(org_perm, permissions.ORG_ROUTING_PERMISSION):
                if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_EDIT_PERMISSION):

                    current_time = times.get_current_timestamp()

                    db_routing.create_conditional_routing(conn, current_time, org_id,
                                                          request.data[var_names.is_enabled],
                                                          request.data[var_names.rule_name],
                                                          request.data[var_names.rule_description],
                                                          request.data[var_names.valid_start],
                                                          request.data[var_names.valid_end],
                                                          request.data[var_names.rule_start_time],
                                                          request.data[var_names.rule_end_time],
                                                          request.data[var_names.repeat],
                                                          request.data[var_names.rule_application_count],
                                                          request.data[var_names.routing_rules],
                                                          request.data[var_names.routing_actions],
                                                          request.data[var_names.timezone],
                                                          request.data[var_names.allow_multiple])

                    syncer_routing.update_organization_conditional_routes_in_cache(conn, cache, current_time, org_id)

                    return Response(_lt.get_label(info.msg_cond_route_created, lang))
                else:
                    return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            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 edit_conditional_routing(request, conn=None, cache=None):
    '''
    Edits a given conditional routing directive.
    :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.routing_ref_id, var_names.is_enabled, var_names.rule_name,
                           var_names.rule_description, var_names.valid_start, var_names.valid_end,
                           var_names.rule_start_time, var_names.rule_end_time, var_names.repeat,
                           var_names.rule_application_count, var_names.routing_rules,
                           var_names.routing_actions, var_names.timezone, var_names.allow_multiple]
        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)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.has_org_permission(org_perm, permissions.ORG_ROUTING_PERMISSION):
                if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_EDIT_PERMISSION):

                    current_time = times.get_current_timestamp()
                    rout_ref_id = request.data[var_names.routing_ref_id]

                    db_routing.edit_conditional_routing(conn, current_time, org_id, rout_ref_id,
                                                        request.data[var_names.is_enabled],
                                                        request.data[var_names.rule_name],
                                                        request.data[var_names.rule_description],
                                                        request.data[var_names.valid_start],
                                                        request.data[var_names.valid_end],
                                                        request.data[var_names.rule_start_time],
                                                        request.data[var_names.rule_end_time],
                                                        request.data[var_names.repeat],
                                                        request.data[var_names.rule_application_count],
                                                        request.data[var_names.routing_rules],
                                                        request.data[var_names.routing_actions],
                                                        request.data[var_names.timezone],
                                                        request.data[var_names.allow_multiple])

                    syncer_routing.update_organization_conditional_routes_in_cache(conn, cache, current_time, org_id)

                    return Response(_lt.get_label(info.msg_cond_route_edited, lang))
                else:
                    return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            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 enable_conditional_routing(request, conn=None, cache=None):
    '''
    Enables a given conditional routing directive.
    :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.routing_ref_id]
        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)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.has_org_permission(org_perm, permissions.ORG_ROUTING_PERMISSION):
                if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_EDIT_PERMISSION):

                    current_time = times.get_current_timestamp()
                    ref_id = request.data[var_names.routing_ref_id]
                    db_routing.enable_routing(conn, current_time, org_id, ref_id, enable=True)

                    syncer_routing.update_organization_conditional_routes_in_cache(conn, cache, current_time, org_id)

                    return Response(_lt.get_label(info.msg_cond_route_enabled, lang))
                else:
                    return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            else:
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
        except (InvalidRequest, LookupError) 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 disable_conditional_routing(request, conn=None, cache=None):
    '''
    Disables a given conditional routing directive.
    :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.routing_ref_id]
        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)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.has_org_permission(org_perm, permissions.ORG_ROUTING_PERMISSION):
                if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_EDIT_PERMISSION):

                    current_time = times.get_current_timestamp()
                    ref_id = request.data[var_names.routing_ref_id]
                    db_routing.enable_routing(conn, current_time, org_id, ref_id, enable=False)

                    syncer_routing.update_organization_conditional_routes_in_cache(conn, cache, current_time, org_id)

                    return Response(_lt.get_label(info.msg_cond_route_disabled, lang))
                else:
                    return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            else:
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
        except (InvalidRequest, LookupError) 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 delete_conditional_routing(request, conn=None, cache=None):
    '''
    Deletes a given conditional routing directive.
    :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.routing_ref_id]
        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)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.has_org_permission(org_perm, permissions.ORG_ROUTING_PERMISSION):
                if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_EDIT_PERMISSION):

                    current_time = times.get_current_timestamp()
                    ref_id = request.data[var_names.routing_ref_id]

                    db_routing.delete_conditional_routing(conn, current_time, org_id, ref_id)

                    syncer_routing.update_organization_conditional_routes_in_cache(conn, cache, current_time, org_id)

                    return Response(_lt.get_label(info.msg_cond_route_deleted, lang))
                else:
                    return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            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)
