"""
Interactive offset helper for TMP117 sensors.

(c) 2025-26 Prof. Flavio ABREU ARAUJO. All rights reserved.
"""

from __future__ import annotations

import argparse
import sys
from typing import Optional, Sequence

from tools.myserial.scpi_serial import SCPISerial

PORT: Optional[str] = None  # Auto-detect if None


def format_port_table() -> str:
    ports = SCPISerial.list_ports()
    if not ports:
        return "No serial ports detected."
    lines = ["Detected serial ports:"]
    for device, description, hwid in ports:
        lines.append(f"  • {device}: {description} ({hwid})")
    return "\n".join(lines)


def parse_args(argv: Sequence[str]) -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Interactive offset helper for TMP117 sensors."
    )
    parser.add_argument(
        "port",
        nargs="?",
        default=PORT,
        help="Serial port path (leave empty to auto-detect)",
    )
    parser.add_argument(
        "--list",
        action="store_true",
        help="List available serial ports and exit",
    )
    return parser.parse_args(argv)


def prompt_float(prompt: str, default: Optional[float] = None) -> Optional[float]:
    text = f"{prompt}"
    if default is not None:
        text += f" [{default}]"
    text += ": "
    try:
        val = input(text).strip()
    except EOFError:
        return default
    if val == "":
        return default
    try:
        return float(val)
    except ValueError:
        print("Invalid number, skipping.")
        return default


def main(argv: Sequence[str] | None = None) -> int:
    args = parse_args(sys.argv[1:] if argv is None else argv)
    if args.list:
        print(format_port_table())
        return 0

    port = args.port
    try:
        with SCPISerial(port=port) as instr:
            print(f"Connected to {instr.port_name}")
            instr.write("*CLS")
            count_resp = instr.query(":SENS:COUN?")
            try:
                count = int(count_resp)
            except Exception:
                count = 1
            print(f"Detected {count} sensor(s)")

            for idx in range(count):
                n = idx + 1
                addr = instr.query(f":CONF{n}:ADDR?")
                current_offs = instr.query(f":CONF{n}:OFFS?")
                print(f"\nSensor {n} @ {addr}: current offset = {current_offs} °C")
                new_offs = prompt_float(f"Enter new offset for sensor {n}", default=None)
                if new_offs is None:
                    continue
                instr.write(f":CONF{n}:OFFS {new_offs}")
                verified = instr.query(f":CONF{n}:OFFS?")
                print(f"  -> Set to {verified} °C")

            save = input("\nSave offsets to flash with :SYST:CAL:SAVE? [y/N]: ").strip().lower()
            if save == "y":
                instr.write(":SYST:CAL:SAVE")
                print("Offsets saved. Note: requires prod USB mode for write access.")

        return 0
    except ValueError as exc:
        print(str(exc))
        print("\n" + format_port_table())
        return 1
    except KeyboardInterrupt:
        print("\n\nCalibration interrupted by user.")
        return 130


if __name__ == "__main__":
    raise SystemExit(main())
