from pyramid.view import view_config
from .view_helpers import *
from bson import json_util
import requests


# JSON
@view_config(route_name="json_lastcard", renderer="prettyjson")
def json_lastcard(request):
    return get_latest_card(request)


@view_config(route_name="json_valuesbetween", renderer="prettyjson")
@view_config(route_name="json_valuesbetween_wparams", renderer="prettyjson")
def json_valuesbetween(request):
    end = datetime.now()
    try:  # Attempt to get a value from the request.
        end = request.matchdict['enddt']
        end = end.replace("T", " ")
        end = datetime.strptime(end, "%Y-%m-%d %H:%M:%S.%fZ")
    except KeyError:
        pass

    start = end - timedelta(days=2)
    try:  # Attempt to get a value from the request.
        start = request.matchdict['startdt']
        start = start.replace("T", " ")
        start = datetime.strptime(start, "%Y-%m-%d %H:%M:%S.%fZ")
    except KeyError:
        pass

    tag_data = []
    grouped_tags = request.db['wellData'].aggregate([
        {
            '$match': {"timestamp": {"$gt": start, "$lte": end}}
        },
        {
            '$sort': {"tagname": 1, "timestamp": 1}
        },
        {
            '$group': {
                '_id': "$tagname",
                'timestamps': {'$push': "$timestamp"},
                'currentValues': {'$push': "$currentValue"}
            }
        }
    ])

    for t in grouped_tags:
        tag_data.append({"tagname": t['_id'], "timestamps": list(map(lambda a: a.strftime("%Y-%m-%d %H:%M:%S.%fZ"), t['timestamps'])), "currentValues": t['currentValues']})
    return {'values': tag_data, 'start': start, 'end': end}


@view_config(route_name="json_valuesdaterange", renderer="prettyjson")
def json_valuesdaterange(request):
    date_limits = list(request.db['wellData'].aggregate([
        {"$group": {
            "_id": 'null',
            "last": {"$max": "$timestamp"},
            "first": {"$min": "$timestamp"}
        }}
    ]))[0]
    return {'first_date': date_limits['first'], 'last_date': date_limits['last']}


@view_config(route_name="json_singlevaluebetween", renderer="prettyjson")
@view_config(route_name="json_singlevaluebetween_wparams", renderer="prettyjson")
def json_singlevaluebetween(request):
    end = datetime.now()
    try:  # Attempt to get a value from the request.
        end = request.matchdict['enddt']
        end = end.replace("T", " ")
        end = datetime.strptime(end, "%Y-%m-%d %H:%M:%S.%fZ")
    except KeyError:
        pass

    start = end - timedelta(days=7)
    try:  # Attempt to get a value from the request.
        start = request.matchdict['startdt']
        start = start.replace("T", " ")
        start = datetime.strptime(start, "%Y-%m-%d %H:%M:%S.%fZ")
    except KeyError:
        pass

    tag_data = []
    grouped_tags = request.db['wellData'].aggregate([
        {"$match": {"tagname": request.matchdict['tagname'], 'timestamp': {'$gt': start, '$lte': end}}},
        {
            '$sort': {"timestamp": 1}
        }
    ])
    return {'values': list(grouped_tags), 'start': start, 'end': end}


@view_config(route_name="json_singlevaluedaterange", renderer="prettyjson")
def json_singlevaluedaterange(request):
    date_limits = list(request.db['wellData'].aggregate([
        {"$match": {"tagname": request.matchdict['tagname']}},
        {"$group": {
            "_id": 'null',
            "last": {"$max": "$timestamp"},
            "first": {"$min": "$timestamp"}
        }}
    ]))[0]
    return {'first_date': date_limits['first'], 'last_date': date_limits['last']}


@view_config(route_name="json_runstatusnow", renderer="prettyjson")
def json_runstatusnow(request):
    status = False
    try:
        status = list(request.db['runStatus'].find().sort("timestamp", -1).limit(1))[0]
    except IndexError:
        pass

    return {'runstatus': status}


@view_config(route_name="json_updateconfig", renderer="prettyjson", request_method='POST', permission="edit")
def json_updateconfig(request):
    conv_to_float = [
        'deltaT',
        'pumpDiameter',
        'fluidGradient',
        'tubingID',
        'tubingOD',
        'tubingAnchorDepth',
        'structuralRating',
        'stuffingBoxFriction',
        'tubingHeadPressure'
    ]
    t_conv_to_float = ['length', 'diameter', 'dampingFactor']
    jsb = request.json_body
    new_config = {}
    new_config['timestamp'] = datetime.utcnow()
    new_config['storedBy'] = request.authenticated_userid
    new_config['wellName'] = jsb['wellName']
    new_config['tapers'] = []
    for p in conv_to_float:
        new_config[p] = float(jsb[p])

    for t_i in range(0, len(jsb['tapers'])):
        t = {}
        for p in t_conv_to_float:
            t[p] = float(jsb['tapers'][t_i][p])
        t['material'] = jsb['tapers'][t_i]['material']
        new_config['tapers'].append(t)

    result = request.db['wellConfiguration'].insert(new_config)

    addr_obj = list(request.db['pocConfiguration'].find({"_id": "pocIPAddress"}))
    address = 'localhost'
    if len(addr_obj) > 0:
        address = addr_obj[0]['pocIPAddress']

    update_url = "http://{}:8000/config?update=true".format(address)
    r = requests.get(update_url)
    pocCmdSts = "OK" if r.status_code == 200 else "failed"

    return {'new_config': request.json_body, 'stored_result': result, 'updated': pocCmdSts}


