from datetime import datetime, timedelta
from bson import json_util, ObjectId
import json
from aiokafka import AIOKafkaConsumer
from app.db import database
from app.utils.connections import connected_clients

async def consume_tracking_data():
    consumer = AIOKafkaConsumer(
        "vehicle_tracking",
        bootstrap_servers="localhost:9092",
        group_id="tracking-group"
    )
    await consumer.start()

    mongo_gen = database.get_mongo_db()
    mongo = next(mongo_gen)

    tracking_logs = mongo["tracking_logs"]
    alert_logs = mongo["alert_logs"]
    geofences = mongo["geofences"]
    geofence_rules = mongo["geofence_rules"]
    geofence_mappings = mongo["geofence_rule_mapping"]

    try:
        async for msg in consumer:
            data = json.loads(msg.value.decode("utf-8"))
            data["received_at"] = datetime.utcnow()
            data["alert_type"] = "W"
            device_id = data.get("device_id")
            coordinates = data.get("location", {}).get("coordinates", [])

            # ✅ Insert tracking log
            tracking_logs.insert_one(data)

            alerts = []

            # 1. 🔔 Check for inactivity (no update in >30 mins)
            last_entry = tracking_logs.find_one(
                {"device_id": device_id},
                sort=[("received_at", -1)]
            )

            if last_entry:
                print("🟡 Last entry found:")
                print(last_entry)

                last_time = last_entry["received_at"]
                current_time = datetime.utcnow()
                gap = current_time - last_time

                # Check if it was inactive for >30 minutes
                if gap > timedelta(minutes=30):
                    # 1. Log inactivity alert
                    alert = {
                        "device_id": device_id,
                        "type": "inactivity",
                        "message": f"Device {device_id} inactive for over 30 minutes.",
                        "triggered_at": current_time
                    }
                    alert_logs.insert_one(alert)
                    alerts.append(alert)

                    # 2. Also log "back online" alert
                    online_alert = {
                        "device_id": device_id,
                        "type": "recovery",
                        "message": f"Device {device_id} is back online after {gap.seconds // 60} minutes of inactivity.",
                        "triggered_at": current_time
                    }
                    alert_logs.insert_one(online_alert)
                    alerts.append(online_alert)

            # 2. 🧠 Check for geofence + rules
            mappings = list(geofence_mappings.find({"assigned_entity_id": device_id}))

            for mapping in mappings:
                geo_id = mapping.get("geofence_id")
                rule_id = mapping.get("geofence_rule_id")

                geofence = geofences.find_one({"_id": ObjectId(geo_id)})
                if not geofence or not coordinates:
                    continue

                from shapely.geometry import Point, Polygon
                point = Point(coordinates)
                polygon = Polygon(geofence["loc"]["coordinates"][0])
                inside = polygon.contains(point)

                if mapping.get("trigger_events") == "exit" and not inside:
                    rule = geofence_rules.find_one({"_id": ObjectId(rule_id)}) if rule_id else None
                    conditions_passed = True

                    if rule and rule.get("conditions"):
                        for cond in rule["conditions"]:
                            param = cond.get("parameter")
                            op = cond.get("operator")
                            expected = cond.get("value")

                            if op not in OPERATORS:
                                conditions_passed = False
                                break

                            actual = data.get(param)
                            try:
                                # Convert types if possible
                                expected_val = float(expected)
                                actual_val = float(actual) if actual is not None else None
                                if actual_val is None or not OPERATORS[op](actual_val, expected_val):
                                    conditions_passed = False
                                    break
                            except Exception as e:
                                conditions_passed = False
                                break

                    if conditions_passed:
                        alert_msg = rule.get("alert_message") if rule else f"Device {device_id} exited geofence."
                        alert = {
                            "device_id": device_id,
                            "type": "geofence-exit",
                            "geofence": geofence["name"],
                            "message": alert_msg,
                            "triggered_at": data["received_at"]
                        }
                        alert_logs.insert_one(alert)
                        alerts.append(alert)

            
            # ✅ Send Kafka message to clients
            for ws in connected_clients.copy():
                print(f"✅ Broadcasting to {len(connected_clients)} connected client(s)")
                try:
                    await ws.send_text(json.dumps(data, default=json_util.default))

                    await ws.send_text(json.dumps({
                            "type": "alert",
                            "message": "Device dev123 exited geofence.",
                            "device_id": "dev123",
                            "alert_type": "E",
                            "geofence": "Tidel park coimbatore",
                            "triggered_at": "triggered_at"
                        }, default=json_util.default))
                    print(f"✅ SEND MESSAGE TO to {len(connected_clients)} connected client(s)")

                    for alert in alerts:
                        await ws.send_text(json.dumps({
                            "type": "alert",
                            "message": alert.get("message", ""),
                            "device_id": alert.get("device_id"),
                            "alert_type": alert.get("type"),
                            "geofence": alert.get("geofence"),
                            "triggered_at": alert.get("triggered_at")
                        }, default=json_util.default))

                except Exception as e:
                    connected_clients.remove(ws)
                    print("❌ WebSocket error:", e)

    finally:
        await consumer.stop()
        try:
            next(mongo_gen)
        except StopIteration:
            pass
