# By: Riasat Ullah
# This file contains incident api views.

from data_syncers import syncer_api_keys
from dbqueries import db_members, db_users
from exceptions.user_exceptions import InvalidRequest, UnauthorizedRequest
from rest_framework.decorators import api_view, throttle_classes
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from translators import label_translator as _lt
from utils import errors, 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'])
@throttle_classes([UserRateThrottle])
def list_users(request, conn=None, cache=None):
    '''
    List the users.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response -> list of dict
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        optional_fields = [var_names.team_ref_id, var_names.keywords]
        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, [], optional_fields)

            current_time = times.get_current_timestamp()
            api_key = tokenizer.extract_api_key(request)
            details = syncer_api_keys.get_api_key_details(conn, cache, current_time, api_key)
            if details is None:
                raise UnauthorizedRequest(errors.err_api_key_request_denied)
            key_id, org_id, perm, for_user, ip_restrictions = details
            request_validator.validate_api_ip_allowed(request, ip_restrictions)

            team_ref_id = request.data[var_names.team_ref_id] if var_names.team_ref_id in request.data else None
            keywords = request.data[var_names.keywords] if var_names.keywords in request.data else None

            # We are using component view permission for now, but will have to move to org member view permission
            if permissions.has_user_permission(perm, permissions.USER_COMPONENTS_VIEW_PERMISSION):
                members_list = db_members.get_members_list(
                    conn, current_time, org_id, row_limit=1000, search_words=keywords, team_ref_id=team_ref_id
                )
                # pref_name, disp_name, user_email, role_name, job_title, photo_url, is_locked
                members_dict_list = [
                    {
                        var_names.preferred_username: x[0],
                        var_names.display_name: x[1],
                        var_names.email: x[2],
                        var_names.user_role: x[3],
                        var_names.job_title: x[4],
                        var_names.profile_picture: x[5],
                        var_names.is_locked: x[6]
                    }
                    for x in members_list
                ]
                return Response(members_dict_list)
            else:
                return Response(_lt.get_label(errors.err_api_key_permission, 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 PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        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'])
@throttle_classes([UserRateThrottle])
def user_details(request, conn=None, cache=None):
    '''
    Get the details of a user.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response -> list of dict
    '''
    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
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)

            current_time = times.get_current_timestamp()
            api_key = tokenizer.extract_api_key(request)
            details = syncer_api_keys.get_api_key_details(conn, cache, current_time, api_key)
            if details is None:
                raise UnauthorizedRequest(errors.err_api_key_request_denied)
            key_id, org_id, perm, for_user, ip_restrictions = details
            request_validator.validate_api_ip_allowed(request, ip_restrictions)

            pref_name = request.data[var_names.preferred_username]

            # We are using component view permission for now, but will have to move to org member view permission
            if permissions.has_user_permission(perm, permissions.USER_COMPONENTS_VIEW_PERMISSION):
                profile = db_users.get_user_details(conn, current_time, org_id, preferred_username=pref_name)
                return Response(profile)
            else:
                return Response(_lt.get_label(errors.err_api_key_permission, 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 PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        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)
