# By: Riasat Ullah
# This file contains conference bridge views.

from dbqueries import db_instance_utilities, db_users, db_workflows
from dbqueries.integrations import db_microsoft_teams
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, integration_type_names as intt, 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_conference_bridge(request, conn=None):
    '''
    Creates a new conference bridge.
    :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.conference_name]
        optional_fields = [var_names.conference_phone, var_names.conference_url, var_names.additional_info,
                           var_names.integration_type, var_names.external_id, var_names.external_info]
        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)

            conf_name = request.data[var_names.conference_name]
            conf_phone = request.data[var_names.conference_phone]\
                if var_names.conference_phone in request.data else None
            conf_url = request.data[var_names.conference_url] if var_names.conference_url in request.data else None
            conf_info = request.data[var_names.additional_info] if var_names.additional_info in request.data else None
            integ_type = request.data[var_names.integration_type]\
                if var_names.integration_type in request.data else None

            current_time = times.get_current_timestamp()
            ext_id, ext_info = None, None
            if integ_type is not None:
                if integ_type == intt.microsoft_teams:
                    if conf_info is not None:
                        curr_integs = db_microsoft_teams.get_org_microsoft_teams_integrations(
                            conn, current_time, org_id, conf_info[var_names.integration_key])

                        if len(curr_integs) == 0:
                            return Response(_lt.get_label(errors.err_unknown_resource, lang), status=403)
                        else:
                            chosen_integ = curr_integs[0]
                            tenant_id = chosen_integ[var_names.additional_info][var_names.tenant_id]
                            user_object_ids = chosen_integ[var_names.additional_info][var_names.user_object_id]\
                                if var_names.user_object_id in chosen_integ[var_names.additional_info] else dict()

                            tc_usr_obj_dict = db_users.get_user(
                                conn, current_time, keyed_on=var_names.preferred_username,
                                preferred_username=conf_info[var_names.preferred_username], organization_id=org_id
                            )
                            if len(tc_usr_obj_dict) == 0:
                                return Response(_lt.get_label(errors.err_unknown_resource, lang), status=403)
                            else:
                                tc_usr_id = tc_usr_obj_dict[conf_info[var_names.preferred_username]].user_id
                                ms_usr_obj_id = None
                                for obj_id in user_object_ids:
                                    if user_object_ids[obj_id] == tc_usr_id:
                                        ms_usr_obj_id = obj_id
                                        break

                                if ms_usr_obj_id is None:
                                    return Response(
                                        _lt.get_label(errors.err_conference_bridge_ms_teams_min_requirements, lang),
                                        status=403
                                    )
                                else:
                                    conf_info = {
                                        var_names.external_id: tenant_id,
                                        var_names.user_object_id: ms_usr_obj_id
                                    }
                    else:
                        return Response(_lt.get_label(errors.err_invalid_request, lang), status=400)
                else:
                    ext_id = request.data[var_names.external_id]\
                        if var_names.external_id in request.data else None
                    ext_info = request.data[var_names.external_info]\
                        if var_names.external_info in request.data else None

            if permissions.has_org_permission(org_perm, permissions.ORG_CONFERENCE_BRIDGES_PERMISSION):
                if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_EDIT_PERMISSION):
                    conf_id = db_instance_utilities.create_conference_bridge(
                        conn, current_time, org_id, conf_name, dial_in=conf_phone, url=conf_url, details=conf_info,
                        integration_type=integ_type, external_id=ext_id, external_info=ext_info
                    )
                    return Response(conf_id)
                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 AssertionError:
            logging.exception(errors.err_invalid_request)
            return Response(_lt.get_label(errors.err_invalid_request, lang), status=400)
        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_conference_bridge(request, conn=None):
    '''
    Delete a conference bridge.
    :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.conference_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_CONFERENCE_BRIDGES_PERMISSION):
                if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_EDIT_PERMISSION):

                    conf_id = request.data[var_names.conference_id]
                    current_time = times.get_current_timestamp()
                    uses_in_workflows = db_workflows.check_component_in_workflow(
                        conn, current_time, org_id, conf_id=conf_id)

                    if len(uses_in_workflows) > 0:
                        raise DependencyFound(
                            errors.err_workflow_dependency_conference_bridge_delete,
                            ' - ' + '; '.join([item[var_names.workflow_name] for item in uses_in_workflows])
                        )

                    db_instance_utilities.delete_conference_bridge(conn, current_time, org_id, conf_id)
                    return Response(_lt.get_label(info.msg_conference_bridge_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, 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 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 get_conference_bridges(request, conn=None):
    '''
    Get the list of conference bridges.
    :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_org_permission(org_perm, permissions.ORG_CONFERENCE_BRIDGES_PERMISSION):
                if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_VIEW_PERMISSION):
                    current_time = times.get_current_timestamp()
                    data = db_instance_utilities.get_conference_bridges(conn, current_time, org_id)
                    return Response(data)
                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, 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)
