# By: Riasat Ullah
# This file contains functions related to team views.

from dbqueries import db_teams, db_workflows
from exceptions.user_exceptions import DependencyFound, InvalidRequest, NotUniqueValue, 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 list_teams(request, conn=None):
    '''
    Gets the list of teams of the organization that are viewable by the user.
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> list
    '''
    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 not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_TEAMS_VIEW_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            do_adv_check = permissions.get_user_advanced_check_status(user_perm, org_perm)[0]
            current_time = times.get_current_timestamp()

            data_list = db_teams.list_teams(conn, current_time, org_id, user_id=user_id if do_adv_check else None)
            return Response(data_list)
        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 list_user_teams(request, conn=None):
    '''
    Gets the list of teams of the organization that the requesting user is a member of.
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> list
    '''
    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 not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_TEAMS_VIEW_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            data_list = db_teams.user_teams_list(conn, times.get_current_timestamp(), org_id, user_id)
            return Response(data_list)
        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_team_details(request, conn=None):
    '''
    Gets the details of a team.
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> list
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.team_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 not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_TEAMS_VIEW_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            do_adv_check = permissions.get_user_advanced_check_status(user_perm, org_perm)[0]
            current_time = times.get_current_timestamp()

            details = db_teams.get_team_details(conn, current_time, org_id, request.data[var_names.team_ref_id],
                                                user_id=user_id if do_adv_check else None)
            return Response(details)
        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_team(request, conn=None):
    '''
    Create a team.
    :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.team_name, var_names.users, var_names.is_public]
        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 not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_TEAMS_EDIT_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            db_teams.create_team(conn, times.get_current_timestamp(), org_id, request.data[var_names.team_name],
                                 request.data[var_names.users], is_public=request.data[var_names.is_public])
            return Response(_lt.get_label(info.msg_team_created, lang))
        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_team(request, conn=None):
    '''
    Create a team.
    :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.team_ref_id, var_names.team_name, var_names.is_public]
        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 not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_TEAMS_EDIT_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            db_teams.edit_team(conn, times.get_current_timestamp(), org_id, user_id,
                               request.data[var_names.team_ref_id], request.data[var_names.team_name],
                               is_public=request.data[var_names.is_public])
            return Response(_lt.get_label(info.msg_team_edited, lang))
        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 delete_team(request, conn=None):
    '''
    Deletes a team.
    :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.team_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)

            team_ref = request.data[var_names.team_ref_id]
            current_time = times.get_current_timestamp()

            if not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_TEAMS_EDIT_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            if permissions.has_org_permission(org_perm, permissions.ORG_WORKFLOWS_PERMISSION):
                team_id = db_teams.get_team_ids_from_ref_ids(conn, current_time, org_id, [team_ref],
                                                             unmasked=False, as_dict=False)[0]
                uses_in_workflows = db_workflows.check_component_in_workflow(
                    conn, current_time, org_id, team_id=team_id)
                if len(uses_in_workflows) > 0:
                    raise DependencyFound(
                        errors.err_workflow_dependency_team_delete,
                        ' - ' + '; '.join([item[var_names.workflow_name] for item in uses_in_workflows])
                    )

            db_teams.delete_team(conn, current_time, org_id, user_id, request.data[var_names.team_ref_id])
            return Response(_lt.get_label(info.msg_team_deleted, lang))
        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 DependencyFound as e:
            logging.exception(e.message + e.additional_message)
            return Response(_lt.get_label(e.message, lang) + e.additional_message, status=400)
        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 add_team_member(request, conn=None):
    '''
    Add a new team member.
    :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.team_ref_id, var_names.preferred_username, var_names.user_role]
        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 not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_TEAMS_EDIT_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            db_teams.add_team_member(conn, times.get_current_timestamp(), org_id, user_id,
                                     request.data[var_names.team_ref_id],
                                     request.data[var_names.preferred_username],
                                     request.data[var_names.user_role])

            return Response(_lt.get_label(info.msg_team_edited, lang))
        except LookupError as e:
            logging.info(str(e))
            return Response(_lt.get_label(errors.err_user_rights, lang), status=400)
        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_team_member_role(request, conn=None):
    '''
    Edit an existing team member's role.
    :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.team_ref_id, var_names.preferred_username, var_names.user_role]
        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 not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_TEAMS_EDIT_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            db_teams.edit_team_member_role(conn, times.get_current_timestamp(), org_id, user_id,
                                           request.data[var_names.team_ref_id],
                                           request.data[var_names.preferred_username],
                                           request.data[var_names.user_role])

            return Response(_lt.get_label(info.msg_team_edited, lang))
        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 delete_team_member(request, conn=None):
    '''
    Delete a team member.
    :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.team_ref_id, 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 not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_TEAMS_EDIT_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            db_teams.delete_team_member(conn, times.get_current_timestamp(), org_id, user_id,
                                        request.data[var_names.team_ref_id],
                                        request.data[var_names.preferred_username])

            return Response(_lt.get_label(info.msg_team_edited, lang))
        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 add_team_component(request, conn=None):
    '''
    Add a new component to a team.
    :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.team_ref_id, var_names.component_type, var_names.component_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)
            comp_type = request.data[var_names.component_type]

            if not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_TEAMS_EDIT_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            if comp_type == var_names.groups and \
                    not permissions.has_org_permission(org_perm, permissions.ORG_GROUPS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            db_teams.add_team_component(conn, times.get_current_timestamp(), org_id, user_id,
                                        request.data[var_names.team_ref_id], comp_type,
                                        request.data[var_names.component_ref_id])

            return Response(_lt.get_label(info.msg_team_edited, lang))
        except NotUniqueValue as e:
            return Response(_lt.get_label(errors.err_team_component_duplicate, lang) + ' - ' + str(e), status=400)
        except (InvalidRequest, LookupError) as e:
            logging.info(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_team_component(request, conn=None):
    '''
    Delete a component from a team.
    :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.team_ref_id, var_names.component_type, var_names.component_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)
            comp_type = request.data[var_names.component_type]

            if not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_TEAMS_EDIT_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            if comp_type == var_names.groups and \
                    not permissions.has_org_permission(org_perm, permissions.ORG_GROUPS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            db_teams.delete_team_component(conn, times.get_current_timestamp(), org_id, user_id,
                                           request.data[var_names.team_ref_id], comp_type,
                                           request.data[var_names.component_ref_id])

            return Response(_lt.get_label(info.msg_team_edited, lang))
        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)
