package models

import (
	"encoding/binary"
	"fmt"
)

// MQTT解析
type MqttAnalysis struct {
}

// 解析MQTT剩余长度
func (ggg *MqttAnalysis) DecodeRemainingLength(buf []byte) (int, int, error) {
	multiplier := 1
	value := 0
	index := 0
	for {
		if index >= len(buf) {
			return 0, 0, fmt.Errorf("剩余长度解析不完整")
		}
		digit := int(buf[index])
		value += (digit & 127) * multiplier
		if multiplier > 128*128*128 {
			return 0, 0, fmt.Errorf("剩余长度过大")
		}
		multiplier *= 128
		index++
		if (digit & 128) == 0 {
			break
		}
	}
	return value, index, nil
}

// 解析MQTT CONNECT报文
func (ggg *MqttAnalysis) ParseConnectPacket(data []byte) (map[string]string, error) {
	result := make(map[string]string)
	// 跳过固定报头和剩余长度
	pos := 2
	// 解析协议名
	protocolLen := binary.BigEndian.Uint16(data[pos : pos+2])
	pos += 2
	protocolName := string(data[pos : pos+int(protocolLen)])
	pos += int(protocolLen)
	result["ProtocolName"] = protocolName
	// 解析协议级别
	protocolLevel := data[pos]
	pos++
	result["ProtocolLevel"] = fmt.Sprintf("%d", protocolLevel)
	// 解析连接标志
	connectFlags := data[pos]
	pos++
	// 解析保持活动时间
	keepAlive := binary.BigEndian.Uint16(data[pos : pos+2])
	pos += 2
	result["KeepAlive"] = fmt.Sprintf("%d", keepAlive)
	// 解析客户端ID
	clientIDLen := binary.BigEndian.Uint16(data[pos : pos+2])
	pos += 2
	clientID := string(data[pos : pos+int(clientIDLen)])
	pos += int(clientIDLen)
	result["ClientID"] = clientID
	// 解析用户名和密码
	if connectFlags&0x80 != 0 {
		usernameLen := binary.BigEndian.Uint16(data[pos : pos+2])
		pos += 2
		username := string(data[pos : pos+int(usernameLen)])
		pos += int(usernameLen)
		result["Username"] = username
	}

	if connectFlags&0x40 != 0 {
		passwordLen := binary.BigEndian.Uint16(data[pos : pos+2])
		pos += 2
		password := string(data[pos : pos+int(passwordLen)])
		pos += int(passwordLen)
		result["Password"] = password
	}

	return result, nil
}

// 生成MQTT CONNACK报文
func (ggg *MqttAnalysis) GenerateConnackPacket(sessionPresent bool, returnCode byte) []byte {
	connack := make([]byte, 4)
	connack[0] = 0x20 // 固定报头：CONNACK
	connack[1] = 0x02 // 剩余长度
	if sessionPresent {
		connack[2] = 0x01 // 会话存在标志
	} else {
		connack[2] = 0x00 // 会话不存在标志
	}
	connack[3] = returnCode // 返回码
	return connack
}

// 生成MQTT PUBLISH报文
func (ggg *MqttAnalysis) GeneratePublishPacket(topic string, payload []byte, qos byte, retain bool, packetID uint16) ([]byte, error) {
	// 验证参数有效性
	if qos > 2 {
		return nil, fmt.Errorf("无效的QoS级别: %d", qos)
	}

	topicLength := len(topic)
	if topicLength > 65535 {
		return nil, fmt.Errorf("主题名长度超出限制")
	}

	// 计算剩余长度
	variableHeaderLength := 2 + topicLength // 主题长度字段(2字节) + 主题名
	if qos > 0 {
		variableHeaderLength += 2 // 包ID
	}
	remainingLength := variableHeaderLength + len(payload)

	// 构建固定报头 (类型 + 标志位)
	fixedHeader := byte(0x30) // PUBLISH类型
	// 设置QoS级别
	fixedHeader |= (qos << 1) & 0x06
	// 设置保留标志
	if retain {
		fixedHeader |= 0x01
	}

	// 编码剩余长度
	remainingBytes := ggg.EncodeRemainingLength(remainingLength)

	// 构建可变报头
	variableHeader := make([]byte, variableHeaderLength)
	binary.BigEndian.PutUint16(variableHeader[0:2], uint16(topicLength))
	copy(variableHeader[2:], topic)

	// QoS>0时添加PacketID
	if qos > 0 {
		binary.BigEndian.PutUint16(variableHeader[2+topicLength:], packetID)
	}

	// 组合完整报文
	message := make([]byte, 1+len(remainingBytes)+len(variableHeader)+len(payload))
	message[0] = fixedHeader
	copy(message[1:], remainingBytes)
	copy(message[1+len(remainingBytes):], variableHeader)
	copy(message[1+len(remainingBytes)+len(variableHeader):], payload)

	return message, nil
}

