/**
 * 自然写互动课堂PC端应用软件 V1.0
 *
 * device_manager.ts - USB/BLE设备管理
 *
 * 功能说明：
 * - USB HID点阵笔连接管理
 * - BLE蓝牙点阵笔扫描与连接
 * - 设备数据解析（7字节紧凑坐标解码）
 * - 设备热插拔监听
 * - 多设备并行管理
 */

/* ======================== 类型定义 ======================== */

/** 设备连接方式 */
enum DeviceInterface {
    USB_HID = 'usb',
    BLE = 'ble'
}

/** 设备状态 */
enum DeviceStatus {
    DISCONNECTED = 'disconnected',
    CONNECTING = 'connecting',
    CONNECTED = 'connected',
    ERROR = 'error'
}

/** 点阵笔设备信息 */
interface PenDevice {
    id: string;               /* 设备唯一ID */
    name: string;             /* 设备名称 */
    macAddress: string;       /* MAC地址 */
    interface: DeviceInterface; /* 连接方式 */
    status: DeviceStatus;     /* 连接状态 */
    battery: number;          /* 电量百分比 */
    firmwareVersion: string;  /* 固件版本 */
    lastConnected: number;    /* 最后连接时间戳 */
}

/** 笔迹坐标点 */
interface StrokePoint {
    x: number;        /* X坐标(毫米) */
    y: number;        /* Y坐标(毫米) */
    pressure: number; /* 压力值(0-1) */
    timestamp: number; /* 时间戳(毫秒) */
    penDown: boolean;  /* 落笔标志 */
}

/** 设备事件回调 */
interface DeviceEventCallbacks {
    onDeviceDiscovered: (device: PenDevice) => void;
    onDeviceConnected: (device: PenDevice) => void;
    onDeviceDisconnected: (deviceId: string) => void;
    onStrokeData: (deviceId: string, points: StrokePoint[]) => void;
    onBatteryUpdate: (deviceId: string, level: number) => void;
    onError: (deviceId: string, error: string) => void;
}

/* ======================== USB HID常量 ======================== */

/** 自然写点阵笔USB VendorID */
const WRITECH_USB_VID = 0x1234;
/** 自然写点阵笔USB ProductID */
const WRITECH_USB_PID = 0x5678;
/** USB HID报文最大长度 */
const USB_REPORT_SIZE = 64;
/** USB轮询间隔（毫秒） */
const USB_POLL_INTERVAL = 5;

/* ======================== BLE常量 ======================== */

/** 自然写笔迹服务UUID */
const BLE_SERVICE_UUID = '0000ffe0-0000-1000-8000-00805f9b34fb';
/** 笔迹数据特征UUID（Notify） */
const BLE_STROKE_CHAR_UUID = '0000ffe1-0000-1000-8000-00805f9b34fb';
/** 电量特征UUID */
const BLE_BATTERY_CHAR_UUID = '0000ffe2-0000-1000-8000-00805f9b34fb';
/** 控制特征UUID（Write） */
const BLE_CONTROL_CHAR_UUID = '0000ffe3-0000-1000-8000-00805f9b34fb';

/* ======================== 坐标解码 ======================== */

/**
 * 解码7字节紧凑坐标编码
 * 编码格式: 20位X + 20位Y + 12位压力 + 4位标志
 */
function decodeCompactPoint(data: Buffer, offset: number): StrokePoint {
    /* 提取20位X坐标 */
    const rawX = (data[offset] << 12) |
                 (data[offset + 1] << 4) |
                 ((data[offset + 2] >> 4) & 0x0F);

    /* 提取20位Y坐标 */
    const rawY = ((data[offset + 2] & 0x0F) << 16) |
                 (data[offset + 3] << 8) |
                 data[offset + 4];

    /* 提取12位压力值 */
    const rawPressure = (data[offset + 5] << 4) |
                        ((data[offset + 6] >> 4) & 0x0F);

    /* 提取4位标志 */
    const flags = data[offset + 6] & 0x0F;

    return {
        x: rawX * 0.3,              /* 点阵码单位转毫米 */
        y: rawY * 0.3,
        pressure: rawPressure / 4095, /* 归一化到0-1 */
        timestamp: Date.now(),
        penDown: (flags & 0x01) !== 0
    };
}

/**
 * 计算CRC-16 CCITT校验
 */
function crc16CCITT(data: Buffer, length: number): number {
    let crc = 0xFFFF;
    for (let i = 0; i < length; i++) {
        crc ^= data[i] << 8;
        for (let j = 0; j < 8; j++) {
            if (crc & 0x8000) {
                crc = ((crc << 1) ^ 0x1021) & 0xFFFF;
            } else {
                crc = (crc << 1) & 0xFFFF;
            }
        }
    }
    return crc;
}

