# By: Riasat Ullah
# This file contains views to fetch live data for status pages.

from data_syncers import syncer_status_pages
from dbqueries.status_pages import db_status_pages, db_status_page_previews, db_status_page_subscribers
from exceptions.user_exceptions import UnauthorizedRequest
from modules import status_page_notifier
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 live_current_status(request, conn=None, cache=None):
    '''
    Get the details needed for a live status page.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: JSON response -> dict of page details
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.with_posts]
        page_url = None
        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)
            page_url = tokenizer.verify_public_request(request)[0]

            live_page = syncer_status_pages.get_live_status_page(
                conn, cache, times.get_current_timestamp(), page_url=page_url)
            if live_page is None:
                raise LookupError(errors.err_unknown_resource)
            else:
                if not request.data[var_names.with_posts]:
                    del live_page[var_names.posts]
                return Response(live_page)
        except LookupError as e:
            logging.error('Status page: ' + errors.err_unknown_resource + ' - ' + str(page_url))
            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 live_published_posts(request, conn=None):
    '''
    Get posts for the live status page.
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> dict of page details
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_ref_id, var_names.start_period, var_names.end_period,
                           var_names.is_maintenance]
        page_url = None
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            page_url = tokenizer.verify_public_request(request)[0]

            current_time = times.get_current_timestamp()
            page_ref_id = request.data[var_names.page_ref_id]
            start_period = times.get_timestamp_from_string(request.data[var_names.start_period]).date()
            end_period = times.get_timestamp_from_string(request.data[var_names.end_period]).date()
            is_maintenance = request.data[var_names.is_maintenance]

            posts = db_status_page_previews.get_status_page_published_posts(
                conn, current_time, check_start=start_period, check_end=end_period, for_published_page=True,
                page_url=page_url, page_ref_id=page_ref_id, is_maintenance=is_maintenance,
                is_open=None if is_maintenance else False
            )
            return Response(posts)
        except LookupError as e:
            logging.error('Status page: ' + errors.err_unknown_resource + ' - ' + str(page_url))
            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_live_url(request, conn=None):
    '''
    Gets the live url of a published status page. This is only used to redirect a user to a live page from the
    web application. Hence, their credentials must be checked.
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> dict of page details
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_ref_id]
        page_ref_id = None
        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)

            page_ref_id = request.data[var_names.page_ref_id]
            live_url = db_status_pages.get_status_page_published_url(conn, times.get_current_timestamp(), page_ref_id)
            return Response(live_url)
        except LookupError as e:
            logging.error('Status page: ' + errors.err_unknown_resource + ' - ' + str(page_ref_id))
            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 live_add_subscriber(request, conn=None):
    '''
    Add a subscriber from the live status page.
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> dict of page details
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_ref_id, var_names.subscribers]
        page_url = None
        page_ref_id, sub_ref_list = None, []
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            page_url = tokenizer.verify_public_request(request)[0]

            page_ref_id = request.data[var_names.page_ref_id]
            subscribers = request.data[var_names.subscribers]
            current_timestamp = times.get_current_timestamp()

            org_id, sub_meth = db_status_page_previews.get_subscription_methods_from_status_page_ref_id(
                conn, current_timestamp, page_ref_id)

            if len(subscribers) != 1 or sub_meth is None or subscribers[0][var_names.subscription_type] not in sub_meth:
                raise UnauthorizedRequest

            sub_ref_list = db_status_page_subscribers.add_status_page_subscriber(
                conn, current_timestamp, org_id, page_ref_id, subscribers
            )
            return Response(_lt.get_label(info.msg_status_page_subscriber_added, lang))
        except LookupError as e:
            logging.error('Status page: ' + errors.err_unknown_resource + ' - ' + str(page_url))
            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:
            syncer_status_pages.send_status_page_subscriber_confirmation_request(conn, page_ref_id, sub_ref_list)
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def live_confirm_subscriber(request, conn=None):
    '''
    Confirm a status page subscription.
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> dict of page details
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_ref_id, var_names.subscriber_ref_id]
        page_url = None
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            page_url = tokenizer.verify_public_request(request)[0]

            page_ref_id = request.data[var_names.page_ref_id]
            subscriber_ref_id = request.data[var_names.subscriber_ref_id]
            current_timestamp = times.get_current_timestamp()

            org_id, sub_meth = db_status_page_previews.get_subscription_methods_from_status_page_ref_id(
                conn, current_timestamp, page_ref_id)

            sub_list = db_status_page_subscribers.list_status_page_subscribers(
                conn, current_timestamp, org_id, page_ref_id, subscribers=[subscriber_ref_id]
            )
            if len(sub_list) > 0:
                if db_status_page_subscribers.confirm_status_page_subscription(
                    conn, current_timestamp, page_ref_id, subscriber_ref_id
                ):
                    return Response(sub_list[0])
            return Response(_lt.get_label(errors.err_unknown_resource, lang), status=404)
        except LookupError as e:
            logging.error('Status page: ' + errors.err_unknown_resource + ' - ' + str(page_url))
            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 live_cancel_subscriber(request, conn=None):
    '''
    Cancel a status page subscription.
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> dict of page details
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_ref_id, var_names.subscriber_ref_id]
        page_url = None
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            page_url = tokenizer.verify_public_request(request)[0]

            page_ref_id = request.data[var_names.page_ref_id]
            subscriber_ref_id = request.data[var_names.subscriber_ref_id]
            current_timestamp = times.get_current_timestamp()

            org_id, sub_meth = db_status_page_previews.get_subscription_methods_from_status_page_ref_id(
                conn, current_timestamp, page_ref_id)

            sub_list = db_status_page_subscribers.list_status_page_subscribers(
                conn, current_timestamp, org_id, page_ref_id, subscribers=[subscriber_ref_id]
            )
            if len(sub_list) > 0:
                db_status_page_subscribers.delete_status_page_subscriber(
                    conn, current_timestamp, org_id, page_ref_id, [subscriber_ref_id])
                return Response(sub_list[0])

            return Response(_lt.get_label(errors.err_unknown_resource, lang), status=404)
        except LookupError as e:
            logging.error('Status page: ' + errors.err_unknown_resource + ' - ' + str(page_url))
            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)
