package net

import (
	"bytes"
	"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, convId uint64, kcpMsgList *[]*KcpMsg) {
	// xor解密
	k.kcpKeyMapLock.RLock()
	xorKey, exist := k.kcpKeyMap[convId]
	k.kcpKeyMapLock.RUnlock()
	if !exist {
		logger.LOG.Error("kcp xor key not exist, convId: %v", convId)
		return
	}
	endec.Xor(data, xorKey)
	k.decodeRecur(data, convId, kcpMsgList)
}

func (k *KcpConnectManager) decodeRecur(data []byte, convId uint64, kcpMsgList *[]*KcpMsg) {
	// 长度太短
	if len(data) < 12 {
		logger.LOG.Debug("packet len less 12 byte")
		return
	}
	// 头部标志错误
	if data[0] != 0x45 || data[1] != 0x67 {
		logger.LOG.Error("packet head magic 0x4567 error")
		return
	}
	// 协议号
	cmdIdByteSlice := make([]byte, 8)
	cmdIdByteSlice[6] = data[2]
	cmdIdByteSlice[7] = data[3]
	cmdIdBuffer := bytes.NewBuffer(cmdIdByteSlice)
	var cmdId int64
	err := binary.Read(cmdIdBuffer, binary.BigEndian, &cmdId)
	if err != nil {
		logger.LOG.Error("packet cmd id parse fail: %v", err)
		return
	}
	// 头部长度
	headLenByteSlice := make([]byte, 8)
	headLenByteSlice[6] = data[4]
	headLenByteSlice[7] = data[5]
	headLenBuffer := bytes.NewBuffer(headLenByteSlice)
	var headLen int64
	err = binary.Read(headLenBuffer, binary.BigEndian, &headLen)
	if err != nil {
		logger.LOG.Error("packet head len parse fail: %v", err)
		return
	}
	// proto长度
	protoLenByteSlice := make([]byte, 8)
	protoLenByteSlice[4] = data[6]
	protoLenByteSlice[5] = data[7]
	protoLenByteSlice[6] = data[8]
	protoLenByteSlice[7] = data[9]
	protoLenBuffer := bytes.NewBuffer(protoLenByteSlice)
	var protoLen int64
	err = binary.Read(protoLenBuffer, binary.BigEndian, &protoLen)
	if err != nil {
		logger.LOG.Error("packet proto len parse fail: %v", err)
		return
	}
	// 检查最小长度
	if len(data) < int(headLen+protoLen)+12 {
		logger.LOG.Error("packet len error")
		return
	}
	// 尾部标志错误
	if data[headLen+protoLen+10] != 0x89 || data[headLen+protoLen+11] != 0xAB {
		logger.LOG.Error("packet tail magic 0x89AB error")
		return
	}
	// 判断是否有不止一个包
	haveMoreData := false
	if len(data) > int(headLen+protoLen)+12 {
		haveMoreData = true
	}
	// 头部数据
	headData := data[10 : 10+headLen]
	// proto数据
	protoData := data[10+headLen : 10+headLen+protoLen]
	// 返回数据
	kcpMsg := new(KcpMsg)
	kcpMsg.ConvId = convId
	kcpMsg.CmdId = uint16(cmdId)
	//kcpMsg.HeadData = make([]byte, len(headData))
	//copy(kcpMsg.HeadData, headData)
	//kcpMsg.ProtoData = make([]byte, len(protoData))
	//copy(kcpMsg.ProtoData, protoData)
	kcpMsg.HeadData = headData
	kcpMsg.ProtoData = protoData
	*kcpMsgList = append(*kcpMsgList, kcpMsg)
	// 递归解析
	if haveMoreData {
		k.decodeRecur(data[int(headLen+protoLen)+12:], convId, kcpMsgList)
	}
}

func (k *KcpConnectManager) encodePayloadToBin(kcpMsg *KcpMsg) (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
	// 协议号
	cmdIdBuffer := bytes.NewBuffer([]byte{})
	err := binary.Write(cmdIdBuffer, binary.BigEndian, kcpMsg.CmdId)
	if err != nil {
		logger.LOG.Error("cmd id encode err: %v", err)
		return nil
	}
	bin[2] = (cmdIdBuffer.Bytes())[0]
	bin[3] = (cmdIdBuffer.Bytes())[1]
	// 头部长度
	headLenBuffer := bytes.NewBuffer([]byte{})
	err = binary.Write(headLenBuffer, binary.BigEndian, uint16(len(kcpMsg.HeadData)))
	if err != nil {
		logger.LOG.Error("head len encode err: %v", err)
		return nil
	}
	bin[4] = (headLenBuffer.Bytes())[0]
	bin[5] = (headLenBuffer.Bytes())[1]
	// proto长度
	protoLenBuffer := bytes.NewBuffer([]byte{})
	err = binary.Write(protoLenBuffer, binary.BigEndian, uint32(len(kcpMsg.ProtoData)))
	if err != nil {
		logger.LOG.Error("proto len encode err: %v", err)
		return nil
	}
	bin[6] = (protoLenBuffer.Bytes())[0]
	bin[7] = (protoLenBuffer.Bytes())[1]
	bin[8] = (protoLenBuffer.Bytes())[2]
	bin[9] = (protoLenBuffer.Bytes())[3]
	// 头部数据
	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加密
	k.kcpKeyMapLock.RLock()
	xorKey, exist := k.kcpKeyMap[kcpMsg.ConvId]
	k.kcpKeyMapLock.RUnlock()
	if !exist {
		logger.LOG.Error("kcp xor key not exist, convId: %v", kcpMsg.ConvId)
		return
	}
	endec.Xor(bin, xorKey)
	return bin
}
