package com.example.cmake_project_test

import java.nio.ByteBuffer
import java.nio.ByteOrder

/**
 * PPTM设备命令编码器
 * 负责编码PPTM设备的命令数据包，包含CRC16校验
 */
class PPTMCommandEncoder {
    
    companion object {
        private const val TAG = "PPTMCommandEncoder"
        private const val MAX_PACKET_SIZE = 244
        
        // PPTM协议操作码
        const val OPCODE_START_SAMPLE = 0x0001
        const val OPCODE_STOP_SAMPLE = 0x0001
        
        // PPTM协议常量
        const val COLLECTION_ON = 0x01
        const val COLLECTION_OFF = 0x00
    }
    
    /**
     * CRC-16-CCITT-FALSE校验
     * @param source 数据源
     * @param offset 偏移
     * @param length 长度
     * @return CRC校验值
     */
    fun crc16(source: ByteArray, offset: Int, length: Int): Int {
        var wCRCin = 0xFFFF
        val wCPoly = 0x1021
        
        for (i in offset until offset + length) {
            for (j in 0..7) {
                val bit = ((source[i].toInt() shr (7 - j)) and 1) == 1
                val c15 = ((wCRCin shr 15) and 1) == 1
                wCRCin = wCRCin shl 1
                if (c15 xor bit) {
                    wCRCin = wCRCin xor wCPoly
                }
            }
        }
        return wCRCin and 0xFFFF
    }
    
    /**
     * 编码命令数据
     * @param opcode 操作码
     * @param payload 负载数据
     * @param payloadLen 负载长度
     * @return 编码后的完整数据包
     */
    fun encode(opcode: Short, payload: ByteArray, payloadLen: Short): ByteArray {
        val buf = ByteBuffer.allocate(MAX_PACKET_SIZE)
        buf.order(ByteOrder.LITTLE_ENDIAN)
        
        // 写入操作码
        buf.putShort(opcode)
        
        // 写入负载长度
        buf.putShort(payloadLen)
        
        // 写入负载数据
        buf.put(payload)
        
        // 计算CRC16校验
        val calcCrcDataLen = buf.position()
        val crc = crc16(buf.array(), 0, calcCrcDataLen)
        buf.putShort(crc.toShort())
        
        // 获取完整数据包
        val allDataLen = buf.position()
        val dst = ByteArray(allDataLen)
        
        buf.flip()
        buf.get(dst, 0, allDataLen)
        
        return dst
    }
    
    /**
     * 创建PPTM开始采样命令
     * @return 编码后的命令
     */
    fun createPptmStartSampleCmd(): ByteArray {
        val payload = byteArrayOf(
            COLLECTION_ON.toByte(), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
        )
        return encode(OPCODE_START_SAMPLE.toShort(), payload, payload.size.toShort())
    }
    
    /**
     * 创建PPTM停止采样命令
     * @return 编码后的命令
     */
    fun createPptmStopSampleCmd(): ByteArray {
        val payload = byteArrayOf(
            COLLECTION_OFF.toByte(), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
        )
        return encode(OPCODE_STOP_SAMPLE.toShort(), payload, payload.size.toShort())
    }
    
    /**
     * 创建自定义PPTM命令
     * @param opcode 操作码
     * @param payload 负载数据
     * @return 编码后的命令
     */
    fun createCustomPptmCmd(opcode: Short, payload: ByteArray): ByteArray {
        return encode(opcode, payload, payload.size.toShort())
    }
    
    /**
     * 验证数据包CRC16校验
     * @param packet 完整数据包
     * @return 校验是否通过
     */
    fun verifyCrc16(packet: ByteArray): Boolean {
        if (packet.size < 6) return false // 至少需要操作码(2) + 长度(2) + CRC(2)
        
        val dataLen = packet.size - 2 // 减去CRC16的2字节
        val calculatedCrc = crc16(packet, 0, dataLen)
        val packetCrc = ((packet[packet.size - 1].toInt() and 0xFF) shl 8) or 
                        (packet[packet.size - 2].toInt() and 0xFF)
        
        return calculatedCrc == packetCrc
    }
    
    /**
     * 解析PPTM数据包
     * @param packet 完整数据包
     * @return 解析结果 (操作码, 负载数据) 或 null
     */
    fun parsePacket(packet: ByteArray): Pair<Short, ByteArray>? {
        if (!verifyCrc16(packet)) {
            return null
        }
        
        if (packet.size < 6) return null
        
        val buf = ByteBuffer.wrap(packet)
        buf.order(ByteOrder.LITTLE_ENDIAN)
        
        val opcode = buf.short
        val payloadLen = buf.short
        
        if (packet.size < 4 + payloadLen + 2) return null // 操作码(2) + 长度(2) + 负载 + CRC(2)
        
        val payload = ByteArray(payloadLen.toInt())
        buf.get(payload)
        
        return Pair(opcode, payload)
    }
}
