import datetime

from dateutil import parser as dateparser

from anchore_engine import db
from anchore_engine.db import Event
from anchore_engine.subsys import logger


def get_byfilter(userId, session=None, since=None, before=None, next=None, limit=100, **dbfilter):
    if not session:
        session = db.Session

    ret = {'results': [], 'next': None}

    query = session.query(Event).filter(Event.resource_user_id == userId)

    if dbfilter:
        query = query.filter_by(**dbfilter)

    if before:
        query = query.filter(Event.timestamp < before)

    if since:
        query = query.filter(Event.timestamp > since)

    if next:
        query = query.filter(Event.timestamp < next)

    query = query.order_by(Event.timestamp.desc()).limit(limit + 1)

    for db_event in query:
        if len(ret) < limit:
            ret['results'].append(_db_to_dict(db_event))
        else:
            ret['next'] = db_event.timestamp.isoformat()

    return ret


def get_byevent_id(userId, eventId, session=None):
    if not session:
        session = db.Session

    db_event = session.query(Event).filter(Event.resource_user_id == userId, Event.generated_uuid == eventId).one_or_none()

    return _db_to_dict(db_event) if db_event else None


def add(msg, session=None):
    if not session:
        session = db.Session

    db_event = _dict_to_db(msg)

    session.add(db_event)
    session.flush()
    res = db_event.to_detached()

    return _db_to_dict(res)


def delete_byfilter(userId, session=None, since=None, before=None):
    if not session:
        session = db.Session

    ret = {'deleted': []}

    query = session.query(Event).filter(Event.resource_user_id == userId)

    if before:
        query = query.filter(Event.timestamp < before)

    if since:
        query = query.filter(Event.timestamp > since)

    for db_event in query:
        ret['deleted'].append(db_event.generated_uuid)
        session.delete(db_event)

    return ret


def delete_byevent_id(userId, eventId, session=None):
    if not session:
        session = db.Session

    ret = None

    db_event = session.query(Event).filter(Event.resource_user_id == userId, Event.generated_uuid == eventId).one_or_none()
    if db_event:
        ret = db_event.generated_uuid
        session.delete(db_event)

    return ret


def _db_to_dict(db_event):
    msg = {'event': {}, 'generated_uuid': None, 'created_at': None}

    for key, value in vars(db_event).iteritems():
        if key.startswith('_'):
            continue

        if key in ['generated_uuid', 'created_at']:
            msg[key] = value if type(value) != datetime.datetime else _format_timestamp(value)
        elif value:
            if key.startswith('resource') or key.startswith('source'):
                key1, key2 = key.split('_', 1)
                if key1 not in msg['event']:
                    msg['event'][key1] = {}
                msg['event'][key1][key2] = value if type(value) != datetime.datetime else _format_timestamp(value)
            else:
                msg['event'][key] = value if type(value) != datetime.datetime else _format_timestamp(value)

    return msg


def _dict_to_db(msg):
    db_event = Event()

    event_msg = {}
    event_msg.update(msg)

    if event_msg.get('source', None):
        db_event.source_servicename = event_msg['source'].get('servicename', None)
        db_event.source_hostid = event_msg['source'].get('hostid', None)
        db_event.source_base_url = event_msg['source'].get('base_url', None)
        db_event.source_request_id = event_msg['source'].get('request_id', None)

    if event_msg.get('resource', None):
        db_event.resource_user_id = event_msg['resource'].get('user_id', None)
        db_event.resource_id = event_msg['resource'].get('id', None)
        db_event.resource_type = event_msg['resource'].get('type', None)

    db_event.type = event_msg['type']
    db_event.level = event_msg['level']
    db_event.message = event_msg['message']
    db_event.details = event_msg.get('details', {})
    db_event.timestamp = dateparser.parse(event_msg['timestamp'])

    return db_event


def _format_timestamp(ts):
    return ts.isoformat() + 'Z'
