# By: Riasat Ullah
# This file contains views for status page posts.

from data_syncers import syncer_status_pages
from dbqueries.status_pages import db_status_page_posts
from exceptions.user_exceptions import 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 CACHE_CLIENT, CONN_POOL
from validations import request_validator
import jwt


@api_view(['POST'])
def create_post(request, conn=None, cache=None):
    '''
    Create a status page. Both incidents and maintenance posts are created by the same call.
    If approval is required before posts can be published, a pending item will be created instead.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_ref_id, var_names.event_type, var_names.title, var_names.message,
                           var_names.status, var_names.notify_subscribers, var_names.impacted_business_services]
        optional_fields = [var_names.post_id, var_names.page_impact, var_names.next_update,
                           var_names.maintenance_start, var_names.maintenance_end, var_names.auto_update]
        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, optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            page_ref_id = request.data[var_names.page_ref_id]
            evn_type = request.data[var_names.event_type]
            post_title = request.data[var_names.title]
            post_message = request.data[var_names.message]
            post_status = request.data[var_names.status]
            to_ntf = request.data[var_names.notify_subscribers]

            syncer_status_pages.create_status_page_post(
                conn, cache, times.get_current_timestamp(), org_id, page_ref_id,
                evn_type, post_title, post_message, post_status,
                page_impact=request.data[var_names.page_impact] if var_names.page_impact in request.data else None,
                next_update_time=request.data[var_names.next_update]
                if var_names.next_update in request.data else None,
                notify_subscribers=to_ntf,
                impacted_components=request.data[var_names.impacted_business_services],
                post_id=request.data[var_names.post_id] if var_names.post_id in request.data else None,
                maintenance_start=times.get_timestamp_from_string(request.data[var_names.maintenance_start])
                if var_names.maintenance_start in request.data else None,
                maintenance_end=times.get_timestamp_from_string(request.data[var_names.maintenance_end])
                if var_names.maintenance_end in request.data else None,
                auto_update=request.data[var_names.auto_update] if var_names.auto_update in request.data else None,
                user_id=user_id
            )
            return Response(_lt.get_label(info.msg_success, lang))
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        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 approve_pending_post(request, conn=None, cache=None):
    '''
    Approve a status page event.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_ref_id, var_names.event_ref_id]
        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)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            page_ref_id = request.data[var_names.page_ref_id]
            syncer_status_pages.approve_status_page_event(
                conn, cache, times.get_current_timestamp(), org_id, page_ref_id=page_ref_id,
                event_ref_id=request.data[var_names.event_ref_id], user_id=user_id
            )
            return Response(_lt.get_label(info.msg_success, lang))
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        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 reject_pending_post(request, conn=None):
    '''
    Reject a status page event.
    :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.page_ref_id, var_names.event_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_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            db_status_page_posts.reject_event(
                conn, times.get_current_timestamp(), org_id, page_ref_id=request.data[var_names.page_ref_id],
                event_ref_id=request.data[var_names.event_ref_id], user_id=user_id
            )
            return Response(_lt.get_label(info.msg_success, lang))
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        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_post(request, conn=None, cache=None):
    '''
    Delete a status page post. The record is deleted from posts table, but not the events table.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_ref_id, var_names.post_id]
        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)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.is_user_admin(user_perm) and \
                    not permissions.has_user_permission(user_perm, permissions.USER_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            syncer_status_pages.delete_post(conn, cache, times.get_current_timestamp(), org_id,
                                            request.data[var_names.page_ref_id],
                                            request.data[var_names.post_id], user_id)
            return Response(_lt.get_label(info.msg_success, lang))
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        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_posts(request, conn=None):
    '''
    List the posts that have been made on a status page.
    :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.page_ref_id, var_names.is_maintenance]
        optional_fields = [var_names.status, var_names.keywords, 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, expected_fields, optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            status_type = request.data[var_names.status] if var_names.status in request.data else None
            keywords = request.data[var_names.keywords] if var_names.keywords in request.data 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]

            pub_posts = db_status_page_posts.list_posts(
                conn, times.get_current_timestamp(), org_id, request.data[var_names.page_ref_id],
                user_id, is_maintenance=request.data[var_names.is_maintenance], post_type=status_type,
                row_limit=row_limit, row_offset=row_offset, search_words=keywords, check_adv_perm=do_adv_check
            )
            return Response(pub_posts)
        except LookupError 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_post_details(request, conn=None):
    '''
    Get the details of a status page post.
    :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.page_ref_id, var_names.page_post_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_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_STATUS_PAGES_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]
            details = db_status_page_posts.get_post_details(
                conn, times.get_current_timestamp(), org_id, request.data[var_names.page_ref_id],
                request.data[var_names.page_post_id], user_id, check_adv_perm=do_adv_check
            )

            return Response(details)
        except LookupError 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 sync_post(request, conn=None):
    '''
    Syncs a post with an internal incident.
    :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.page_ref_id, var_names.post_id, var_names.organization_instance_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_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.is_user_admin(user_perm) and \
                    not permissions.has_user_permission(user_perm, permissions.USER_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            db_status_page_posts.sync_post_with_system_incident(
                conn, times.get_current_timestamp(), org_id, request.data[var_names.page_ref_id],
                request.data[var_names.post_id], request.data[var_names.organization_instance_id], user_id
            )
            return Response(_lt.get_label(info.msg_success, lang))
        except LookupError 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_pending_posts(request, conn=None):
    '''
    List the posts that are pending.
    :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.page_ref_id]
        optional_fields = [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, expected_fields, optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            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]
            pnd_posts = db_status_page_posts.list_pending_posts(
                conn, times.get_current_timestamp(), org_id, request.data[var_names.page_ref_id],
                user_id, row_limit=row_limit, row_offset=row_offset, check_adv_perm=do_adv_check
            )
            return Response(pnd_posts)
        except LookupError 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_pending_post_details(request, conn=None):
    '''
    Get the details of a status page event.
    :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.page_ref_id, var_names.event_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_STATUS_PAGES_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_STATUS_PAGES_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]
            pnd_details = db_status_page_posts.get_pending_post_details(
                conn, times.get_current_timestamp(), org_id, request.data[var_names.page_ref_id],
                request.data[var_names.event_ref_id], user_id, check_adv_perm=do_adv_check
            )
            return Response(pnd_details)
        except LookupError 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)
