# By: Riasat Ullah
# This file contains business service related views.


from dbqueries import db_business_services, db_users
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 errors, info, logging, permissions, times, tokenizer, var_names
from utils.db_connection import CONN_POOL
from validations import request_validator
import jwt


@api_view(['POST'])
def create_business_service(request, conn=None):
    '''
    Creates a new business service for the organization.
    :param request: Http request
    :param conn: db connection
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.service_name]
        optional_fields = [var_names.supporting_tech_services, var_names.supporting_business_services,
                           var_names.teams, var_names.description, var_names.min_urgency]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields, optional_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):
                current_time = times.get_current_timestamp()

                db_business_services.create_business_service(
                    conn, current_time, org_id, request.data[var_names.service_name],
                    supporting_technical_services=request.data[var_names.supporting_tech_services]
                    if var_names.supporting_tech_services in request.data else None,
                    supporting_business_services=request.data[var_names.supporting_business_services]
                    if var_names.supporting_business_services in request.data else None,
                    associated_teams=request.data[var_names.teams] if var_names.teams in request.data else None,
                    description=request.data[var_names.description] if var_names.description in request.data else None,
                    min_urgency=request.data[var_names.min_urgency] if var_names.min_urgency in request.data else None
                )

                return Response(_lt.get_label(info.msg_business_service_created, lang))
            else:
                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 edit_business_service(request, conn=None):
    '''
    Edit an existing business service.
    :param request: Http request
    :param conn: db connection
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.business_service_ref_id, var_names.service_name]
        optional_fields = [var_names.supporting_tech_services, var_names.supporting_business_services,
                           var_names.teams, var_names.description, var_names.min_urgency]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields, optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            # business service edits are allowed until Managers
            if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_EDIT_PERMISSION):
                current_time = times.get_current_timestamp()
                db_business_services.edit_business_service(
                    conn, current_time, request.data[var_names.business_service_ref_id], org_id,
                    request.data[var_names.service_name],
                    supporting_technical_services=request.data[var_names.supporting_tech_services]
                    if var_names.supporting_tech_services in request.data else None,
                    supporting_business_services=request.data[var_names.supporting_business_services]
                    if var_names.supporting_business_services in request.data else None,
                    associated_teams=request.data[var_names.teams] if var_names.teams in request.data else None,
                    description=request.data[var_names.description] if var_names.description in request.data else None,
                    min_urgency=request.data[var_names.min_urgency] if var_names.min_urgency in request.data else None)

                return Response(_lt.get_label(info.msg_business_service_edited, lang))
            else:
                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_business_service(request, conn=None):
    '''
    Deletes a business service.
    :param request: Http request
    :param conn: db connection
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.business_service_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)

            # business service edits are allowed until Managers
            if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_EDIT_PERMISSION):
                current_time = times.get_current_timestamp()
                bus_ref_id = request.data[var_names.business_service_ref_id]

                db_business_services.delete_business_service(conn, current_time, bus_ref_id, org_id)
                return Response(_lt.get_label(info.msg_business_service_deleted, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError, DependencyFound) 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_business_services_list(request, conn=None):
    '''
    Get the list of business services.
    :param request: Http request
    :param conn: db connection
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_VIEW_PERMISSION):
                current_time = times.get_current_timestamp()
                bus_list = db_business_services.list_business_services(conn, current_time, org_id)
                return Response(bus_list)
            else:
                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 get_business_service_details(request, conn=None):
    '''
    Get the details of a business service.
    :param request: Http request
    :param conn: db connection
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            # business service edits are allowed until Managers
            if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_EDIT_PERMISSION):
                bus_ref_id = request.data[var_names.business_service_ref_id]
                current_time = times.get_current_timestamp()

                bus_details = db_business_services.list_business_services(conn, current_time, org_id,
                                                                          bus_ref_id=bus_ref_id)
                bus_details = bus_details[0] if len(bus_details) > 0 else dict()
                return Response(bus_details)
            else:
                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 get_business_service_subscriptions(request, conn=None):
    '''
    Get the list of business services that a user is subscribed to.
    :param request: Http request
    :param conn: db connection
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.preferred_username]
        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_BUSINESS_SERVICES_SUBSCRIPTION_PERMISSION):
                pref_name = request.data[var_names.preferred_username]
                current_time = times.get_current_timestamp()
                if pref_name is None:
                    subscriber_id = user_id
                else:
                    if not permissions.is_user_admin(user_perm):
                        return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

                    subscriber_id = db_users.get_user_ids_from_preferred_usernames(
                        conn, current_time, org_id, [pref_name])[0]

                subs = db_business_services.get_user_business_service_subscriptions(conn, current_time, subscriber_id)
                return Response(subs)
            else:
                return Response(_lt.get_label(errors.err_subscription_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 update_business_service_subscriptions(request, conn=None):
    '''
    Update the list of business services that a user subscribes to.
    :param request: Http request
    :param conn: db connection
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.preferred_username, var_names.business_services]
        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_BUSINESS_SERVICES_SUBSCRIPTION_PERMISSION):
                bus_ref_ids = request.data[var_names.business_services]
                pref_name = request.data[var_names.preferred_username]
                current_time = times.get_current_timestamp()
                if pref_name is None:
                    subscriber_id = user_id
                else:
                    if not permissions.is_user_admin(user_perm):
                        return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

                    subscriber_id = db_users.get_user_ids_from_preferred_usernames(
                        conn, current_time, org_id, [pref_name])[0]

                db_business_services.update_business_service_subscriptions(conn, current_time, org_id,
                                                                           subscriber_id, bus_ref_ids)
                return Response(_lt.get_label(info.msg_business_service_subscriptions_updated, lang))
            else:
                return Response(_lt.get_label(errors.err_subscription_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)
