# port_manager.py
# Versão 2.1 - Registro do Windows com fallback via PySerial e suporte a refresh

import winreg

_found_port_name = None
_found_port_number = None

def _find_rfid_port_via_pyserial():
    """Tenta localizar a porta via pyserial pela descrição do dispositivo."""
    try:
        import serial.tools.list_ports  # type: ignore
    except Exception:
        return None

    try:
        for p in serial.tools.list_ports.comports():
            desc = (p.description or "").lower()
            if "cp210x" in desc or "silicon labs" in desc:
                return p.device  # e.g., 'COM5'
    except Exception:
        return None
    return None

def find_rfid_port_via_registry():
    global _found_port_name
    if _found_port_name:
        return _found_port_name

    # print("🔍 Procurando porta COM via Registro do Windows (método não-intrusivo)...")
    registry_path = r"SYSTEM\CurrentControlSet\Enum\USB"

    try:
        with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, registry_path) as key:
            for i in range(winreg.QueryInfoKey(key)[0]):
                vid_pid_name = winreg.EnumKey(key, i)
                with winreg.OpenKey(key, vid_pid_name) as vid_pid_key:
                    for j in range(winreg.QueryInfoKey(vid_pid_key)[0]):
                        instance_name = winreg.EnumKey(vid_pid_key, j)
                        with winreg.OpenKey(vid_pid_key, instance_name) as instance_key:
                            try:
                                friendly_name, _ = winreg.QueryValueEx(instance_key, "FriendlyName")
                                if "CP210x" in friendly_name:
                                    with winreg.OpenKey(instance_key, "Device Parameters") as params_key:
                                        port_name, _ = winreg.QueryValueEx(params_key, "PortName")
                                        # print(f"✅ Hardware encontrado no Registro! Descrição: '{friendly_name}', Porta: {port_name}")
                                        _found_port_name = port_name
                                        return port_name
                            except FileNotFoundError:
                                continue
    except PermissionError:
            # print("❌ ERRO: Acesso negado ao Registro. Tente executar o programa como Administrador.")
        return None
    except Exception as e:
        # print(f"❌ Erro inesperado ao acessar o Registro do Windows: {e}")
        return None

    # print("❌ Hardware não encontrado no Registro do Windows.")
    return None

def force_refresh_cache():
    """Limpa o cache interno para forçar nova descoberta de porta."""
    global _found_port_name, _found_port_number
    _found_port_name = None
    _found_port_number = None

def get_com_port_number(refresh=False):
    """
    Retorna o número da porta COM do Reader.
    - Se refresh=True, limpa o cache e tenta novamente.
    - Primeiro tenta o Registro; se falhar, usa pyserial como fallback.
    """
    global _found_port_number
    if refresh:
        force_refresh_cache()

    if _found_port_number:
        return _found_port_number

    port_name = find_rfid_port_via_registry()
    if not port_name:
        pyserial_device = _find_rfid_port_via_pyserial()
        if pyserial_device:
            port_name = pyserial_device
            print(f"✅ Hardware encontrado via PySerial: {port_name}")

    if port_name:
        try:
            number = int(''.join(filter(str.isdigit, port_name)))
            _found_port_number = number
            return number
        except (ValueError, TypeError):
            return None
    return None