// 构建MQTT PUBLISH消息
func (ggg *MqttAnalysis) BuildPublishMessage(topic string, payload []byte, qos byte, retain bool) ([]byte, error) {
	// 验证QoS值
	if qos > 2 {
		return nil, fmt.Errorf("无效的QoS级别: %d", qos)
	}

	topicLength := len(topic) // 计算主题名长度
	if topicLength > 65535 {
		return nil, fmt.Errorf("主题名长度超出限制")
	}

	// 计算剩余长度
	// 剩余长度 = 主题名长度(2字节) + 主题名 + 可选PacketID(2字节) + 载荷长度
	remainingLength := 2 + topicLength + len(payload)
	if qos > 0 {
		remainingLength += 2 // 包含PacketID
	}

	// 构建固定报头
	fixedHeader := byte(0x30) // PUBLISH类型
	// 设置QoS级别
	fixedHeader |= (qos << 1) & 0x06
	// 设置保留标志
	if retain {
		fixedHeader |= 0x01
	}

	// 编码剩余长度
	remainingBytes := ggg.EncodeRemainingLength(remainingLength)

	// 构建可变报头
	variableHeader := make([]byte, 2+topicLength)
	binary.BigEndian.PutUint16(variableHeader[0:2], uint16(topicLength))
	copy(variableHeader[2:], topic)

	// 如果QoS>0，添加PacketID
	var packetIDBytes []byte
	if qos > 0 {
		packetIDBytes = make([]byte, 2)
		// 这里应该使用唯一的PacketID，示例中使用固定值
		binary.BigEndian.PutUint16(packetIDBytes, uint16(1234))
	}

	// 组装完整消息
	message := make([]byte, 1+len(remainingBytes)+len(variableHeader)+len(packetIDBytes)+len(payload))
	message[0] = fixedHeader
	copy(message[1:], remainingBytes)
	copy(message[1+len(remainingBytes):], variableHeader)
	if qos > 0 {
		copy(message[1+len(remainingBytes)+len(variableHeader):], packetIDBytes)
	}
	copy(message[1+len(remainingBytes)+len(variableHeader)+len(packetIDBytes):], payload)

	return message, nil
}

// 生成MQTT SUBACK报文
func (ggg *MqttAnalysis) GenerateSubackPacket(packetID uint16, returnCodes []byte) []byte {
	// 计算剩余长度
	remainingLength := 2 + len(returnCodes)

	// 构建固定报头
	fixedHeader := []byte{
		0x90, // SUBACK报文类型
		byte(remainingLength),
	}

	// 构建可变报头
	variableHeader := make([]byte, 2)
	binary.BigEndian.PutUint16(variableHeader, packetID)

	// 组合完整报文
	return append(append(fixedHeader, variableHeader...), returnCodes...)
}

// 编码剩余长度字段（MQTT协议特有变长编码）
func (ggg *MqttAnalysis) EncodeRemainingLength(length int) []byte {
	var result []byte
	for {
		digit := byte(length % 128)
		length = length / 128
		if length > 0 {
			digit |= 0x80
		}
		result = append(result, digit)
		if length == 0 {
			break
		}
	}
	return result
}
