# By: Riasat Ullah
# This file contains functions related to status page views.

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


@api_view(['POST'])
def create_status_page(request, conn=None, cache=None):
    '''
    Create a new status page.
    :param request: HttpRequest
    :param conn: db connection
    :param cache: cache client
    :return: HttpResponse -> str
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_name, var_names.description, var_names.is_published, var_names.url_extension,
                           var_names.url, var_names.business_services, var_names.layout_type, var_names.uptime_bar_days,
                           var_names.show_past_incidents, var_names.subscription_type, var_names.colors,
                           var_names.navigation_bar, var_names.footer, var_names.operational_message,
                           var_names.page_timezone, var_names.language, var_names.google_analytics_id,
                           var_names.hide_seo, var_names.max_pending_hours, var_names.auto_post,
                           var_names.post_permissions, var_names.edit_permissions, var_names.approvers]
        optional_fields = [var_names.is_private, var_names.sso_ref_id, var_names.ip_address]
        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)

            is_published = request.data[var_names.is_published]
            is_private = request.data[var_names.is_private] if var_names.is_private in request.data else False
            sso_ref_id = request.data[var_names.sso_ref_id] if var_names.sso_ref_id in request.data else None
            ip_address = request.data[var_names.ip_address] if var_names.ip_address in request.data else None
            post_page_perm = request.data[var_names.post_permissions]
            edit_page_perm = request.data[var_names.edit_permissions]
            current_time = times.get_current_timestamp()

            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 (is_private or sso_ref_id is not None or ip_address is not None) and \
                    not permissions.has_org_permission(org_perm, permissions.ORG_STATUS_PAGES_PRIVATE_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if sso_ref_id is not None and \
                    not permissions.has_org_permission(org_perm, permissions.ORG_EXTERNAL_SSO_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if (post_page_perm is not None or edit_page_perm is not None) and \
                    not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_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)

            # Uniqueness of the URL is checked in the query
            page_ref_id = db_status_pages.create_status_page(
                conn, current_time, org_id, is_published,
                request.data[var_names.page_name], request.data[var_names.description],
                request.data[var_names.url_extension], request.data[var_names.url],
                request.data[var_names.business_services], request.data[var_names.layout_type],
                request.data[var_names.uptime_bar_days], request.data[var_names.show_past_incidents],
                request.data[var_names.subscription_type], request.data[var_names.colors],
                request.data[var_names.navigation_bar], request.data[var_names.footer],
                request.data[var_names.operational_message], request.data[var_names.page_timezone],
                request.data[var_names.language], request.data[var_names.google_analytics_id],
                request.data[var_names.hide_seo], is_private, sso_ref_id, ip_address,
                request.data[var_names.max_pending_hours], request.data[var_names.auto_post],
                post_page_perm, edit_page_perm, request.data[var_names.approvers]
            )

            if is_published:
                syncer_status_pages.refresh_status_page_details(conn, cache, current_time, page_ref_id)

            return Response(page_ref_id)
        except (InvalidRequest, 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 edit_status_page(request, conn=None, cache=None):
    '''
    Edit a status page.
    :param request: HttpRequest
    :param conn: db connection
    :param cache: cache client
    :return: HttpResponse -> str
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_ref_id, var_names.page_name, var_names.description, var_names.is_published,
                           var_names.business_services, var_names.layout_type, var_names.uptime_bar_days,
                           var_names.show_past_incidents, var_names.subscription_type, var_names.colors,
                           var_names.navigation_bar, var_names.footer, var_names.operational_message,
                           var_names.page_timezone, var_names.language, var_names.google_analytics_id,
                           var_names.hide_seo, var_names.max_pending_hours, var_names.auto_post,
                           var_names.post_permissions, var_names.edit_permissions, var_names.approvers]
        optional_fields = [var_names.is_private, var_names.sso_ref_id, var_names.ip_address]
        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)

            page_ref_id = request.data[var_names.page_ref_id]
            is_published = request.data[var_names.is_published]
            is_private = request.data[var_names.is_private] if request.data[var_names.is_private] else False
            sso_ref_id = request.data[var_names.sso_ref_id] if var_names.sso_ref_id in request.data else None
            ip_address = request.data[var_names.ip_address] if var_names.ip_address in request.data else None
            post_page_perm = request.data[var_names.post_permissions]
            edit_page_perm = request.data[var_names.edit_permissions]
            current_time = times.get_current_timestamp()

            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 (is_private or sso_ref_id is not None or ip_address is not None) and \
                    not permissions.has_org_permission(org_perm, permissions.ORG_STATUS_PAGES_PRIVATE_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if sso_ref_id is not None and \
                    not permissions.has_org_permission(org_perm, permissions.ORG_EXTERNAL_SSO_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if (post_page_perm is not None or edit_page_perm is not None) and \
                    not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_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_pages.edit_status_page(
                conn, current_time, org_id, page_ref_id, is_published,
                request.data[var_names.page_name], request.data[var_names.description],
                request.data[var_names.business_services], request.data[var_names.layout_type],
                request.data[var_names.uptime_bar_days], request.data[var_names.show_past_incidents],
                request.data[var_names.subscription_type], request.data[var_names.colors],
                request.data[var_names.navigation_bar], request.data[var_names.footer],
                request.data[var_names.operational_message], request.data[var_names.page_timezone],
                request.data[var_names.language], request.data[var_names.google_analytics_id],
                request.data[var_names.hide_seo], is_private, sso_ref_id, ip_address,
                request.data[var_names.max_pending_hours], request.data[var_names.auto_post],
                post_page_perm, edit_page_perm, request.data[var_names.approvers], user_id
            )

            if is_published:
                syncer_status_pages.refresh_status_page_details(conn, cache, current_time, page_ref_id)

            return Response(info.msg_status_page_edited)
        except (InvalidRequest, 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 delete_status_page(request, conn=None, cache=None):
    '''
    Delete a status page.
    :param request: HttpRequest
    :param conn: db connection
    :param cache: cache client
    :return: HttpResponse -> str
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_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]
            current_time = times.get_current_timestamp()

            db_status_pages.delete_status_page(conn, current_time, org_id, page_ref_id, user_id)
            syncer_status_pages.remove_status_page_details(cache, page_ref_id)

            return Response(info.msg_status_page_deleted)
        except (InvalidRequest, 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_status_pages(request, conn=None):
    '''
    List all the status pages of an organization.
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> list
    '''
    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 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)

            data_list = db_status_pages.list_status_pages(conn, times.get_current_timestamp(), org_id)
            return Response(data_list)
        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_status_page_details(request, conn=None):
    '''
    Gets the details of a status page.
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> list
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_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)

            details = db_status_pages.get_status_page_details(conn, times.get_current_timestamp(), org_id,
                                                              request.data[var_names.page_ref_id])
            return Response(details)
        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 publish_status_page(request, conn=None, cache=None):
    '''
    Publish a status page.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: JSON response -> list
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_ref_id, var_names.version]
        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]
            version_id = request.data[var_names.version]
            current_time = times.get_current_timestamp()

            db_status_pages.publish_status_page(conn, current_time, org_id, page_ref_id, version_id, user_id)
            syncer_status_pages.refresh_status_page_details(conn, cache, current_time, page_ref_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 unpublish_status_page(request, conn=None, cache=None):
    '''
    Unpublish a status page.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: JSON response -> list
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_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]
            current_time = times.get_current_timestamp()

            db_status_pages.unpublish_status_page(conn, current_time, org_id, page_ref_id, user_id)
            syncer_status_pages.remove_status_page_details(cache, page_ref_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 get_status_page_components(request, conn=None):
    '''
    Get the components of the current version of the status page (published or not).
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> (list of list) of business services
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.page_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)

            page_ref_id = request.data[var_names.page_ref_id]
            current_time = times.get_current_timestamp()
            pg_comps = db_status_pages.get_status_page_components(conn, current_time, org_id, page_ref_id)

            return Response(pg_comps)
        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 add_status_page_image_info(request, conn=None):
    '''
    Update the details of a status page with the location where the images are stored on s3.
    :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.images]
        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)

            current_time = times.get_current_timestamp()
            page_ref_id = request.data[var_names.page_ref_id]
            images = request.data[var_names.images]

            db_status_pages.update_state_page_images_info(conn, current_time, org_id, page_ref_id, images)
            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 get_status_page_published_image_info(request, conn=None):
    '''
    Get the urls of all the images that are associated with a published 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]
        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)

            current_time = times.get_current_timestamp()
            page_ref_id = request.data[var_names.page_ref_id]
            pub_img_urls = db_status_pages.get_status_page_published_image_urls(conn, current_time, org_id, page_ref_id)
            return Response(pub_img_urls)
        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)
