import tkinter as tk
from tkinter import ttk
import serial
import serial.tools.list_ports
import time

class TunerGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("Gripper Fine-Tuning (Pos: 97/85/138)")
        self.root.geometry("450x550")
        
        self.ser = None
        self.step_size = tk.IntVar(value=1)
        
        self.angles = {
            1: 97,  
            2: 85,  
            3: 138, 
            4: 125  
        }
        self.labels = {} 

        self.create_ui()

    def create_ui(self):
        frame_conn = tk.LabelFrame(self.root, text="Connection", padx=10, pady=10)
        frame_conn.pack(fill="x", padx=10, pady=5)
        
        tk.Label(frame_conn, text="Port:").pack(side="left")
        self.port_combo = ttk.Combobox(frame_conn, width=15)
        self.port_combo.pack(side="left", padx=5)
        tk.Button(frame_conn, text="Refresh", command=self.refresh_ports).pack(side="left")
        self.btn_connect = tk.Button(frame_conn, text="Connect", command=self.toggle_connection, bg="#DDDDDD")
        self.btn_connect.pack(side="left", padx=5)
        self.refresh_ports()

        frame_step = tk.LabelFrame(self.root, text="Step Size", padx=10, pady=10)
        frame_step.pack(fill="x", padx=10, pady=5)
        tk.Radiobutton(frame_step, text="1° (Fine)", variable=self.step_size, value=1).pack(side="left", padx=20)
        tk.Radiobutton(frame_step, text="5° (Coarse)", variable=self.step_size, value=5).pack(side="left", padx=20)

        frame_ctrl = tk.LabelFrame(self.root, text="Position Adjustment", padx=10, pady=10)
        frame_ctrl.pack(fill="both", expand=True, padx=10, pady=5)

        self.create_row(frame_ctrl, 1, "Base (41)")
        self.create_row(frame_ctrl, 2, "Big Arm (Sync)")
        self.create_row(frame_ctrl, 3, "Mid Arm (Sync)")
        
        self.create_row(frame_ctrl, 4, ">>> GRIPPER <<<", bg_color="#E0F7FA")

        tk.Button(self.root, text="Reset to 97 / 85 / 138 / 125", command=self.reset_position, 
                  bg="#FFCCBC", height=2).pack(fill="x", padx=10, pady=10)

    def create_row(self, parent, sid, name, bg_color=None):
        row = tk.Frame(parent, bg=bg_color) if bg_color else tk.Frame(parent)
        row.pack(fill="x", pady=8)
        
        tk.Label(row, text=name, width=15, anchor="w", bg=bg_color).pack(side="left")
        tk.Button(row, text=" < ", command=lambda: self.move(sid, -1)).pack(side="left")
        
        lbl = tk.Label(row, text=str(self.angles[sid]), width=6, font=("Arial", 14, "bold"), fg="blue", bg=bg_color)
        lbl.pack(side="left", padx=10)
        self.labels[sid] = lbl
        
        tk.Button(row, text=" > ", command=lambda: self.move(sid, 1)).pack(side="left")

    def refresh_ports(self):
        ports = [p.device for p in serial.tools.list_ports.comports()]
        self.port_combo['values'] = ports
        if ports: self.port_combo.current(0)

    def toggle_connection(self):
        if self.ser and self.ser.is_open:
            self.ser.close()
            self.btn_connect.config(text="Connect", bg="#DDDDDD")
        else:
            try:
                self.ser = serial.Serial(self.port_combo.get(), 9600, timeout=1)
                self.btn_connect.config(text="Connected", bg="#99FF99")
                time.sleep(1.5)
            except Exception as e:
                print(e)

    def move(self, sid, direction):
        step = self.step_size.get()
        new_val = self.angles[sid] + (step * direction)
        if new_val < 0: new_val = 0
        if new_val > 180: new_val = 180
        
        self.angles[sid] = new_val
        self.labels[sid].config(text=str(new_val))
        self.send(sid, new_val)

    def reset_position(self):
        defaults = {1: 97, 2: 85, 3: 138, 4: 125}
        for i in range(1, 5):
            self.angles[i] = defaults[i]
            self.labels[i].config(text=str(defaults[i]))
            self.send(i, defaults[i])
            time.sleep(0.05)

    def send(self, sid, val):
        if self.ser and self.ser.is_open:
            cmd = f"{sid}:{val}\n"
            self.ser.write(cmd.encode())
            print(f"Sent: {cmd.strip()}")
        else:
            print(f"Sim: {sid} -> {val}")

if __name__ == "__main__":
    root = tk.Tk()
    app = TunerGUI(root)
    root.mainloop()