#!/usr/bin/env python3
"""
HMD Serial Number Update Script

Updates the HMD_Serial field in the device configuration of any Beyond.
Reads the current configuration, updates the HMD_Serial to a hardcoded value,
writes it back to the device, and verifies the update.
"""

import hid
import os
import sys
import time
import logging
import pyperclip
from plyer import notification
from steamvr.unbuffered.DeviceMonitor import instance

# logging.basicConfig(level=logging.DEBUG)  # debug

# Constants
ICON_PATH = os.path.join(sys._MEIPASS, 'favicon.ico') if hasattr(sys, '_MEIPASS') else 'favicon.ico'
BIGSCREEN_VID = 0x35BD
BEYOND_PID = 0x0101

reset_monitor = False

def read_device_serial(device):
    """
    Read serial from device
    """
    raw_serial = None
    logging.debug("Reading device serial...")
    # Send requests for 16 blocks of current config memory.
    device.send_feature_report([0, ord('&')])
    # Wait for reception of this block
    while True:
        data = device.read(64)
        if data:
            if data[0] == ord('&'):
                logging.debug(f"Received serial from device")
                raw_serial= bytes(data[1:63])
                break
    
    try:
        return raw_serial.decode('ascii').replace('\x00', '').strip()
    except UnicodeDecodeError:
        logging.debug("Warning: Could not decode device serial as ASCII")
        return None

def connect_to_device(path=None):
    """
    Connect to the HMD device
    """
    try:
        device = hid.device()
        if(path):
            device.open_path(path)
        else:
            device.open(BIGSCREEN_VID, BEYOND_PID)
        print("Connected to HMD")
        return device
    except Exception as e:
        raise Exception(f"Could not connect to HMD: {e}")
    
def on_new_hid_device(dev, hid_index, new_devs, prev_devs):
    """
    Copy hmd serial
    """
    global reset_monitor
    vid = dev['vendor_id']
    pid = dev['product_id']
    path = dev['path']
    device = None

    if vid == BIGSCREEN_VID and pid == BEYOND_PID and path not in prev_devs:
        try:
            print("")
            logging.debug(f"New HMD detected. Attempting connection...")
            
            # Connect to device
            device = connect_to_device(path)
            
            # Parse current HMD serial
            current_serial = read_device_serial(device)
            if current_serial:
                logging.debug(f"Found HMD serial: {current_serial}")
                pyperclip.copy(current_serial)
                print(f"Copied HMD serial '{current_serial}' to clipboard")
                notification.notify(f"{current_serial} --> Snatched!", "HMD serial copied to clipboard.", "HMD Serial Snatcher", timeout=10, app_icon=ICON_PATH)
            else:
                logging.warning("HMD serial not found or not set")
            
            
        except Exception as e:
            logging.error(f"{e}")
            return 1
        
        finally:
            if device:
                try:
                    device.close()
                    logging.debug("Device connection closed")
                    time.sleep(1)
                    reset_monitor = True
                except:
                    pass


def main():
    global reset_monitor

    print('')
    print("=== HMD Serial Snatcher ===")
    print("Now listening for new headsets...")

    instance.register_on_new_hid_device(on_new_hid_device)

    while True:
        time.sleep(1)
        if reset_monitor:
            time.sleep(5)
            instance.reset_history()
            reset_monitor = False
    
    return 0

if __name__ == "__main__":
    try:
        main()
    except BaseException as e:
        print(e)
    k = input("press close to exit")