/* ======================== 设备管理器 ======================== */

/**
 * 点阵笔设备管理器
 * 统一管理USB和BLE连接的点阵笔设备
 */
class DeviceManager {
    /** 已连接设备列表 */
    private devices: Map<string, PenDevice> = new Map();
    /** 事件回调 */
    private callbacks: DeviceEventCallbacks;
    /** USB轮询定时器 */
    private usbPollTimer: ReturnType<typeof setInterval> | null = null;
    /** BLE扫描状态 */
    private bleScanning: boolean = false;
    /** 是否运行中 */
    private running: boolean = false;

    constructor(callbacks: DeviceEventCallbacks) {
        this.callbacks = callbacks;
        console.log('[设备管理] 初始化');
    }

    /* ==================== USB HID管理 ==================== */

    /**
     * 启动USB设备监听
     * 使用node-usb库检测设备热插拔
     */
    startUSBMonitor(): void {
        console.log('[设备管理] 启动USB监听');
        this.running = true;

        /* 枚举已连接的USB设备 */
        this.scanUSBDevices();

        /* 监听USB热插拔事件
           usb.on('attach', (device) => this.onUSBAttach(device));
           usb.on('detach', (device) => this.onUSBDetach(device)); */

        /* 启动USB数据轮询 */
        this.usbPollTimer = setInterval(() => {
            this.pollUSBData();
        }, USB_POLL_INTERVAL);
    }

    /**
     * 扫描已连接的USB HID设备
     */
    private scanUSBDevices(): void {
        /* const devices = HID.devices()
           .filter(d => d.vendorId === WRITECH_USB_VID &&
                       d.productId === WRITECH_USB_PID); */

        console.log('[设备管理] USB扫描完成');
    }

    /**
     * USB设备接入处理
     */
    private onUSBAttach(usbDevice: any): void {
        const deviceId = `usb_${usbDevice.serialNumber || Date.now()}`;

        const pen: PenDevice = {
            id: deviceId,
            name: `WritechPen-USB-${deviceId.slice(-4)}`,
            macAddress: '',
            interface: DeviceInterface.USB_HID,
            status: DeviceStatus.CONNECTED,
            battery: 100,
            firmwareVersion: '1.0.0',
            lastConnected: Date.now()
        };

        this.devices.set(deviceId, pen);
        this.callbacks.onDeviceConnected(pen);
        console.log(`[设备管理] USB设备接入: ${pen.name}`);
    }

    /**
     * USB设备拔出处理
     */
    private onUSBDetach(usbDevice: any): void {
        const deviceId = `usb_${usbDevice.serialNumber || ''}`;
        if (this.devices.has(deviceId)) {
            this.devices.delete(deviceId);
            this.callbacks.onDeviceDisconnected(deviceId);
            console.log(`[设备管理] USB设备断开: ${deviceId}`);
        }
    }

    /**
     * 轮询USB设备数据
     * 读取HID报文并解析坐标
     */
    private pollUSBData(): void {
        this.devices.forEach((device, deviceId) => {
            if (device.interface !== DeviceInterface.USB_HID) return;
            if (device.status !== DeviceStatus.CONNECTED) return;

            /* const report = hidDevice.readSync();
               if (report && report.length > 0) {
                   this.parseUSBReport(deviceId, Buffer.from(report));
               } */
        });
    }

    /**
     * 解析USB HID报文
     * 报文格式: [报文类型][数据长度][坐标数据...]
     */
    private parseUSBReport(deviceId: string, report: Buffer): void {
        const reportType = report[0];
        const dataLen = report[1];

        if (reportType === 0x01) {
            /* 笔迹数据报文: 每11字节一个坐标点(7字节坐标+4字节时间戳) */
            const points: StrokePoint[] = [];
            const pointSize = 11;

            for (let offset = 2; offset + pointSize <= 2 + dataLen; offset += pointSize) {
                const point = decodeCompactPoint(report, offset);
                /* 时间戳从报文中提取 */
                point.timestamp = report.readUInt32LE(offset + 7);
                points.push(point);
            }

            if (points.length > 0) {
                this.callbacks.onStrokeData(deviceId, points);
            }
        } else if (reportType === 0x04) {
            /* 电量报文 */
            const battery = report[2];
            this.callbacks.onBatteryUpdate(deviceId, battery);
        }
    }

    /* ==================== BLE管理 ==================== */

