# By: Riasat Ullah
# This file contains all constants and functions related to the Webex integration.

from dbqueries import db_integrations
from utils import constants, integration_type_names as intt, logging, s3, var_names
import datetime
import requests


# webex s3 credential file variables
webex_s3_bucket = 'taskcall-prod-data'
webex_s3_key = 'credentials/webex_credentials.json'

# webex url paths
webex_invitees_path = 'https://webexapis.com/v1/meetingInvitees/bulkInsert'
webex_meetings_path = 'https://webexapis.com/v1/meetings'
webex_token_retrieval_path = 'https://webexapis.com/v1/access_token'

# webex variables
var_id = 'id'
var_web_link = 'webLink'


def get_webex_credentials():
    '''
    Get the credentials needed for handling and making API calls to Webex.
    :return: (dict) of credentials
    '''
    creds = s3.read_json(webex_s3_bucket, webex_s3_key)
    return creds


def get_webex_standard_headers(access_token):
    '''
    Get the standard headers that need to be sent with Webex API calls.
    :param access_token: Webex access token
    :return: (dict) of headers
    '''
    return {"Authorization": "Bearer " + access_token, "Accept": "application/json"}


def webex_refresh_token(conn, timestamp, org_id, webex_org_id, refresh_token):
    '''
    Refresh a Webex token.
    :param conn: db connection
    :param timestamp: timestamp when this request is being made
    :param org_id: organization ID
    :param webex_org_id: unique ID of the organization in Webex
    :param refresh_token: current refresh token
    :return: (str) new access token
    '''
    try:
        new_acc_tok = None
        wbx_creds = get_webex_credentials()
        body = {
            'grant_type': 'refresh_token',
            'client_id': wbx_creds[var_names.client_id],
            'client_secret': wbx_creds[var_names.client_secret],
            'refresh_token': refresh_token,
        }
        response = requests.post(webex_token_retrieval_path, data=body)
        status = response.status_code
        output = response.json()
        if status in [200, 201]:
            new_acc_tok = output[var_names.access_token]
            external_info = {
                var_names.access_token: new_acc_tok,
                var_names.refresh_token: output[var_names.refresh_token]
            }
            db_integrations.check_and_update_organization_integration_details(
                conn, timestamp, org_id, intt.webex, webex_org_id, external_info
            )
        return new_acc_tok
    except (ConnectionRefusedError, ConnectionError) as e:
        logging.exception('Failed to connect with Webex')
        logging.exception(str(e))
        raise ConnectionRefusedError
    except Exception as e:
        logging.exception('Webex API request failed...')
        logging.exception(str(e))
        raise ConnectionRefusedError


def create_meeting(conn, timestamp, org_id, wbx_org_id, wbx_acc_tok, wbx_ref_tok, title, assignee_emails):
    '''
    Create a Webex meeting.
    :param conn: db connection
    :param timestamp: timestamp when this request is being made
    :param org_id: ID of the organization
    :param wbx_org_id: Webex organization ID
    :param wbx_acc_tok: Webex access token
    :param wbx_ref_tok: Webex refresh token
    :param title: title to set for the meeting (should be the title of the incident)
    :param assignee_emails: (list) of email addresses of assignees
    '''
    meeting_id, conf_url = None, None
    if len(assignee_emails) > 0:
        invitees = [{'email': item} for item in assignee_emails]
        if len(invitees) > 0:
            start_time = timestamp + datetime.timedelta(minutes=1)
            end_time = start_time + datetime.timedelta(minutes=30)
            body = {
                'title': title,
                'start': start_time.strftime(constants.timestamp_format),
                'end': end_time.strftime(constants.timestamp_format),
                'invitees': invitees
            }

            resp = requests.post(webex_meetings_path, json=body, headers=get_webex_standard_headers(wbx_acc_tok))
            if resp.status_code == 200:
                resp_body = resp.json()
                meeting_id = resp_body[var_id]
                conf_url = resp_body[var_web_link]
            else:
                new_acc_tok = webex_refresh_token(conn, timestamp, org_id, wbx_org_id, wbx_ref_tok)
                if new_acc_tok is not None:
                    resp = requests.post(webex_meetings_path, json=body,
                                         headers=get_webex_standard_headers(new_acc_tok))
                    if resp.status_code == 200:
                        resp_body = resp.json()
                        meeting_id = resp_body[var_id]
                        conf_url = resp_body[var_web_link]

    return meeting_id, conf_url


def add_invitees(conn, timestamp, org_id, wbx_org_id, wbx_acc_tok, wbx_ref_tok, meeting_id, assignee_emails):
    '''
    Add more participants to a Webex meeting.
    :param conn: db connection
    :param timestamp: timestamp when this request is being made
    :param org_id: ID of the organization
    :param wbx_org_id: Webex organization ID
    :param wbx_acc_tok: Webex access token
    :param wbx_ref_tok: Webex refresh token
    :param meeting_id: ID of the Webex meeting
    :param assignee_emails: (list) of email addresses of assignees
    '''
    if len(assignee_emails) > 0:
        invitees = [{'email': item} for item in assignee_emails]
        if len(invitees) > 0:
            body = {
                'meeting': meeting_id,
                'invitees': invitees
            }
            resp = requests.post(webex_meetings_path, json=body, headers=get_webex_standard_headers(wbx_acc_tok))
            if resp.status_code != 200:
                new_acc_tok = webex_refresh_token(conn, timestamp, org_id, wbx_org_id, wbx_ref_tok)
                if new_acc_tok is not None:
                    requests.post(webex_meetings_path, json=body, headers=get_webex_standard_headers(new_acc_tok))
