package com.narutohuo.xindazhou.ble.model

import kotlin.experimental.xor

/**
 * 分包协议数据包
 * 
 * 按照协议文档第3节"分包协议"定义
 */
data class Packet(
    /**
     * 包头（固定0x0A）
     */
    val header: Byte,
    
    /**
     * 业务ID（4字节）
     * 最后一个字节表示业务类型：0x01=请求，0x02=响应
     */
    val businessId: UInt,
    
    /**
     * 总包数（2字节）
     */
    val totalPackets: UShort,
    
    /**
     * 包序号（2字节，从0开始）
     */
    val packetSeq: UShort,
    
    /**
     * 数据长度（2字节）
     */
    val dataLength: UShort,
    
    /**
     * 数据区
     */
    val data: ByteArray,
    
    /**
     * 应答状态（1字节）
     * 0x01=ACK，0x02=REX
     */
    val responseStatus: Byte,
    
    /**
     * 包校验（1字节，异或校验）
     */
    val checksum: Byte,
    
    /**
     * 包尾（固定0x0D）
     */
    val tail: Byte
) {
    /**
     * 计算校验和
     */
    fun computeChecksum(): Byte {
        var sum: Byte = 0
        // businessId 拆成 4 个字节参与校验
        sum = sum xor (businessId.toInt() and 0xFF).toByte()
        sum = sum xor ((businessId.toInt() shr 8) and 0xFF).toByte()
        sum = sum xor ((businessId.toInt() shr 16) and 0xFF).toByte()
        sum = sum xor ((businessId.toInt() shr 24) and 0xFF).toByte()
        // totalPackets、packetSeq、dataLength 各 2 字节
        sum = sum xor (totalPackets.toInt() and 0xFF).toByte()
        sum = sum xor ((totalPackets.toInt() shr 8) and 0xFF).toByte()
        sum = sum xor (packetSeq.toInt() and 0xFF).toByte()
        sum = sum xor ((packetSeq.toInt() shr 8) and 0xFF).toByte()
        sum = sum xor (dataLength.toInt() and 0xFF).toByte()
        sum = sum xor ((dataLength.toInt() shr 8) and 0xFF).toByte()
        // data 区
        data.forEach { sum = sum xor it }
        // responseStatus
        sum = sum xor responseStatus
        return sum
    }
    
    /**
     * 校验当前对象的 checksum 是否正确
     */
    fun isValid(): Boolean = checksum == computeChecksum()
    
    /**
     * 获取消息类型（业务ID的最后一位）
     * 0x01=请求，0x02=响应
     */
    fun messageType(): Byte {
        return (businessId and 0xFFu).toByte()
    }
    
    /**
     * 根据收到的包生成确认响应报文（ACK）
     */
    fun buildAckResponse(): ByteArray {
        // 业务ID最低字节改为0x02（响应）
        val responseBusinessId = (this.businessId and 0xFFFFFF00u) or 0x02u
        
        val totalPackets = 0x0001.toUShort()
        val dataLength = 0x0000.toUShort()
        val responseStatus = 0x01.toByte() // ACK
        val tail = 0x0D.toByte()
        
        // 响应报文长度 = 1(header) + 4(businessId) + 2(total) + 2(seq) + 2(len) + 1(rsp) + 1(chk) + 1(tail) = 14
        val result = ByteArray(14)
        
        var pos = 0
        result[pos++] = 0x0A.toByte() // header
        
        // businessId（4字节，大端序）
        result[pos++] = ((responseBusinessId.toInt() shr 24) and 0xFF).toByte()
        result[pos++] = ((responseBusinessId.toInt() shr 16) and 0xFF).toByte()
        result[pos++] = ((responseBusinessId.toInt() shr 8) and 0xFF).toByte()
        result[pos++] = (responseBusinessId.toInt() and 0xFF).toByte()
        
        // totalPackets（2字节，大端序）
        result[pos++] = ((totalPackets.toInt() shr 8) and 0xFF).toByte()
        result[pos++] = (totalPackets.toInt() and 0xFF).toByte()
        
        // packetSeq（2字节，大端序）- 保持请求的seq
        result[pos++] = ((this.packetSeq.toInt() shr 8) and 0xFF).toByte()
        result[pos++] = (this.packetSeq.toInt() and 0xFF).toByte()
        
        // dataLength（2字节，大端序）
        result[pos++] = ((dataLength.toInt() shr 8) and 0xFF).toByte()
        result[pos++] = (dataLength.toInt() and 0xFF).toByte()
        
        // responseStatus
        result[pos++] = responseStatus
        
        // checksum（异或校验，从businessId开始到responseStatus）
        var checksum: Byte = 0x00
        for (i in 1 until pos) {
            checksum = checksum xor result[i]
        }
        result[pos++] = checksum
        
        // 包尾
        result[pos] = tail
        
        return result
    }
    
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as Packet

        if (header != other.header) return false
        if (businessId != other.businessId) return false
        if (totalPackets != other.totalPackets) return false
        if (packetSeq != other.packetSeq) return false
        if (dataLength != other.dataLength) return false
        if (!data.contentEquals(other.data)) return false
        if (responseStatus != other.responseStatus) return false
        if (checksum != other.checksum) return false
        if (tail != other.tail) return false

        return true
    }

    override fun hashCode(): Int {
        var result = header.toInt()
        result = 31 * result + businessId.hashCode()
        result = 31 * result + totalPackets.hashCode()
        result = 31 * result + packetSeq.hashCode()
        result = 31 * result + dataLength.hashCode()
        result = 31 * result + data.contentHashCode()
        result = 31 * result + responseStatus.toInt()
        result = 31 * result + checksum.toInt()
        result = 31 * result + tail.toInt()
        return result
    }
}

