"""
Modulo de comunicacion con el programador IR de pulseras LED.
Extraido de programar_pulsera.py - protocolo decodificado por ingenieria inversa.

Hardware: CH9326 (USB HID-UART) + STC 8C2K32S2
VID: 0x1A86, PID: 0xE010, UART: 9600 baud 8N1

Protocolo: [0x05][R][Rhi][Rlo][G][Ghi][Glo][B][Bhi][Blo][checksum]
"""
import hid
import time

VID = 0x1A86
PID = 0xE010


def connect():
    """Conecta al programador USB. Retorna el device HID o None."""
    devices = hid.enumerate(VID, PID)
    if not devices:
        return None
    target = next((d for d in devices if d['usage_page'] == 0xFFA0), devices[0])
    dev = hid.device()
    dev.open_path(target['path'])
    dev.set_nonblocking(1)
    return dev


def disconnect(dev):
    """Cierra la conexion HID."""
    if dev:
        try:
            dev.close()
        except Exception:
            pass


def is_connected(dev):
    """Verifica si el device sigue conectado."""
    if dev is None:
        return False
    try:
        dev.read(64)
        return True
    except Exception:
        return False


def build_packet(red_min=0, green_min=0, blue_min=0):
    """Construye el paquete de 11 bytes. Tiempos en minutos (0-65535)."""
    packet = [
        0x05,
        0x52, (red_min >> 8) & 0xFF, red_min & 0xFF,
        0x47, (green_min >> 8) & 0xFF, green_min & 0xFF,
        0x42, (blue_min >> 8) & 0xFF, blue_min & 0xFF,
    ]
    packet.append(sum(packet) & 0xFF)
    return packet


def send_packet(dev, packet):
    """Envia paquete al CH9326 con prefijo de longitud."""
    length = len(packet)
    buf = [0x00, length] + list(packet) + [0x00] * (31 - length)
    return dev.write(buf[:33])


def read_response(dev, timeout=0.5):
    """Lee respuesta del MCU. Retorna 'FAIL', 'OK', o None."""
    start = time.time()
    while time.time() - start < timeout:
        data = dev.read(64)
        if data:
            plen = data[0]
            if plen == 0x06 and data[1] == 0x05 and bytes(data[2:7]) == b'FAIL!':
                return 'FAIL'
            elif plen == 0x04 and data[1] == 0x05 and data[2] == 0x4F and data[3] == 0x4B:
                return 'OK'
        time.sleep(0.001)
    return None


def program_wristband(dev, red_min, green_min, blue_min, timeout=30):
    """
    Envia paquete continuamente hasta que una pulsera responda OK o expire el timeout.
    Retorna ('ok', timestamp) o ('timeout', None) o ('error', message).
    """
    packet = build_packet(red_min, green_min, blue_min)
    hex_str = ' '.join(f'{b:02X}' for b in packet)
    print(f"[IR] Packet R={red_min} G={green_min} B={blue_min} -> [{hex_str}]", flush=True)
    start = time.time()

    while time.time() - start < timeout:
        try:
            send_packet(dev, packet)
        except Exception as e:
            return ('error', str(e))

        resp = read_response(dev, timeout=1.0)
        if resp == 'OK':
            from datetime import datetime
            elapsed = time.time() - start
            print(f"[IR] OK en {elapsed:.1f}s", flush=True)
            return ('ok', datetime.now().isoformat())

        time.sleep(0.1)

    return ('timeout', None)
