import atexit
import threading
import serial
import serial.tools.list_ports
from loguru import logger

class SerialManager(object):
    def __init__(self):
        self.devices = []

    def search_devices(self, pid=0x4001):
        """
        搜索pid指定的串口设备
        :param pid: 设备PID，默认0x4001
        :return: 可用设备列表
        """
        ports = serial.tools.list_ports.comports()
        for port in ports:
            if hasattr(port, 'pid') and port.pid == pid:
                self.devices.append({
                    'port': port.device,
                    'description': port.description,
                    'pid': port.pid,
                    'vid': port.vid
                })
                
        return self
    
    def select_device(self):
        """
        用户选择可用的串口设备
        :param devices: 设备列表
        :return: 选中的设备
        """
        if not self.devices:
            print("没有找到可用的设备")
            return None
        
        print("可用设备列表:")
        for i, device in enumerate(self.devices):
            print(f"{i+1}. {device['port']} - {device['description']}")
        
        while True:
            try:
                choice = int(input("请选择设备编号: "))
                if 1 <= choice <= len(self.devices):
                    return self.devices[choice-1]['port']
                else:
                    print("输入无效，请重新选择")
            except ValueError:
                print("输入无效，请输入数字")

class SerialDevice:
    def __init__(self, port):
        self._port = port
        self.serial_device = None
        self.reading = False
        self.read_thread = None    

    @property
    def port(self):
        return self._port
    
    # 是否已连接
    def is_connected(self):
        return self.serial_device and  self.serial_device.is_open
    
    # 连接
    def connect(self, baudrate=9600, timeout=1):
        """
        连接串口设备
        :param device: 设备信息
        :param baudrate: 波特率，默认9600
        :param timeout: 超时时间，默认1秒
        :return: 是否连接成功
        """
        if self.serial_device and  self.serial_device.is_open:
            print(f"串口{self._port}已连接")
            return self
        
        try:
            self.serial_device = serial.Serial(
                port=self._port,
                baudrate=baudrate,
                timeout=timeout,
                write_timeout=timeout
            )
            if self.serial_device.is_open:
                print(f"成功连接到设备: {self._port}")
                return self
            else:
                print("连接失败")
                return None
        except Exception as e:
            print(f"连接错误: {e}")
            return None
    
    def send(self, data: bytes):
        """
        发送16进制字符串指令
        :param hex_command: 16进制字符串指令
        :return: 是否发送成功
        """
        if not self.serial_device or not self.serial_device.is_open:
            print("串口未连接")
            return False
        
        try:
            # 将16进制字符串转换为二进制数据
            self.serial_device.write(data)
            return True
        except Exception as e:
            print(f"发送错误: {e}")
            return False
        
    def start_reading(self, callback = None):
        """启动后台读取线程"""
        if not self.serial_device or not self.serial_device.is_open:
            return
        
        if not self.reading:
            self.reading = True
            self.read_thread = threading.Thread(
                target=self._read_loop,
                args=(callback,),
                daemon=True  
            )
            self.read_thread.start()
    
    def _read_loop(self, callback = None):
        """读取循环 - 必须能被优雅终止"""
        while self.reading and self.serial_device and self.serial_device.is_open:
            try:
                # 使用带超时的read
                data = self.serial_device.read(1024)
                if data:
                    # logger.debug(data.hex())
                    if callback:
                        callback(data)
            except serial.SerialException as e:
                print(f"读取错误: {e}")
                break
            except Exception as e:
                print(f"未知错误: {e}")
                break
    def disconnect(self):
        """
        断开串口设备
        :return: 是否断开成功
        """
        self.reading = False  # 通知读取线程退出
        try:
            if self.serial_device and self.serial_device.is_open:
                self.serial_device.close()
                print("已断开串口连接")
                return True
            else:
                print("串口未连接")
                return False
        except Exception as e:
            print(f"断开错误: {e}")
            return False
    def safe_exit(self):
        """安全退出清理"""
        self.reading = False  # 通知读取线程退出
        
        if self.read_thread and self.read_thread.is_alive():
            self.read_thread.join(timeout=2.0)  # 等待线程结束
        
        if self.serial_device and self.serial_device.is_open:
            try:
                self.serial_device.cancel_read()  # 如果有的话
                self.serial_device.cancel_write()
                self.serial_device.close()
                print("串口已关闭")
            except Exception as e:
                print(f"关闭串口时出错: {e}")
    
    def __del__(self):
        """析构函数作为最后保障"""
        self.safe_exit()