import serial
import threading
import ttkbootstrap as ttk  # Modern UI Library
from tkinter import messagebox, StringVar
from pymongo import MongoClient
from datetime import datetime

# MongoDB Setup
client = MongoClient("replace with your mongodb uri")
db = client["toll_system"]
users_collection = db["users"]
log_collection = db["logs"]

# Constants
SERIAL_PORT = "replace with serial port name"  # Adjust based on your system
BAUD_RATE = 9600
TOLL_AMOUNT = 50  # Fixed toll fee

# Setup Serial
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)

# Tkinter Setup (Modern UI)
root = ttk.Window(themename="darkly")
root.title("Smart Toll System")
root.geometry("750x500")

# Notebook (Tabs)
notebook = ttk.Notebook(root)
notebook.pack(expand=True, fill="both")

# Home Frame (Status + Recharge Input)
home_frame = ttk.Frame(notebook, padding=20)
notebook.add(home_frame, text="🏠 Home")

status_label = ttk.Label(home_frame, text="Waiting for users...", font=("Arial", 14, "bold"))
status_label.pack(pady=10)

uid_label = ttk.Label(home_frame, text="", font=("Arial", 12))
uid_label.pack(pady=5)

# Recharge Section (Initially Hidden)
recharge_frame = ttk.Frame(home_frame)

recharge_label = ttk.Label(recharge_frame, text="Enter Recharge Amount:", font=("Arial", 12))
recharge_entry = ttk.Entry(recharge_frame, font=("Arial", 12))

vehicle_label = ttk.Label(recharge_frame, text="Vehicle Number:", font=("Arial", 12))
vehicle_entry = ttk.Entry(recharge_frame, font=("Arial", 12))

confirm_button = ttk.Button(recharge_frame, text="Confirm")

# Log Section (Global Logs)
log_frame = ttk.Frame(notebook, padding=10)
notebook.add(log_frame, text="📜 Logs")

log_text = ttk.Text(log_frame, height=15, width=75, wrap="word", font=("Consolas", 10))
log_text.pack(pady=10)

# User Logs Section
user_log_frame = ttk.Frame(notebook, padding=10)
notebook.add(user_log_frame, text="🚗 Vehicle Logs")

vehicle_var = StringVar()
vehicle_dropdown = ttk.Combobox(user_log_frame, textvariable=vehicle_var, font=("Arial", 12))
vehicle_dropdown.pack(pady=5)

load_user_logs_button = ttk.Button(user_log_frame, text="Load Logs", command=lambda: load_user_logs(vehicle_var.get()))
load_user_logs_button.pack(pady=5)

user_log_text = ttk.Text(user_log_frame, height=15, width=75, wrap="word", font=("Consolas", 10))
user_log_text.pack(pady=10)


# Function to update logs
def update_log(uid, vehicle, message):
    log_entry = {"time": datetime.now(), "event": message}
    log_collection.insert_one(log_entry)

    users_collection.update_one(
        {"uid": uid},
        {"$push": {"logs": log_entry}}
    )

    load_logs()


# Handle UID Processing
def process_uid(uid):
    root.after(0, lambda: handle_uid(uid))


def handle_uid(uid):
    status_label.config(text="Checking database...")
    uid_label.config(text=f"UID: {uid}")

    user = users_collection.find_one({"uid": uid})

    if user:
        balance = user["balance"]
        vehicle = user["vehicle"]
        if balance >= TOLL_AMOUNT:
            new_balance = balance - TOLL_AMOUNT
            users_collection.update_one({"uid": uid}, {"$set": {"balance": new_balance}})
            update_log(uid, vehicle, f"✅ {vehicle} ({uid}) passed. New balance: {new_balance}")
            send_to_arduino(new_balance)
            status_label.config(text=f"Vehicle ID:{vehicle} \nBalance: {new_balance}")
            root.after(2000, reset_home_screen)
        else:
            show_recharge_ui(uid, vehicle, balance, new_user=False)
    else:
        show_recharge_ui(uid, None, 0, new_user=True)


