"""
serial_logger.py - log lines from a serial device to a timestamped CSV.

Usage:
    python serial_logger.py --list                    # show available ports
    python serial_logger.py COM3                      # 9600 baud, log.csv
    python serial_logger.py /dev/ttyUSB0 -b 115200 -o readings.csv
Stop with Ctrl+C.
"""
import argparse
import csv
import sys
from datetime import datetime

import serial
from serial.tools import list_ports


def list_available() -> None:
    ports = list_ports.comports()
    if not ports:
        print("No serial ports found.")
    for p in ports:
        print(f"{p.device:<15} {p.description}")


def log(port: str, baud: int, outfile: str, delimiter: str) -> None:
    with serial.Serial(port, baud, timeout=1) as dev, open(outfile, "a", newline="") as f:
        writer = csv.writer(f)
        print(f"Logging {port} @ {baud} baud to {outfile} (Ctrl+C to stop)")
        count = 0
        while True:
            raw = dev.readline()               # waits up to `timeout` seconds
            if not raw:
                continue                        # nothing arrived; keep waiting
            line = raw.decode("utf-8", errors="replace").strip()
            if not line:
                continue
            stamp = datetime.now().isoformat(timespec="milliseconds")
            fields = line.split(delimiter) if delimiter else [line]
            writer.writerow([stamp, *fields])
            f.flush()                           # don't lose data if unplugged
            count += 1
            print(f"{count:>6}  {stamp}  {line}")


def main() -> None:
    parser = argparse.ArgumentParser(description="Log serial data to CSV.")
    parser.add_argument("port", nargs="?", help="e.g. COM3 or /dev/ttyUSB0")
    parser.add_argument("-b", "--baud", type=int, default=9600)
    parser.add_argument("-o", "--output", default="log.csv")
    parser.add_argument("-d", "--delimiter", default=",",
                        help="split each line into columns on this ('' to keep whole line)")
    parser.add_argument("--list", action="store_true", help="list serial ports and exit")
    args = parser.parse_args()

    if args.list or not args.port:
        list_available()
        return

    try:
        log(args.port, args.baud, args.output, args.delimiter)
    except serial.SerialException as e:
        sys.exit(f"Serial error: {e}")
    except KeyboardInterrupt:
        print("\nStopped.")


if __name__ == "__main__":
    main()
