import logging
import json

from pymisp import MISPAttribute, MISPEvent, MISPTag,  MISPObject
from . import check_input_attribute, checking_error, standard_error_message

from qintel_helper import search_qsentry

logger = logging.getLogger('qintel_qsentry')
logger.setLevel(logging.DEBUG)

moduleinfo = {
    'version': '1.0',
    'author': 'Qintel, LLC',
    'description': 'Query Qintel QSentry for ip intelligence',
    'module-type': ['hover', 'expansion']
}

moduleconfig = ['token', 'remote']

misperrors = {'error': 'Error'}

mispattributes = {
    'input': ['ip-src', 'ip-dst'],
    'output': ['ip-src', 'ip-dst', 'AS', 'freetext'],
    'format': 'misp_standard'
}

TAG_COLOR = {
    'benign': '#27ae60',
    'suspicious': '#e6a902',
    'malicious': '#c0392b'
}

CLIENT_HEADERS = {
        'User-Agent': f"MISP/{moduleinfo['version']}",
}


def _return_error(message):
    misperrors['error'] = message
    return misperrors


def _make_tags(enriched_attr, result):

    for tag in result['tags']:
        color = TAG_COLOR['suspicious']
        if tag == 'criminal':
            color = TAG_COLOR['malicious']

        t = MISPTag()
        t.from_dict(**{
            'name': f'qintel:tag="{tag}"',
            'colour': color
        })
        enriched_attr.add_tag(**t)

    return enriched_attr


def _make_enriched_attr(event, result, orig_attr):

    enriched_object = MISPObject('Qintel Threat Enrichment')
    enriched_object.add_reference(orig_attr.uuid, 'related-to')

    enriched_attr = MISPAttribute()
    enriched_attr.from_dict(**{
        'value': orig_attr.value,
        'type': orig_attr.type,
        'distribution': 0,
        'object_relation': 'enriched-attr',
        'to_ids': orig_attr.to_ids
    })

    enriched_attr = _make_tags(enriched_attr, result)
    enriched_object.add_attribute(**enriched_attr)

    comment_attr = MISPAttribute()
    comment_attr.from_dict(**{
        'value': '\n'.join(result.get('descriptions', [])),
        'type': 'text',
        'object_relation': 'descriptions',
        'distribution': 0
    })
    enriched_object.add_attribute(**comment_attr)

    last_seen = MISPAttribute()
    last_seen.from_dict(**{
        'value': result.get('last_seen'),
        'type': 'datetime',
        'object_relation': 'last-seen',
        'distribution': 0
    })
    enriched_object.add_attribute(**last_seen)

    event.add_attribute(**orig_attr)
    event.add_object(**enriched_object)

    return event


def _make_asn_attr(event, result, orig_attr):

    asn_object = MISPObject('asn')
    asn_object.add_reference(orig_attr.uuid, 'related-to')

    asn_attr = MISPAttribute()
    asn_attr.from_dict(**{
        'type': 'AS',
        'value': result.get('asn'),
        'object_relation': 'asn',
        'distribution': 0
    })
    asn_object.add_attribute(**asn_attr)

    org_attr = MISPAttribute()
    org_attr.from_dict(**{
        'type': 'text',
        'value': result.get('asn_name', 'unknown').title(),
        'object_relation': 'description',
        'distribution': 0
    })
    asn_object.add_attribute(**org_attr)

    event.add_object(**asn_object)

    return event


def _format_hover(event, result):

    enriched_object = event.get_objects_by_name('Qintel Threat Enrichment')[0]

    tags = ', '.join(result.get('tags'))
    enriched_object.add_attribute('Tags', type='text', value=tags)

    return event


def _format_result(attribute, result):

    event = MISPEvent()

    orig_attr = MISPAttribute()
    orig_attr.from_dict(**attribute)

    event = _make_enriched_attr(event, result, orig_attr)
    event = _make_asn_attr(event, result, orig_attr)

    return event


def _check_config(config):
    if not config:
        return False

    if not isinstance(config, dict):
        return False

    if config.get('token', '') == '':
        return False

    return True


def METHOD_NAME(request):
    if not request.get('attribute'):
        return f'{standard_error_message}, {checking_error}'

    check_reqs = ('type', 'value')
    if not check_input_attribute(request['attribute'],
                                 requirements=check_reqs):
        return f'{standard_error_message}, {checking_error}'

    if request['attribute']['type'] not in mispattributes['input']:
        return 'Unsupported attribute type'


def handler(q=False):
    if not q:
        return False

    request = json.loads(q)
    config = request.get('config')

    if not _check_config(config):
        return _return_error('Missing Qintel token')

    check_request_error = METHOD_NAME(request)
    if check_request_error:
        return _return_error(check_request_error)

    search_args = {
        'token': config['token'],
        'remote': config.get('remote')
    }

    try:
        result = search_qsentry(request['attribute']['value'], **search_args)
    except Exception as e:
        return _return_error(str(e))

    event = _format_result(request['attribute'], result)
    if not request.get('event_id'):
        event = _format_hover(event, result)

    event = json.loads(event.to_json())

    ret_result = {key: event[key] for key in ('Attribute', 'Object') if key
                  in event}
    return {'results': ret_result}


def introspection():
    return mispattributes


def version():
    moduleinfo['config'] = moduleconfig
    return moduleinfo