import base64
import http.client
import json
import requests

from datetime import datetime, timedelta
from pymongo import MongoClient
from haversine import haversine

import time


# Functions
def getLocationName(locationId):
    if locationId == "0001":
        return "01_nalepkova-71"
    if locationId == "0002":
        return "02_lesobar"
    if locationId == "0003":
        return "03_rozhledna"
    if locationId == "0004":
        return "04_cafelouka"
    if locationId == "0005":
        return "05_nalepkova71-snowing"
    if locationId == "0006":
        return "06_campus"
    if locationId == "0007":
        return "07_efekt-inside"
    if locationId == "0008":
        return "08_efekt-outside"
    if locationId == "0009":
        return "09_spilberk-uvoz-15"
    if locationId == "000a":
        return "10_spilberk-socha-jana-skacela"
    if locationId == "000b":
        return "11_spilberk-hrad"
    if locationId == "000c":
        return "12_nalepkova-71-outside"
    if locationId == "000d":
        return  "13_zabovresky-lidl-outside"
    return "00_unknown"


def getSF(sfStr):
    if sfStr == "SF7BW125":
        return 7
    if sfStr == "SF8BW125":
        return 8
    if sfStr == "SF9BW125":
        return 9
    if sfStr == "SF10BW125":
        return 10
    if sfStr == "SF11BW125":
        return 11
    if sfStr == "SF12BW125":
        return 12


def getTimestamp(timeStr):
    dateTimeStr = timeStr[0:10] + " " + timeStr[11:19]
    dateTime = datetime.strptime(dateTimeStr, "%Y-%m-%d %H:%M:%S") + timedelta(hours=1)
    return datetime.timestamp(dateTime)


def getGatewayes(uplinkGws, locationId):
    gatewayes = []
    for uplinkGw in uplinkGws:
        gwId = uplinkGw["gtw_id"]
        rssi = uplinkGw["rssi"]
        snr = uplinkGw["snr"]

        request = "https://www.thethingsnetwork.org/gateway-data/gateway/" + gwId
        response = requests.get(request)
        unparsedContent = response.content.decode("utf-8")
        content = json.loads(unparsedContent)
        gatewayInfo = content[gwId]

        distance = getGWDistance(gatewayInfo, locationId)
        gwName = getGWName(gatewayInfo)

        gateway = {
            "gw_id": gwId,
            "name": gwName,
            "rssi": rssi,
            "snr": snr,
            "distance_in_km": distance,
        }
        gatewayes.append(gateway)

    return gatewayes


def getGWDistance(gatewayInfo, locationId):
    myLocation = (0, 0)
    if locationId == "0001":
        myLocation = (49.20844547, 16.54891351)
    if locationId == "0002":
        myLocation = (49.21316788371159, 16.537835597991947)
    if locationId == "0003":
        myLocation = (49.21484991328758, 16.54428362846375)
    if locationId == "0004":
        myLocation = (49.210967141922836, 16.556868553161625)
    if locationId == "0005":
        myLocation = (49.20844547, 16.54891351)
    if locationId == "0006":
        myLocation = (49.17687755, 16.565910915627235)
    if locationId == "0007":
        myLocation = (49.21653889372744, 16.587327718734745)
    if locationId == "0008":
        myLocation = (49.21653889372744, 16.587327718734745)
    if locationId == "0009":
        myLocation = (49.1950141, 16.5946358)
    if locationId == "000a":
        myLocation = (49.1934836, 16.5978635)
    if locationId == "000b":
        myLocation = (49.194546095836785, 16.59821212291718)
    if locationId == "000c":
        myLocation = (49.20844547, 16.54891351)
    if locationId == "000d":
        myLocation = (49.209929815643115, 16.593062281608585)
    if locationId == "0045":
        myLocation = (49.20844547, 16.54891351)
    if "location" in gatewayInfo:
        gatewayLocation = (gatewayInfo["location"]["latitude"], gatewayInfo["location"]["longitude"])
        return haversine(myLocation, gatewayLocation)

    # if no location data then return None
    return None


def getGWName(gatewayInfo):
    if "description" in gatewayInfo:
        return gatewayInfo["description"]

    # if no description then return None
    return None


# Script
counter = 1;
while True:
    # connect to pipedream
    pd_bearer = os.environ.get("PD_BEARER")
    conn = http.client.HTTPSConnection('api.pipedream.com')
    conn.request("GET", '/v1/sources/dc_lVuMqgm/event_summaries?expand=event', '', {
        'Authorization': pd_bearer,
    })

    # connect to mongoDB and get last id
    cluster = MongoClient(os.environ.get("MONGODB_CLIENT"))
    db = cluster[os.environ.get("MONGODB_DATABASE")]

    # get uplinks
    res = conn.getresponse()
    events = res.read()
    eventsStr = events.decode("utf-8")
    eventsParsed = json.loads(eventsStr)

    # get newest payload/loop through payloads
    for data in eventsParsed["data"]:
        # unpack payload
        payloadRaw = data["event"]["body"]["payload_raw"]
        uplink = base64.b64decode(payloadRaw).hex()
        # extract values from uplink
        uplinkId = uplink[0:8]
        locationId = uplink[8:12]

        # get name of location and its collection
        nameOfLocation = getLocationName(locationId)
        locationCol = db[nameOfLocation]

        numOfSameId = locationCol.count_documents({"_id": uplinkId}, limit=1)
        if numOfSameId == 0 and not nameOfLocation == "00_unknown":
            # get wanted information from uplink
            timestamp = getTimestamp(data["event"]["body"]["metadata"]["time"])
            sf = getSF(data["event"]["body"]["metadata"]["data_rate"])
            gatewayes = getGatewayes(data["event"]["body"]["metadata"]["gateways"], locationId)

            # create post to db and post it
            post = {
                "_id": uplinkId,
                "timestamp": timestamp,
                "sf": sf,
                "gatewayes": gatewayes,
            }
            locationCol.insert_one(post)
            print(counter)
            counter = counter + 1

    time.sleep(2)
