# By: Riasat Ullah
# This file contains code for serving organization specific pages.

from constants import api_paths, component_names as cnm, label_names as lnm, var_names, static_vars
from django.core import exceptions
from django.http import HttpResponse, JsonResponse
from django.views.decorators.http import require_http_methods
from taskcallweb import settings
from system_tests.test_data import test_data_organization, test_data_users
from translators import label_translator as lt
from utils import helpers, logging
from validations import request_validator
import json


@require_http_methods(['POST'])
def get_account_owner(request):
    '''
    Gets the username and email of the current account owner.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            if settings.TEST_MODE:
                output = None
                for key in test_data_users.user_details:
                    item = test_data_users.user_details[key]
                    if item[var_names.user_role] == static_vars.owner_role:
                        output = [item[var_names.first_name] + ' ' + item[var_names.last_name], key]

                if output is not None:
                    return JsonResponse(output, status=200, safe=False)
                else:
                    return JsonResponse(lt.get_label(lnm.err_unknown_resource, lang), status=400, safe=False)
            else:
                body = dict()
                status, output = helpers.post_api_request(api_paths.owner, body, request)
                return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def transfer_account_ownership(request):
    '''
    Transfers the ownership of an account to another user.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            body = json.loads(request.body.decode())
            if settings.TEST_MODE:
                return JsonResponse('Ownership has been transferred', status=200, safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.owner_transfer, body, request)
                return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def get_cards(request):
    '''
    Get all the cards that are stored for the organization.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            if settings.TEST_MODE:
                status = 200
                output = test_data_organization.account_cards
            else:
                body = dict()
                status, output = helpers.post_api_request(api_paths.cards, body, request)

            card_id_mapper = dict()
            for i in range(0, len(output)):
                card_id_mapper[i] = output[i][var_names.card_id]
                output[i][var_names.card_id] = i

            request.session[var_names.card_id_mapper] = card_id_mapper
            return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def add_card(request):
    '''
    Add a new organization card
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            body = json.loads(request.body.decode())

            if var_names.customer_id in request.session:
                body[var_names.customer_id] = request.session[var_names.customer_id]
                del request.session[var_names.customer_id]

                if settings.TEST_MODE:
                    return JsonResponse('New card has been added', safe=False)
                else:
                    status, output = helpers.post_api_request(api_paths.cards_add, body, request)
                    return JsonResponse(output, status=status, safe=False)
            else:
                return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def delete_card(request):
    '''
    Deletes an existing organization card.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            try:
                body = json.loads(request.body.decode())
                mapped_id = body[var_names.card_id]

                if var_names.card_id_mapper in request.session and\
                        mapped_id in request.session[var_names.card_id_mapper]:
                    card_id = request.session[var_names.card_id_mapper][mapped_id]

                    body = {var_names.card_id: card_id}
                    if settings.TEST_MODE:
                        return JsonResponse('Card has been deleted', safe=False)
                    else:
                        status, output = helpers.post_api_request(api_paths.cards_delete, body, request)
                        return JsonResponse(output, status=status, safe=False)
                else:
                    logging.error('Could not find card id in session')
                    return JsonResponse(lt.get_label(lnm.err_system_error, lang), status=500, safe=False)
            except Exception as e:
                logging.exception(str(e))
                return JsonResponse(lt.get_label(lnm.err_system_error, lang), status=500, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def set_default_card(request):
    '''
    Set a specific card as the default card.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):

            body = json.loads(request.body.decode())
            mapped_id = body[var_names.card_id]

            if var_names.card_id_mapper in request.session and mapped_id in request.session[var_names.card_id_mapper]:
                card_id = request.session[var_names.card_id_mapper][mapped_id]

                body = {var_names.card_id: card_id}
                if settings.TEST_MODE:
                    return JsonResponse('Card has been set as default', safe=False)
                else:
                    status, output = helpers.post_api_request(api_paths.cards_set_default, body, request)
                    return JsonResponse(output, status=status, safe=False)
            else:
                logging.error('Could not find card id in session')
                return JsonResponse(lt.get_label(lnm.err_system_error, lang), status=500, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def get_active_credits(request):
    '''
    Get all the credits an organization has.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            if settings.TEST_MODE:
                status, output = 200, test_data_organization.account_credits
            else:
                body = dict()
                status, output = helpers.post_api_request(api_paths.credits_active, body, request)
            return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def redeem_credit(request):
    '''
    Redeem credit for an organization.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            body = json.loads(request.body.decode())
            if settings.TEST_MODE:
                status, output = 200, 'Success'
            else:
                status, output = helpers.post_api_request(api_paths.credits_redeem, body, request)

            return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def get_stripe_token(request):
    '''
    Get the stripe vendor token.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            body = dict()
            status, output = helpers.post_api_request(api_paths.stripe_token, body, request)

            if status == 200:
                request.session[var_names.customer_id] = output[1]
                output = [output[0], output[2]]

            return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def get_current_subscription(request):
    '''
    Get the
    :param request: Http request
    :return: JSON Response -> dict of lists
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            if settings.TEST_MODE:
                return JsonResponse(test_data_organization.organization_subscription, safe=False)
            else:
                body = dict()
                status, output = helpers.post_api_request(api_paths.subscription_current, body, request)
                return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def update_subscription(request):
    '''
    Add a subscription to an account.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            if settings.TEST_MODE:
                return JsonResponse('New subscription has been added', safe=False)
            else:
                body = json.loads(request.body.decode())
                status, output = helpers.post_api_request(api_paths.subscription_update, body, request)
                return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def update_billing_currency(request):
    '''
    Updates the billing currency of an account.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            if settings.TEST_MODE:
                return JsonResponse('Billing currency has been updated', safe=False)
            else:
                body = json.loads(request.body.decode())
                status, output = helpers.post_api_request(api_paths.billing_currency_update, body, request)
                return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def save_onboarding_answers(request):
    '''
    Save the answers provided by the owner of the organization in the onboarding questionnaire.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            body = json.loads(request.body.decode())
            if settings.TEST_MODE:
                return JsonResponse('Success', safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.onboarding_save_answers, body, request)
                return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def get_incidents_api_url(request):
    '''
    Get the incidents api url given the region the server is running in.
    This is needed to display the api command in the onboarding process.
    :param request: Http request
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            if settings.TEST_MODE:
                inc_api_url = static_vars.regional_test_mode_urls[settings.REGION]['incidents_api_base_url']
            elif settings.TEST_SERVER:
                inc_api_url = static_vars.regional_test_server_urls[settings.REGION]['incidents_api_base_url']
            else:
                inc_api_url = static_vars.regional_urls[settings.REGION]['incidents_api_base_url']
            return JsonResponse(inc_api_url, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def get_billing_information(request):
    '''
    Get billing information of an organization. These are additional and optional details.
    :param request: Http request
    :return: JsonResponse
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            if settings.TEST_MODE:
                return JsonResponse(test_data_organization.billing_info, safe=False)
            else:
                body = dict()
                status, output = helpers.post_api_request(api_paths.billing_information, body, request)
                return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def update_billing_information(request):
    '''
    Update the optional billing information of an organization.
    :param request: Http request
    :return: JsonResponse
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            body = json.loads(request.body.decode())
            if settings.TEST_MODE:
                return JsonResponse(lt.get_label(lnm.msg_org_billing_information_updated, lang), safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.billing_information_update, body, request)
                return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['POST'])
def get_bills(request):
    '''
    Get all the bills of an organization.
    :param request: Http request
    :return: JsonResponse
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        if request_validator.user_in_session(request):
            body = json.loads(request.body.decode())
            if settings.TEST_MODE:
                return JsonResponse(test_data_organization.account_bills, safe=False)
            else:
                status, output = helpers.post_api_request(api_paths.bills, body, request)
                return JsonResponse(output, status=status, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)


@require_http_methods(['GET'])
def get_bill_pdf(request, bill_id):
    '''
    Gets the pdf of a bill/invoice.
    :param request: Http request
    :param bill_id: the unique ID of the bill
    :return: Http response
    '''
    if request.method == 'GET':
        lang = request_validator.get_user_language(request)

        if request_validator.user_in_session(request):
            nav_bar_components = request_validator.get_nav_bar_components(request)

            has_view_perm, has_edit_perm = request_validator.get_session_permission(
                request, cnm.dis_com_organization, nav_bar_components
            )
            if not has_edit_perm:
                raise exceptions.PermissionDenied

            if settings.TEST_MODE:
                status = 200
                bill_details = {**test_data_organization.account_bill_details[0],
                                **test_data_organization.organization_details,
                                **{var_names.vat_id: test_data_organization.billing_info[var_names.vat_id]}}
            else:
                request_body = {var_names.bill_id: int(bill_id)}
                status, bill_details = helpers.post_api_request(api_paths.bills_details, request_body, request)

            if status == 200 and bill_details is not None:
                bill_details[var_names.bill_id] = str(bill_details[var_names.bill_id]).zfill(9)
                context = bill_details
                context[var_names.name] = 'TaskCall Cloud Services, S.L.'\
                    if bill_details[var_names.bill_year] <= 2023 else 'TaskCall Inc.'
                try:
                    pdf = helpers.render_to_pdf('tmpl_invoice_pdf.html', context)
                    if pdf:
                        response = HttpResponse(pdf, content_type='application/pdf')
                        filename = 'Invoice_' + bill_details[var_names.bill_id] + '.pdf'
                        content = "attachment; filename={0}".format(filename)
                        response['Content-Disposition'] = content
                        return response
                    return JsonResponse(lt.get_label(lnm.err_invoice_download, lang), status=500, safe=False)
                except Exception as e:
                    logging.exception(str(e))
                    return JsonResponse(lt.get_label(lnm.err_invoice_download, lang), status=500, safe=False)
            else:
                return JsonResponse(lt.get_label(lnm.err_invoice_download, lang), status=500, safe=False)
        else:
            return JsonResponse(lt.get_label(lnm.err_unauthorized_access, lang), status=401, safe=False)
