# By: Riasat Ullah
# This view takes care all interactions with twilio's rest api.

from data_syncers import syncer_communication_vendors
from django.http import HttpResponse
from rest_framework.decorators import api_view
from twilio.twiml.messaging_response import MessagingResponse
from twilio.twiml.voice_response import Gather, VoiceResponse
from translators import label_translator as _lt
from utils import constants, errors, logging, url_paths
from utils.db_connection import CACHE_CLIENT, CONN_POOL
from validations import request_validator, string_validator


@api_view(['GET'])
def twilio_create_call_content(request):
    '''
    This function creates Twiml voice content.
    :param request: Http request
    :return: Http response -> Twiml
    '''
    if request.method == 'GET':
        lang = request.query_params['language']
        message = request.query_params['message']

        resp = VoiceResponse()
        gather = Gather(action=url_paths.communication_twilio_voice_response)
        gather.say(message, voice='man', language=lang)
        resp.append(gather)
        return HttpResponse(resp, content_type='text/xml')


@api_view(['POST'])
def twilio_process_incoming_sms(request, conn=None, cache=None):
    '''
    This function handles and processes incoming sms responses from clients.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response -> str
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        from_number = request.data['From']
        body = request.data['Body']
        logging.info('SMS response received from {0} - {1}'.format(from_number, body))

        resp = MessagingResponse()
        try:
            if string_validator.is_telephone_response_code(body):
                conn = CONN_POOL.get_db_conn() if conn is None else conn
                cache = CACHE_CLIENT if cache is None else cache

                matched, message = syncer_communication_vendors.process_telephone_response(
                    conn, cache, constants.text, body, from_number, constants.twilio)
                if matched:
                    logging.info(message)
                else:
                    logging.info(message)

                resp.message(_lt.get_label(message, lang))

                CONN_POOL.put_db_conn(conn)
            else:
                logging.info(errors.err_invalid_response)
                resp.message(_lt.get_label(errors.err_invalid_response, lang))
            return HttpResponse(resp, content_type='text/xml')
        except Exception as e:
            logging.info(str(e))
            resp.message(_lt.get_label(errors.err_processing_failed, lang))
            return HttpResponse(resp, content_type='text/xml', status=500)


@api_view(['POST'])
def twilio_process_voice_response(request, conn=None, cache=None):
    '''
    This function handles and processes incoming voice call responses from clients.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response -> str
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)

        # Since response from voice calls are made from within the call, the 'To' number is the number dialled,
        # which is the number of the user we called.
        to_number = request.data['To']
        body = request.data['Digits']
        logging.info('Voice response received from {0} - {1}'.format(to_number, body))

        resp = VoiceResponse()
        try:
            if string_validator.is_telephone_response_code(body):
                conn = CONN_POOL.get_db_conn() if conn is None else conn
                cache = CACHE_CLIENT if cache is None else cache

                matched, message = syncer_communication_vendors.process_telephone_response(
                    conn, cache, constants.call, body, to_number, constants.twilio)
                if matched:
                    logging.info(message)
                else:
                    logging.info(message)

                resp.say(_lt.get_label(message, lang))

                CONN_POOL.put_db_conn(conn)
            else:
                logging.info(errors.err_invalid_response)
                resp.say(_lt.get_label(errors.err_invalid_response, lang))
            return HttpResponse(resp, content_type='text/xml')
        except Exception as e:
            logging.info(str(e))
            resp.say(_lt.get_label(errors.err_processing_failed, lang))
            return HttpResponse(resp, content_type='text/xml', status=500)
