# By: Riasat Ullah
# This file contains recent changes related views.

from dbqueries import db_change_events
from exceptions.user_exceptions import 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 list_change_events(request, conn=None):
    '''
    Gets a list of recent changes. All changes can be obtained or can be filtered by service.
    They can also be filtered by similarity to a specific incident.
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> list
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        optional_fields = [var_names.services, var_names.teams, var_names.integration_type, var_names.instance_id,
                           var_names.timestamp, var_names.last_update, var_names.row_limit, var_names.row_offset]
        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 not permissions.has_org_permission(org_perm, permissions.ORG_RECENT_CHANGES_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.can_user_view_components(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            check_timestamp = times.get_timestamp_from_string(request.data[var_names.timestamp])\
                if var_names.timestamp in request.data and request.data[var_names.timestamp] is not None\
                else times.get_current_timestamp()
            serv_refs = request.data[var_names.services] if var_names.services in request.data else None
            team_refs = request.data[var_names.teams] if var_names.teams in request.data else None
            itg_type = request.data[var_names.integration_type] if var_names.integration_type in request.data else None
            inst_id = request.data[var_names.instance_id] if var_names.instance_id in request.data else None
            min_tmsp = times.get_timestamp_from_string(request.data[var_names.last_update])\
                if var_names.last_update in request.data and request.data[var_names.last_update] is not None else None
            row_limit = request.data[var_names.row_limit] if var_names.row_limit in request.data else None
            row_offset = request.data[var_names.row_offset] if var_names.row_offset in request.data else None

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

            if inst_id is None:
                ev_list = db_change_events.list_change_events(
                    conn, check_timestamp, org_id, serv_ref_ids=serv_refs, team_ref_ids=team_refs,
                    integ_types=itg_type, min_timestamp=min_tmsp, user_id=user_id, check_adv_perm=do_adv_check,
                    row_limit=row_limit, row_offset=row_offset
                )
                return Response(ev_list)
            else:
                ev_list = db_change_events.list_instance_change_events(conn, check_timestamp, org_id, user_id, inst_id)
                return Response(ev_list[:2])
        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 redact_change_event(request, conn=None):
    '''
    Redacts a change event. It is completely deleted from the database.
    :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.event_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_RECENT_CHANGES_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.is_user_admin(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            event_id = request.data[var_names.event_id]

            db_change_events.delete_change_event(conn, times.get_current_timestamp(), event_id, org_id, user_id)

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