package net

import (
	"encoding/binary"

	"hk4e/pkg/endec"
	"hk4e/pkg/logger"
)

/*
										原神KCP协议(带*为xor加密数据)
0			1			2					4											8(字节)
+---------------------------------------------------------------------------------------+
|											conv										|
+---------------------------------------------------------------------------------------+
|	cmd		|	frg		|		wnd			|					ts						|
+---------------------------------------------------------------------------------------+
|						sn					|					una						|
+---------------------------------------------------------------------------------------+
|						len					|		0X4567*		|		cmdId*			|
+---------------------------------------------------------------------------------------+
|		headLen*		|				payloadLen*				|		head*			|
+---------------------------------------------------------------------------------------+
|								payload*						|		0X89AB*			|
+---------------------------------------------------------------------------------------+
*/

type KcpMsg struct {
	ConvId    uint64
	CmdId     uint16
	HeadData  []byte
	ProtoData []byte
}

func (k *KcpConnectManager) decodeBinToPayload(data []byte, dataBuf *[]byte, convId uint64, kcpMsgList *[]*KcpMsg, xorKey []byte) {
	// xor解密
	endec.Xor(data, xorKey)
	k.decodeLoop(data, dataBuf, convId, kcpMsgList)
}

func (k *KcpConnectManager) decodeLoop(data []byte, dataBuf *[]byte, convId uint64, kcpMsgList *[]*KcpMsg) {
	if len(*dataBuf) != 0 {
		// 取出之前的缓冲区数据
		data = append(*dataBuf, data...)
		*dataBuf = make([]byte, 0, 1500)
	}
	// 长度太短
	if len(data) < 12 {
		logger.Debug("packet len less 12 byte")
		return
	}
	// 头部幻数错误
	if data[0] != 0x45 || data[1] != 0x67 {
		logger.Error("packet head magic 0x4567 error")
		return
	}
	// 协议号
	cmdId := binary.BigEndian.Uint16(data[2:4])
	// 头部长度
	headLen := binary.BigEndian.Uint16(data[4:6])
	// proto长度
	protoLen := binary.BigEndian.Uint32(data[6:10])
	// 检查长度
	packetLen := int(headLen) + int(protoLen) + 12
	if packetLen > PacketMaxLen {
		logger.Error("packet len too long")
		return
	}
	haveMorePacket := false
	if len(data) > packetLen {
		// 有不止一个包
		haveMorePacket = true
	} else if len(data) < packetLen {
		// 这一次没收够 放入缓冲区
		*dataBuf = append(*dataBuf, data...)
		return
	}
	// 尾部幻数错误
	if data[int(headLen)+int(protoLen)+10] != 0x89 || data[int(headLen)+int(protoLen)+11] != 0xAB {
		logger.Error("packet tail magic 0x89AB error")
		return
	}
	// 头部数据
	headData := data[10 : 10+int(headLen)]
	// proto数据
	protoData := data[10+int(headLen) : 10+int(headLen)+int(protoLen)]
	// 返回数据
	kcpMsg := new(KcpMsg)
	kcpMsg.ConvId = convId
	kcpMsg.CmdId = cmdId
	kcpMsg.HeadData = headData
	kcpMsg.ProtoData = protoData
	*kcpMsgList = append(*kcpMsgList, kcpMsg)
	// 递归解析
	if haveMorePacket {
		k.decodeLoop(data[packetLen:], dataBuf, convId, kcpMsgList)
	}
}

func (k *KcpConnectManager) encodePayloadToBin(kcpMsg *KcpMsg, xorKey []byte) (bin []byte) {
	if kcpMsg.HeadData == nil {
		kcpMsg.HeadData = make([]byte, 0)
	}
	if kcpMsg.ProtoData == nil {
		kcpMsg.ProtoData = make([]byte, 0)
	}
	bin = make([]byte, len(kcpMsg.HeadData)+len(kcpMsg.ProtoData)+12)
	// 头部幻数
	bin[0] = 0x45
	bin[1] = 0x67
	// 协议号
	binary.BigEndian.PutUint16(bin[2:4], kcpMsg.CmdId)
	// 头部长度
	binary.BigEndian.PutUint16(bin[4:6], uint16(len(kcpMsg.HeadData)))
	// proto长度
	binary.BigEndian.PutUint32(bin[6:10], uint32(len(kcpMsg.ProtoData)))
	// 头部数据
	copy(bin[10:], kcpMsg.HeadData)
	// proto数据
	copy(bin[10+len(kcpMsg.HeadData):], kcpMsg.ProtoData)
	// 尾部幻数
	bin[len(bin)-2] = 0x89
	bin[len(bin)-1] = 0xAB
	// xor加密
	endec.Xor(bin, xorKey)
	return bin
}
