import serial
import time
import datetime
import threading


# ─── Configuration ────────────────────────────────────────────────────────────
PORT     = 'COM7'
BAUDRATE = 115200
TIMEOUT  = 1
# ──────────────────────────────────────────────────────────────────────────────


def connect(port: str, baudrate: int) -> serial.Serial:
    """Open the serial connection and wait for Arduino to reset."""
    ser = serial.Serial(port, baudrate, timeout=TIMEOUT)
    time.sleep(2)           # Arduino resets on connect – give it time
    ser.reset_input_buffer()
    print(f"[INFO] Connected to {port} @ {baudrate} baud")
    return ser


def send(ser: serial.Serial, message: str) -> None:
    """Send a string to Arduino (newline-terminated)."""
    if not ser.is_open:
        print("[ERROR] Port is closed.")
        return
    payload = (message.strip() + '\n').encode('utf-8')
    ser.write(payload)
    print(f"[SENT] {message.strip()}")


def read_loop(ser: serial.Serial, stop_event: threading.Event) -> None:
    """Continuously read lines from Arduino and print them (runs in a thread)."""
    while not stop_event.is_set():
        try:
            line = ser.readline().decode('utf-8').rstrip()
            if line:
                ts = datetime.datetime.now().strftime('%H:%M:%S.%f')[:-3]
                print(f"[{ts}] Arduino → {line}")
        except serial.SerialException as e:
            print(f"[ERROR] Serial error: {e}")
            stop_event.set()
        except UnicodeDecodeError:
            print("[WARN] Received non-UTF-8 data – skipped.")


def main() -> None:
    try:
        ser = connect(PORT, BAUDRATE)
    except serial.SerialException as e:
        print(f"[ERROR] Could not open port: {e}")
        return

    stop_event = threading.Event()
    reader = threading.Thread(target=read_loop, args=(ser, stop_event), daemon=True)
    reader.start()

    print("Type a message and press Enter to send it. Ctrl+C to quit.\n")

    try:
        while True:
            user_input = input()           # blocks until the user presses Enter
            if user_input:
                send(ser, user_input)
    except KeyboardInterrupt:
        print("\n[INFO] Interrupted by user.")
    finally:
        stop_event.set()
        ser.close()
        print("[INFO] Port closed. Goodbye!")


if __name__ == '__main__':
    main()