# Show Recharge UI (Dynamic for New Users)
def show_recharge_ui(uid, vehicle, balance, new_user=False):
    recharge_entry.delete(0, "end")  # Clear previous input
    recharge_frame.pack(pady=10)

    # Remove vehicle fields if not needed
    for widget in recharge_frame.winfo_children():
        widget.pack_forget()

    # Recharge label & entry
    recharge_label.pack(side="top", pady=2)
    recharge_entry.pack(side="top", pady=2)

    if new_user:
        vehicle_entry.delete(0, "end")  # Clear vehicle entry field
        vehicle_label.pack(side="top", pady=2)
        vehicle_entry.pack(side="top", pady=2)
        status_label.config(text=f"🆕 New User: {uid}. Enter Vehicle Number & Recharge:")
    else:
        status_label.config(text=f"⚠ Low Balance for: {vehicle}")

    confirm_button.pack(side="top", pady=5)
    confirm_button.config(command=lambda: process_recharge(uid, vehicle, balance, new_user))


# Process Recharge
def process_recharge(uid, vehicle, balance, new_user=False):
    try:
        amount = int(recharge_entry.get())
        new_balance = amount if new_user else balance + amount
        new_balance -= TOLL_AMOUNT

        if new_user:
            vehicle = vehicle_entry.get().strip()
            if not vehicle:
                messagebox.showerror("Error", "Enter a valid vehicle number!")
                return
            users_collection.insert_one({"uid": uid, "vehicle": vehicle, "balance": new_balance, "logs": []})
            update_log(uid, vehicle, f"🆕 New User {vehicle} ({uid}) created. Initial Balance: {new_balance}")
        else:
            users_collection.update_one({"uid": uid}, {"$set": {"balance": new_balance}})
            update_log(uid, vehicle, f"💰 Recharge: {amount} for {vehicle} ({uid}). New Balance: {new_balance}")

        send_to_arduino(new_balance)
        status_label.config(text=f"Balance: {new_balance}")

    except ValueError:
        messagebox.showerror("Error", "Invalid input! Enter a valid amount.")

    recharge_frame.pack_forget()
    root.after(2000, reset_home_screen)


# Reset Home Screen
def reset_home_screen():
    status_label.config(text="Waiting for users...")
    uid_label.config(text="")


# Send balance to Arduino
def send_to_arduino(balance):
    ser.write(str(balance).encode())


# Load user logs by vehicle number
def load_user_logs(vehicle):
    user_log_text.delete("1.0", "end")

    user = users_collection.find_one({"vehicle": vehicle})
    if user and "logs" in user:
        for log in user["logs"]:
            log_time = log["time"].strftime("%H:%M:%S")
            log_event = log["event"]
            user_log_text.insert("end", f"{log_time} - {log_event}\n")
    else:
        user_log_text.insert("end", "No logs available for this vehicle.\n")


# Populate vehicle dropdown
def load_vehicle_dropdown():
    vehicles = users_collection.find({}, {"vehicle": 1})
    vehicle_dropdown["values"] = [user["vehicle"] for user in vehicles]
    root.after(5000, load_vehicle_dropdown)


# Serial Read Thread
def serial_read():
    while True:
        if ser.in_waiting:
            uid = ser.readline().decode().strip()
            if uid and uid != "System Ready...":
                process_uid(uid)

def load_logs():
    log_text.delete("1.0", "end")  # Clear log text box

    # Fetch logs from MongoDB
    logs = log_collection.find().sort("time", -1)  # Show latest first
    for log in logs:
        log_time = log["time"].strftime("%Y-%m-%d %H:%M:%S")
        log_event = log["event"]
        log_text.insert("end", f"{log_time} - {log_event}\n")

    log_text.yview_moveto(1)  # Scroll to latest log



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

# Initialize UI
load_vehicle_dropdown()

# Run GUI
root.mainloop()
