# By: Riasat Ullah
# This file contains all the views related to a group.

from data_syncers import syncer_policies
from dbqueries import db_policies
from exceptions.user_exceptions import DependencyFound, 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 constants, errors, helpers, info, 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 create_escalation_policy(request, conn=None):
    '''
    Create a new group.
    :param request: HttpRequest
    :param conn: db connection
    :return: HttpResponse -> str
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.policy_name, var_names.levels]
        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_user_permission(user_perm, permissions.USER_COMPONENTS_EDIT_PERMISSION):
                pol_name = request.data[var_names.policy_name]
                pol_levels = request.data[var_names.levels]
                current_time = times.get_current_timestamp()

                if db_policies.policy_name_is_unique(conn, current_time, org_id, pol_name):
                    db_policies.create_policy(conn, current_time, org_id, pol_name, pol_levels)
                    return Response(_lt.get_label(info.msg_policy_created, lang))
                else:
                    return Response(_lt.get_label(errors.err_policy_name, lang), status=400)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, ValueError) 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_escalation_policy(request, conn=None, cache=None):
    '''
    Edits the details of a group.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response -> str
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.policy_ref_id, var_names.policy_name, var_names.levels]
        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.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)

                pol_ref_id = request.data[var_names.policy_ref_id]
                pol_name = request.data[var_names.policy_name]
                pol_levels = request.data[var_names.levels]
                current_time = times.get_current_timestamp()

                if db_policies.policy_name_is_unique(conn, current_time, org_id, pol_name, ignore_policy=pol_ref_id):
                    syncer_policies.edit_policy(conn, cache, current_time, user_id, org_id,
                                                pol_ref_id, pol_name, pol_levels,
                                                check_adv_perm=do_adv_check,
                                                has_comp_perm=do_comp_check,
                                                has_team_perm=do_team_check)
                    return Response(_lt.get_label(info.msg_policy_edited, lang))
                else:
                    return Response(_lt.get_label(errors.err_policy_name, lang), status=400)
            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(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError, ValueError) 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_escalation_policy(request, conn=None, cache=None):
    '''
    Deletes a group.
    :param request: HttpRequest
    :param conn: db connection
    :param cache: cache client
    :return: HttpResponse -> str
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.policy_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.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)

                pol_ref_id = request.data[var_names.policy_ref_id]
                current_time = times.get_current_timestamp()

                syncer_policies.delete_policy(conn, cache, current_time, user_id, org_id, pol_ref_id,
                                              check_adv_perm=do_adv_check,
                                              has_comp_perm=do_comp_check,
                                              has_team_perm=do_team_check)
                return Response(_lt.get_label(info.msg_policy_deleted, 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 DependencyFound as e:
            logging.exception(e.message + e.additional_message)
            return Response(_lt.get_label(e.message, lang) + e.additional_message, 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_escalation_policies_list(request, conn=None):
    '''
    Get the list of groups of an organization along with their basic information.
    :param request: Http request
    :param conn: db connection
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        optional_fields = [var_names.row_limit, var_names.row_offset, var_names.assignee_type]
        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)

            if permissions.can_user_view_components(user_perm):
                do_adv_check = permissions.get_user_advanced_check_status(user_perm, org_perm)[0]
                teams_only = False
                if var_names.assignee_type in request.data and\
                        request.data[var_names.assignee_type] == constants.team_assignee:
                    teams_only = True

                retrieved_policies = db_policies.get_policies(
                    conn, times.get_current_timestamp(), with_org_id=org_id, policy_type=constants.group_policy,
                    for_display=True, with_user_id=user_id, check_adv_perm=do_adv_check, user_teams_only=teams_only
                )

                serialized_policies = [item.to_dict(basic_info=True, with_on_call=True)
                                       for item in list(retrieved_policies.values())]
                serialized_policies = helpers.sorted_list_of_dict(serialized_policies, var_names.policy_name)

                key_manager.conceal_object_keys(serialized_policies,
                                                [var_names.associated_services, var_names.policy_id,
                                                 var_names.policy_ref_id, var_names.on_call, var_names.routines])

                return Response(serialized_policies)
            else:
                return Response(_lt.get_label(errors.err_user_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_escalation_policy_details(request, conn=None):
    '''
    Gets all the escalation policies that a user is associated to.
    :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.policy_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.can_user_view_components(user_perm):
                do_adv_check = permissions.get_user_advanced_check_status(user_perm, org_perm)[0]

                retrieved_policies = db_policies.get_policies(
                    conn, times.get_current_timestamp(), with_policy_ref_id=request.data[var_names.policy_ref_id],
                    with_org_id=org_id, policy_type=constants.group_policy, for_display=True,
                    with_user_id=user_id, check_adv_perm=do_adv_check
                )
                if len(retrieved_policies) > 0:
                    requested_policy = list(retrieved_policies.values())[0]
                    serialized_policy = requested_policy.to_dict(basic_info=True, with_on_call=True)

                    key_manager.conceal_object_keys(serialized_policy,
                                                    [var_names.associated_services, var_names.policy_id,
                                                     var_names.policy_ref_id, var_names.on_call, var_names.routines])
                    return Response(serialized_policy)
                else:
                    return Response(_lt.get_label(errors.err_unknown_resource, lang), status=404)
            else:
                return Response(_lt.get_label(errors.err_user_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_escalation_policy_on_calls(request, conn=None):
    '''
    Gets the on calls of every level of a group.
    :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.policy_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.can_user_view_components(user_perm):
                do_adv_check = permissions.get_user_advanced_check_status(user_perm, org_perm)[0]

                retrieved_groups = db_policies.get_policies(
                    conn, times.get_current_timestamp(), with_policy_ref_id=request.data[var_names.policy_ref_id],
                    with_org_id=org_id, policy_type=constants.group_policy, for_display=True, with_user_id=user_id,
                    check_adv_perm=do_adv_check
                )
                if len(retrieved_groups) > 0:
                    requested_group = list(retrieved_groups.values())[0]
                    on_calls = requested_group.to_dict(basic_info=True, with_on_call=True)[var_names.on_call]
                    return Response(on_calls)
                else:
                    return Response(_lt.get_label(errors.err_unknown_resource, lang), status=404)
            else:
                return Response(_lt.get_label(errors.err_user_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)
