
from unihiker import GUI
import serial
import serial.tools.list_ports
import time
from pinpong.board import Board, Pin
from pinpong.libs.dfrobot_huskylens import Huskylens
from pinpong.libs.dfrobot_huskylens import Parameter

Board().begin()
btn_success_pin = Pin(Pin.P3, Pin.IN) 
btn_fail_pin = Pin(Pin.P4, Pin.IN)    

try:
    p_huskylens = Huskylens()
    print("HuskyLens Init Success")
except:
    print("HuskyLens Init Failed!")

u_gui = GUI()
u_gui.draw_text(text="Exp 2: Fast Scan", x=30, y=5, font_size=18, color="#0000FF")

status_text = u_gui.draw_text(text="Wait Start", x=20, y=35, font_size=12, color="gray")
object_text = u_gui.draw_text(text="--", x=130, y=35, font_size=12, color="black")
warning_text = u_gui.draw_text(text="", x=20, y=115, font_size=15, color="red") 
info_text = u_gui.draw_text(text="READY", x=60, y=70, font_size=35, color="#FF0000")

u_gui.draw_text(text="Success(P3)", x=10, y=140, font_size=12, color="green")
success_text = u_gui.draw_text(text="0", x=35, y=160, font_size=25, color="green")
u_gui.draw_text(text="Fail(P4)", x=140, y=140, font_size=12, color="red")
fail_text = u_gui.draw_text(text="0", x=160, y=160, font_size=25, color="red")
u_gui.draw_text(text="Total:", x=20, y=190, font_size=15, color="black")
cycle_text = u_gui.draw_text(text="0", x=80, y=185, font_size=20, color="blue")

ser = None
ports = list(serial.tools.list_ports.comports())
port_name = None
for p in ports:
    if "ACM" in p.device or "USB" in p.device:
        port_name = p.device
        break
if port_name:
    ser = serial.Serial(port_name, 9600, timeout=0.05) 
    status_text.config(text=f"Conn: {port_name}", color="green")
else:
    status_text.config(text="No Arduino", color="red")

cycle_count = 0; success_count = 0; fail_count = 0
last_p3_state = 0; last_p4_state = 0
sys_state = 0 

liquid_triggered_this_round = False 
waiting_for_user_resume = False 

scan_counters = {1:0, 2:0, 3:0} 
id4_confirm_counter = 0


def reset_ui_for_scan():
    global liquid_triggered_this_round, id4_confirm_counter, scan_counters
    info_text.config(text="SCANNING...", color="black", font_size=30)
    object_text.config(text="Looking...", color="gray")
    status_text.config(text="Mode: Auto Scan", color="blue")
    warning_text.config(text="")
    
    liquid_triggered_this_round = False
    id4_confirm_counter = 0
    scan_counters = {1:0, 2:0, 3:0} 

def start_robot_action(target_id):
    global sys_state, id4_confirm_counter
    
    name_map = {1:"Paper", 2:"Glass", 3:"Plastic"}
    obj_name = name_map.get(target_id, "Unknown")
    
    object_text.config(text=f"ID:{target_id} {obj_name}", color="blue")
    info_text.config(text="SENDING...", color="orange", font_size=30)
    
    if ser and ser.is_open:
        ser.reset_input_buffer()
        ser.write(f"I{target_id}\n".encode()) 
        time.sleep(0.5)
        ser.write(b'1\n') 
        
    time.sleep(2.0) 
    
    info_text.config(text="RUNNING", color="orange", font_size=35)
    id4_confirm_counter = 0 
    sys_state = 2 

def click_start():
    global sys_state
    if sys_state == 0:
        sys_state = 1
        reset_ui_for_scan()

def click_stop():
    global sys_state
    sys_state = 0 
    if ser: ser.write(b'0\n')
    info_text.config(text="STOPPED", color="red", font_size=30)
    status_text.config(text="Idle", color="gray")

def click_clear():
    global cycle_count, success_count, fail_count
    cycle_count = 0; success_count = 0; fail_count = 0
    cycle_text.config(text="0"); success_text.config(text="0"); fail_text.config(text="0")

u_gui.add_button(text="START", x=20, y=230, w=90, h=45, onclick=click_start)
u_gui.add_button(text="STOP", x=130, y=230, w=90, h=45, onclick=click_stop)
u_gui.add_button(text="Clear", x=75, y=285, w=90, h=30, onclick=click_clear)

last_scan_time = time.time()
CONFIRM_THRESHOLD = 3 

while True:
    p_huskylens.command_request()
    current_detected_id = p_huskylens.read_block_center_parameter_direct(Parameter.id, "blocks")

    if sys_state == 1:
        if time.time() - last_scan_time > 0.1:
            if current_detected_id == 1:
                scan_counters[1] += 1; scan_counters[2] = 0; scan_counters[3] = 0
            elif current_detected_id == 2:
                scan_counters[2] += 1; scan_counters[1] = 0; scan_counters[3] = 0
            elif current_detected_id == 3:
                scan_counters[3] += 1; scan_counters[1] = 0; scan_counters[2] = 0
            else:
                scan_counters = {1:0, 2:0, 3:0}

            if scan_counters[1] >= CONFIRM_THRESHOLD: start_robot_action(1)
            elif scan_counters[2] >= CONFIRM_THRESHOLD: start_robot_action(2)
            elif scan_counters[3] >= CONFIRM_THRESHOLD: start_robot_action(3)
            
            last_scan_time = time.time()

    elif sys_state == 2:
        if not liquid_triggered_this_round:
            if current_detected_id == 4:
                id4_confirm_counter += 1
            else:
                id4_confirm_counter = 0

            if id4_confirm_counter >= 3:
                print("!!! LIQUID CONFIRMED !!!")
                ser.write(b'L\n') 
                warning_text.config(text="LIQUID DETECTED!", color="red")
                liquid_triggered_this_round = True
                id4_confirm_counter = 0 
        
        if ser and ser.is_open and ser.in_waiting > 0:
            try:
                line = ser.readline().decode().strip()
                if "STEP:" in line:
                    step = line.split(":")[1]
                    info_text.config(text=f"Step {step}/11", color="#FF0000", font_size=35)
                elif "WAITING_USER" in line:
                    info_text.config(text="Pause: Press P3", color="purple", font_size=25)
                    waiting_for_user_resume = True
                elif "CYCLE_DONE" in line:
                    sys_state = 3 
                    waiting_for_user_resume = False
                    cycle_count += 1
                    cycle_text.config(text=str(cycle_count))
                    info_text.config(text="Judge P3/P4", color="green", font_size=30)
            except:
                pass

    current_p3 = btn_success_pin.value()
    current_p4 = btn_fail_pin.value()

    if current_p3 == 1 and last_p3_state == 0:
        if sys_state == 2 and waiting_for_user_resume:
            ser.write(b'1') 
            waiting_for_user_resume = False
            info_text.config(text="Resuming...", color="orange")
        elif sys_state == 3:
            success_count += 1
            success_text.config(text=str(success_count))
            sys_state = 1
            reset_ui_for_scan()
            time.sleep(1.0)

    if current_p4 == 1 and last_p4_state == 0:
        if sys_state == 2 and waiting_for_user_resume:
            ser.write(b'1') 
            waiting_for_user_resume = False
        elif sys_state == 3:
            fail_count += 1
            fail_text.config(text=str(fail_count))
            sys_state = 1
            reset_ui_for_scan()
            time.sleep(1.0)

    last_p3_state = current_p3
    last_p4_state = current_p4

    time.sleep(0.02)