# By : Asif Al Shahriar
# This file contains all constants related to the HaloITSM integration.

from dbqueries.integrations import db_haloitsm
from integrations.freshservice import default_status_value
from utils import constants, errors, var_names
import json
import logging
import requests

# HaloITSM variables
var_ticket = 'ticket'
var_summary = 'summary'
var_id = 'id'
var_details = 'details'
var_priority_id = 'priority_id'
var_status_id = 'status_id'
var_ticket_type_id = 'ticket_type_id'
var_name = 'name'

# Default Values
default_status_value = 1 # Open
default_priority_value = 1 # Urgent

# HaloITSM priority/urgency
halo_priority_mapping = {
    1   : constants.critical_urgency,
    2   : constants.high_urgency,
    3   : constants.medium_urgency,
    4   : constants.low_urgency
}

# HaloITSM status
halo_status_mapping = {
    1 : constants.open_state, # New
    2 : constants.acknowledged_state, #In Progress
    9 : constants.resolved_state # closed
}

url_authorize_haloitsm_account = 'https://{0}/auth/token'
url_create_ticket = 'https://{0}/api/tickets'
url_update_ticket = 'https://{0}/api/tickets'

def authorize_haloitsm_account(domain, id , secret):
    '''
    Get the access token for further requests
    :param domain : The domain this integration associated with
    :param id: Client id
    :param secret: Client secret
    '''

    headers_body = {"Content-Type": "application/x-www-form-urlencoded"}
    req_body= {
        'grant_type': 'client_credentials',
        'client_id': id,
        'client_secret': secret,
        'scope': 'all'
    }
    response = requests.post(url_authorize_haloitsm_account.format(domain),headers=headers_body,data= req_body)
    response = response.json()
    return response['token_type']+" "+response['access_token']


def create_haloitsm_ticket(conn, timestamp, org_id, integ_key, integ_info, task_title, text_msg,
                               instance_state, urgency):
    '''
    Creates a HaloITSM ticket.
    :param conn: db connection
    :param timestamp: timestamp when this request is being made
    :param org_id: organization ID
    :param integ_key: the integration key of this HaloITSM integration
    :param integ_info: additional info of this integration
    :param task_title: instance task title that will be used as the summary of the issue
    :param text_msg: instance text details that will be used as the description of the issue
    :param instance_state: the current state of the instance
    :param urgency: the urgency level of the instance
    :return: (str) -> ticket ID (None if ticket cannot be created)
    '''
    halo_det = db_haloitsm.get_haloitsm_accounts(conn, timestamp, org_id, integration_key=integ_key)
    if len(halo_det) == 0:
        raise LookupError(errors.err_haloitsm_integration_not_found)

    halo_status = int(integ_info[var_names.status][instance_state])\
        if integ_info[var_names.status] is not None else default_status_value
    halo_priority = int(integ_info[var_names.urgency_level][str(urgency)]) \
        if integ_info[var_names.urgency_level] is not None else default_priority_value

    domain = halo_det[0][var_names.vendor_endpoint]
    client_id = halo_det[0][var_names.access_token]
    client_secret = halo_det[0][var_names.secret_token]
    access_token = authorize_haloitsm_account(domain, client_id, client_secret)
    headers = {"Content-Type": "application/json", "Accept": "application/json", "Authorization": access_token}
    ticket_create_body = [{'summary': task_title,
                           'details': '<div>' + text_msg if text_msg is not None else task_title + '</div>',
                           'tickettype_id': integ_info[var_names.ticket_type],
                           'priority_id': 1,
                           'category_1': 'Account Administration',
                           'impact': 0,
                           'urgency': halo_priority,
                           'status_id': halo_status,
                           'dateoccurred': timestamp,
                           'customfields': [{'id': 165, 'value': 1},
                                            {'id': 166, 'value': 1},
                                            {'id': 223, 'value': False}]}]

    ticket_id, exe_status, exe_output = None, 400, errors.err_processing_failed
    try:
        response = requests.post(url_create_ticket.format(domain),
                             headers=headers,
                             data=json.dumps(ticket_create_body))
        exe_status = response.status_code
        exe_output = response.json()
        if exe_status in [200, 201]:
            ticket_id = str(exe_output['id'])
        else:
            logging.exception('Failed to create HaloITSM ticket')
            logging.exception(exe_output)
    except Exception as e:
        logging.exception('Failed to create HaloITSM ticket')
        logging.exception(str(e))
    finally:
        return ticket_id, exe_status, exe_output


def update_haloitsm_ticket(conn, timestamp, org_id, integ_key, integ_info, ticket_id, new_state=None,
                               new_urgency=None, new_note=None):
    '''
    Update a HaloITSM ticket.
    :param conn: db connection
    :param timestamp: timestamp when this request is being made
    :param org_id: organization ID
    :param integ_key: the integration key of this Jira integration
    :param integ_info: additional info of this integration
    :param ticket_id: ID of the ticket
    :param new_state: new state of the instance
    :param new_urgency: new urgency level of the instance
    :param new_note: new note added to the instance
    :param voice_url: the URL of the voice message
    '''
    halo_det = db_haloitsm.get_haloitsm_accounts(conn, timestamp, org_id, integration_key=integ_key)
    if len(halo_det) == 0:
        raise LookupError(errors.err_haloitsm_integration_not_found)

    domain = halo_det[0][var_names.vendor_endpoint_name]
    client_id = halo_det[0][var_names.access_token]
    client_secret = halo_det[0][var_names.secret_token]
    access_token = authorize_haloitsm_account(domain, client_id, client_secret)
    headers = {"Content-Type": "application/json", "Accept": "application/json", "Authorization": access_token}

    to_sync_status = new_state is not None and integ_info[var_names.status] is not None
    to_sync_urgency = new_urgency is not None and integ_info[var_names.urgency_level] is not None
    to_sync_notes = new_note is not None and integ_info[var_names.to_sync_notes]

    if to_sync_status or to_sync_urgency :
        body = {}
        body['id'] = ticket_id
        if to_sync_status:
            body['status_id'] = int(integ_info[var_names.status][new_state])
        if to_sync_urgency:
            body['priority_id'] = int(integ_info[var_names.urgency_level][str(new_urgency)])

        try:
            response = requests.put(url_update_ticket.format(domain), headers=headers, data=json.dumps(body))
            if response.status_code not in [200, 201]:
                logging.error('Failed - HaloITSM ticket ' + ticket_id + ' update - ' + str(body))
                logging.exception(response.json())
        except Exception as e:
            logging.exception('Failed to update HaloITSM ticket')
            logging.exception(str(e))

    # if to_sync_notes:
    #     body = {'body': new_note, 'private': True}
    #     try:
    #         response = requests.post(url_add_ticket_note.format(domain, ticket_id), headers=headers,
    #                                  data=json.dumps(body), auth=HTTPBasicAuth(api_key, 'x'))
    #         if response.status_code not in [200, 201]:
    #             logging.error('Failed - Freshservice ticket ' + ticket_id + ' add note - ' + str(body))
    #             logging.exception(response.json())
    #     except Exception as e:
    #         logging.exception('Failed to add note to Freshservice ticket')
    #         logging.exception(str(e))


def get_field_value(field, payload):
    """
    Get a field value from the payload's ticket object.
    """
    ticket = payload[var_ticket]
    if not isinstance(ticket, dict):
        return None

    return ticket[field]