@view_config(route_name="json_cmd", renderer="prettyjson", permission="edit")
def json_cmd(request):
    action = request.matchdict['action']
    address = get_poc_address(request) or 'localhost'

    java_url = {}
    java_url['start'] = "http://{}:8000/command?cmd=start&user={}".format(address, request.authenticated_userid)
    java_url['stop'] = "http://{}:8000/command?cmd=stop&user={}".format(address, request.authenticated_userid)
    java_url['shake'] = "http://{}:8000/shake".format(address)

    r = requests.get(java_url[action])
    return r.text if r.status_code == 200 else {"status": "failure sending command"}


@view_config(route_name="json_shake", renderer="prettyjson", permission="view")
def json_shake(request):
    address = get_poc_address(request) or 'localhost'
    url = "http://{}:8000/shake".format(address)

    r = requests.get(url)
    return r.text if r.status_code == 200 else {"status": "failure sending command"}


@view_config(route_name="json_update_poc_address", renderer="prettyjson", request_method='POST', permission="edit")
def json_update_poc_address(request):
    try:
        new_addr = request.json_body['pocIPAddress']
        upsert = request.db['pocConfiguration'].update_one({"_id": "pocIPAddress"}, {"$set": {'pocIPAddress': new_addr}}, upsert=True)
        return {"status": "OK"}
    except KeyError:
        return {"status": "failure"}


@view_config(route_name="json_users", renderer="prettyjson", request_method='POST', permission="edit")
def json_newuser(request):
    jsb = request.json_body
    if request.db['users'].count({"username": jsb['username']}) > 0:
        fail_reason = "There is already a user with this username"
        return {"status": 'fail', "info": fail_reason}

    elif len(jsb['username']) < 5:
        fail_reason = "The username must be at least 5 characters"
        return {"status": 'fail', "info": fail_reason}

    elif len(jsb['password']) < 5:
        fail_reason = "The password must be at least 5 characters"
        return {"status": 'fail', "info": fail_reason}

    else:
        set_return = set_password(request, jsb['username'], jsb['password'])
        return {'status': "OK"}


@view_config(route_name="json_users", renderer="prettyjson", permission="edit", request_method='GET')
def json_getuser(request):
    user_list = []
    users = list(request.db['users'].find())
    for user in users:
        user_list.append(user['username'])
    return {'users': user_list}


@view_config(route_name="json_users", renderer="prettyjson", permission="edit", request_method='DELETE')
def json_deleteuser(request):
    request.db['users'].remove({'username': request.json_body['username']})
    user_list = []
    users = list(request.db['users'].find())
    for user in users:
        user_list.append(user['username'])
    return {'users': user_list}


@view_config(route_name="json_users", renderer="prettyjson", request_method='PUT', permission="edit")
def json_updateuser(request):
    jsb = request.json_body
    if len(jsb['username']) < 5:
        fail_reason = "The username must be at least 5 characters"
        return {"status": 'fail', "info": fail_reason}

    elif len(jsb['password']) < 5:
        fail_reason = "The password must be at least 5 characters"
        return {"status": 'fail', "info": fail_reason}

    else:
        set_return = set_password(request, jsb['username'], jsb['password'])
        return {'status': "OK"}


@view_config(route_name="json_setpoints", renderer="prettyjson", request_method='GET', permission='edit')
def json_setpoints(request):
    return {'setpoints': list(request.db['setpoints'].find())}


@view_config(route_name="json_setpoints", renderer="prettyjson", request_method='POST', permission='edit')
def json_setpoints_post(request):
    jsb = request.json_body
    try:
        name = jsb['name']
        value = jsb['value']
        upsert = request.db['setpoints'].update_one({"name": name}, {"$set": {'value': value, 'storedBy': request.authenticated_userid, 'lastStored': datetime.utcnow()}}, upsert=True)

        address = get_poc_address(request) or 'localhost'
        url = "http://{}:8000/update?setpoint={}".format(address, name)
        print(url)
        r = requests.get(url)
        update_status = r.text if r.status_code == 200 else {"status": "failure sending command"}

        return {"updated": list(request.db['setpoints'].find_one({"name": name})), 'status': update_status}
    except KeyError:
        return {"status": "bad reqest"}


runModes = {0: 'poc', 1: 'manual', 2: 'timer'}


@view_config(route_name="json_mode", renderer="prettyjson", request_method='POST', permission='edit')
def json_mode_post(request):
    jsb = request.json_body
    try:
        mode = jsb['mode']
        upsert = request.db['setpoints'].update_one({"name": "runMode"}, {"$set": {'value': mode, 'storedBy': request.authenticated_userid, 'lastStored': datetime.utcnow()}}, upsert=True)

        address = get_poc_address(request) or 'localhost'
        url = "http://{}:8000/mode?mode={}&user={}".format(address, runModes[mode], request.authenticated_userid)
        print(url)
        r = requests.get(url)
        update_status = r.text if r.status_code == 200 else {"status": "failure sending command"}

        return {"updated": request.db['setpoints'].find_one({"name": "runMode"}), 'status': update_status}
    except KeyError:
        return {"status": "bad reqest"}
