import paho.mqtt.client as mqtt
from pymongo.mongo_client import MongoClient
from pymongo.server_api import ServerApi
import json
from datetime import datetime
from zoneinfo import ZoneInfo
import re
import requests
import queue, threading

uri = "mongodb+srv://junyoungjeon:1234QWER@dri-testing-server.fxxkcwo.mongodb.net/?retryWrites=true&w=majority&appName=DRI-TESTING-SERVER"
 
mongo_client = MongoClient(uri, server_api=ServerApi('1'))

try:
    mongo_client.admin.command('ping')
    print("MongoDB Connection is success!")
except Exception as e:
    print(f"MongoDB Connection is failed: {e}")
 

db = mongo_client['DRI_Sensor']
collection = db['Main_Data']
initial_col= db['GPS_Data']

TOPIC_TO_COL = {
    "JunyoungJeon/DRI_Sensor_data": collection,
    "JunyoungJeon/initial_data":initial_col
}
DEFAULT_COL=collection



# Helper function to convert standardized ID back to the original format
def convert_id_to_original_format(raw_id: str) -> str:
    
    if len(raw_id) <=5:
        return raw_id
    return f"{raw_id[:5]}"


zoom = 18


def get_address(lat,lon):
    try:
        url = f"https://nominatim.openstreetmap.org/reverse?lat={lat}&lon={lon}&format=json&addressdetails=1&zoom=18"
        res = requests.get(url, headers={"User-Agent": "DRI-JunyoungJeon-app"}, timeout=10).json()
        name = res.get("name","UnknownName")   
        print("type",res.get("type"))
        
        return name
    except Exception as e:
        print(f"Nominatim error: {e}")
        return None
    
def get_altitude(lat,lon):
    try:
        url = f"https://api.open-elevation.com/api/v1/lookup?locations={lat},{lon}"
        res = requests.get(url, timeout=10).json()
        return res["results"][0]["elevation"]
    except Exception as e:
        print(f"Open-Elevation error: {e}")
        return None


def on_connect(client, userdata, flags, rc):
    print("EMQX Connection is success! result code: " + str(rc))
    client.subscribe("JunyoungJeon/DRI_Sensor_data")
    client.subscribe("JunyoungJeon/initial_data")

msg_queue = queue.Queue()

def mongo_worker():
    while True:
        topic, data = msg_queue.get()
        try:
            TOPIC = TOPIC_TO_COL.get(topic, DEFAULT_COL)
            TOPIC.insert_one(data)
            print("MongoDB data is saved!")
        except Exception as e:
            print(f"MongoDB insert failed: {e}")
        msg_queue.task_done()

threading.Thread(target=mongo_worker, daemon=True).start()

def on_message(client, userdata, msg):
    try:
        payload = msg.payload.decode()
        print(f"Received data : {payload}")
        data = json.loads(payload)

        base_id = data.get("_id", "Unknown_ID")
        timestamp = datetime.now(ZoneInfo("America/Los_Angeles"))
        CHIPSET_ID = convert_id_to_original_format(base_id)
        data.pop("_id", None)  # Remove _id from data to avoid duplication
        data.pop("location",None)
        data.pop("altitude",None)
        
        lon = data.get("longitude")
        lat = data.get("latitude")
        address_text = None
        location=None
        altitude=None
        Longitude=None
        Latitude=None

        if lat and lon:
            location = get_address(lat, lon)
            altitude = data.get("altitude")

            data["Location"] = location
            Longitude = data.get("longitude")
            Latitude = data.get("latitude")
        
        if msg.topic == "JunyoungJeon/initial_data":    
            doc = {
            "CHIPSET_ID": CHIPSET_ID,
            "Datetime": timestamp.strftime("%Y-%m-%d %H:%M:%S"),
            "Location": location,
            "Altitude": altitude,
            "Longitude": Longitude,
            "Latitude": Latitude
            }
        elif msg.topic == "JunyoungJeon/DRI_Sensor_data":
            doc = {
                "CHIPSET_ID": CHIPSET_ID,
                "Datetime": timestamp.strftime("%Y-%m-%d %H:%M:%S"),
                **data
            }
        else:
            doc=data

        msg_queue.put((msg.topic, doc))
        print(f"Enqueued documet for {msg.topic}")
   
    except Exception as e:
        print(f"MongoDB data save is failed : {e}")
 
mqtt_client = mqtt.Client(client_id="python_mongo_client", clean_session=False, protocol=mqtt.MQTTv311)
 
mqtt_client.on_connect = on_connect
mqtt_client.on_message = on_message
 
mqtt_client.connect("34.171.10.59", 1883, 60)
 
mqtt_client.loop_forever()