    /**
     * 启动BLE蓝牙扫描
     */
    startBLEScan(): void {
        if (this.bleScanning) return;

        console.log('[设备管理] 启动BLE扫描');
        this.bleScanning = true;

        /* noble.on('discover', (peripheral) => {
               if (peripheral.advertisement.localName?.startsWith('WritechPen')) {
                   this.onBLEDiscover(peripheral);
               }
           });
           noble.startScanning([BLE_SERVICE_UUID], true); */
    }

    /**
     * 停止BLE扫描
     */
    stopBLEScan(): void {
        this.bleScanning = false;
        /* noble.stopScanning(); */
        console.log('[设备管理] BLE扫描已停止');
    }

    /**
     * BLE设备发现回调
     */
    private onBLEDiscover(peripheral: any): void {
        const deviceId = `ble_${peripheral.address.replace(/:/g, '')}`;

        if (this.devices.has(deviceId)) return;

        const pen: PenDevice = {
            id: deviceId,
            name: peripheral.advertisement.localName || 'WritechPen',
            macAddress: peripheral.address,
            interface: DeviceInterface.BLE,
            status: DeviceStatus.DISCONNECTED,
            battery: 0,
            firmwareVersion: '',
            lastConnected: 0
        };

        this.callbacks.onDeviceDiscovered(pen);
        console.log(`[设备管理] 发现BLE设备: ${pen.name} [${pen.macAddress}]`);
    }

    /**
     * 连接BLE设备
     */
    async connectBLE(deviceId: string): Promise<boolean> {
        const device = this.devices.get(deviceId);
        if (!device || device.interface !== DeviceInterface.BLE) {
            return false;
        }

        device.status = DeviceStatus.CONNECTING;
        console.log(`[设备管理] 连接BLE设备: ${device.name}`);

        try {
            /* peripheral.connect((err) => { ... });
               peripheral.discoverServices([BLE_SERVICE_UUID], (err, services) => {
                   services[0].discoverCharacteristics([...], (err, chars) => {
                       // 订阅笔迹数据Notify
                       strokeChar.subscribe();
                       strokeChar.on('data', (data) => this.onBLEData(deviceId, data));
                   });
               }); */

            device.status = DeviceStatus.CONNECTED;
            device.lastConnected = Date.now();
            this.devices.set(deviceId, device);
            this.callbacks.onDeviceConnected(device);
            return true;
        } catch (err: any) {
            device.status = DeviceStatus.ERROR;
            this.callbacks.onError(deviceId, err.message);
            return false;
        }
    }

    /**
     * BLE数据接收回调
     */
    private onBLEData(deviceId: string, data: Buffer): void {
        /* BLE数据帧格式与USB类似：[帧头0xAA][类型][长度][数据...][CRC16] */
        if (data[0] !== 0xAA) return;

        const frameType = data[1];
        const payloadLen = data[2];

        /* CRC校验 */
        const expectedCrc = data.readUInt16LE(3 + payloadLen);
        const calcCrc = crc16CCITT(data.slice(0, 3 + payloadLen), 3 + payloadLen);
        if (expectedCrc !== calcCrc) {
            console.warn(`[设备管理] BLE数据CRC校验失败: ${deviceId}`);
            return;
        }

        if (frameType === 0x01) {
            /* 笔迹坐标数据 */
            const points: StrokePoint[] = [];
            const pointSize = 11;
            for (let i = 3; i + pointSize <= 3 + payloadLen; i += pointSize) {
                points.push(decodeCompactPoint(data, i));
            }
            if (points.length > 0) {
                this.callbacks.onStrokeData(deviceId, points);
            }
        } else if (frameType === 0x04) {
            /* 电量数据 */
            this.callbacks.onBatteryUpdate(deviceId, data[3]);
        }
    }

    /* ==================== 公共接口 ==================== */

    /** 获取所有已连接设备 */
    getConnectedDevices(): PenDevice[] {
        return Array.from(this.devices.values())
            .filter(d => d.status === DeviceStatus.CONNECTED);
    }

    /** 获取设备数量 */
    getDeviceCount(): number {
        return this.devices.size;
    }

    /** 断开指定设备 */
    disconnect(deviceId: string): void {
        const device = this.devices.get(deviceId);
        if (device) {
            device.status = DeviceStatus.DISCONNECTED;
            this.callbacks.onDeviceDisconnected(deviceId);
            console.log(`[设备管理] 断开设备: ${device.name}`);
        }
    }

    /** 停止所有设备管理 */
    shutdown(): void {
        this.running = false;
        if (this.usbPollTimer) {
            clearInterval(this.usbPollTimer);
        }
        this.stopBLEScan();
        this.devices.clear();
        console.log('[设备管理] 已关闭');
    }
}

export { DeviceManager, PenDevice, StrokePoint, DeviceStatus, DeviceInterface };
