import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext
import serial
import threading
import time
import csv
from datetime import datetime


class LaurelLoggerGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("MBARI Laurel L-Series Logger")

        self.ser = None
        self.connected = False
        self.logging = False

        # ---------------- GUI ----------------
        tk.Label(root, text="COM Port:").grid(row=0, column=0, sticky="e")
        self.com_entry = tk.Entry(root, width=8)
        self.com_entry.insert(0, "COM3")
        self.com_entry.grid(row=0, column=1)

        tk.Label(root, text="Baud:").grid(row=0, column=2, sticky="e")
        self.baud_entry = tk.Entry(root, width=8)
        self.baud_entry.insert(0, "9600")
        self.baud_entry.grid(row=0, column=3)

        self.connect_btn = tk.Button(root, text="Connect", command=self.connect)
        self.connect_btn.grid(row=0, column=4, padx=5)

        self.disconnect_btn = tk.Button(root, text="Disconnect", command=self.disconnect, state="disabled")
        self.disconnect_btn.grid(row=0, column=5)

        self.status_label = tk.Label(root, text="Disconnected", fg="red")
        self.status_label.grid(row=1, column=0, columnspan=6)

        tk.Label(root, text="CSV File:").grid(row=2, column=0, sticky="e")
        self.file_entry = tk.Entry(root, width=45)
        self.file_entry.grid(row=2, column=1, columnspan=4)

        tk.Button(root, text="Browse", command=self.browse_file).grid(row=2, column=5)

        self.start_btn = tk.Button(root, text="Start Logging", command=self.start_logging, state="disabled")
        self.start_btn.grid(row=3, column=2, pady=5)

        self.stop_btn = tk.Button(root, text="Stop Logging", command=self.stop_logging, state="disabled")
        self.stop_btn.grid(row=3, column=3)

        tk.Label(root, text="Parsed Laurel Updates:").grid(row=4, column=0, columnspan=6)

        self.raw_display = scrolledtext.ScrolledText(root, width=70, height=12)
        self.raw_display.grid(row=5, column=0, columnspan=6, padx=5, pady=5)

        # Reader thread
        threading.Thread(target=self.serial_reader, daemon=True).start()

    # ---------------- Serial Control ----------------
    def connect(self):
        try:
            self.ser = serial.Serial(
                self.com_entry.get(),
                int(self.baud_entry.get()),
                timeout=0.05
            )
            self.connected = True
            self.connect_btn.config(state="disabled")
            self.disconnect_btn.config(state="normal")
            self.start_btn.config(state="normal")
            self.status_label.config(text="Connected", fg="green")
        except Exception as e:
            messagebox.showerror("Serial Error", str(e))

    def disconnect(self):
        self.logging = False
        self.connected = False
        if self.ser and self.ser.is_open:
            self.ser.close()

        self.connect_btn.config(state="normal")
        self.disconnect_btn.config(state="disabled")
        self.start_btn.config(state="disabled")
        self.stop_btn.config(state="disabled")
        self.status_label.config(text="Disconnected", fg="red")

    # ---------------- File ----------------
    def browse_file(self):
        filename = filedialog.asksaveasfilename(
            defaultextension=".csv",
            filetypes=[("CSV files", "*.csv")]
        )
        if filename:
            self.file_entry.delete(0, tk.END)
            self.file_entry.insert(0, filename)

    # ---------------- Logging ----------------
    def start_logging(self):
        if not self.file_entry.get():
            messagebox.showerror("Error", "Please select a CSV file.")
            return

        self.csv_file = open(self.file_entry.get(), "w", newline="")
        self.csv_writer = csv.writer(self.csv_file)
        self.csv_writer.writerow(["Time", "Load Cell"])

        self.logging = True
        self.start_btn.config(state="disabled")
        self.stop_btn.config(state="normal")
        self.status_label.config(text="Logging", fg="blue")

    def stop_logging(self):
        self.logging = False
        if hasattr(self, "csv_file"):
            self.csv_file.close()

        self.start_btn.config(state="normal")
        self.stop_btn.config(state="disabled")
        self.status_label.config(text="Connected (idle)", fg="green")

    # ---------------- Serial Reader ----------------
    def serial_reader(self):
        buffer = ""
        while True:
            if self.connected and self.ser:
                try:
                    data = self.ser.read(self.ser.in_waiting or 1).decode("ascii", errors="ignore")
                    if data:
                        buffer += data

                        # Laurel sends CR-only overwrite updates
                        while "\r" in buffer:
                            line, buffer = buffer.split("\r", 1)
                            line = line.strip()

                            if self.is_valid_value(line):
                                timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]

                                # GUI display (one value per line)
                                self.raw_display.insert(tk.END, f"{timestamp}  {line}\n")
                                self.raw_display.see(tk.END)

                                if self.logging:
                                    self.csv_writer.writerow([timestamp, line])
                                    self.csv_file.flush()
                except:
                    pass

            time.sleep(0.005)

    # ---------------- Validator ----------------
    @staticmethod
    def is_valid_value(s):
        try:
            if "." not in s:
                return False
            float(s)
            return True
        except:
            return False


# ---------------- Main ----------------
if __name__ == "__main__":
    root = tk.Tk()
    app = LaurelLoggerGUI(root)
    root.mainloop()
