// 协议栈上行模块模块
// 秒寻科技
// zt 2024-08-31

package psul

import (
	"encoding/binary"
	"errors"
	"fmt"
	"ipsomc/core/dao/redis/redisapi"
	"ipsomc/module/oam"
	"ipsomc/module/ps/ap"
	"ipsomc/module/ps/mcp"
	"ipsomc/module/ps/mcpb"
	"ipsomc/module/ps/psdl"
	"ipsomc/module/ps/psmodel"
	"ipsomc/module/socket/socketmodel"
	"ipsomc/util"
	"net"
)

type PsUl struct {
	psDlApi      psdl.PsDl
	apApi        ap.Ap
	mcpApi       mcp.Mcp
	mcpbApi      mcpb.McpB
	oamReportApi oam.OamReport
}

// 协议栈上行模块
// udpAddress:客户端地址
// dataList:数据队列
// dataListLen:数据队列长度
func (obj *PsUl) PsUl(udpAddress *net.UDPAddr, dataList []byte, dataListLen int) error {
	var dwLen int = dataListLen
	var wStopIndex = 0
	var redisObj redisapi.RedisApi
	var clientAddr socketmodel.ClientAddr

	//AP层处理
	pstHeadModel, pstTailModel, err := obj.apApi.ApUl(dataList, &dwLen)
	if err != nil {
		return err
	}

	//更新redis中的客户端连接
	myViper := util.GetViper()
	expireTime := myViper.GetInt("token.pc_expire")
	if expireTime <= 0 {
		expireTime = 10 //10分钟
	}

	//保存客户端IP和端口资料
	redisKey := fmt.Sprintf("%08X", int(pstHeadModel.StVpHead.ProjectID)) + "-" + fmt.Sprintf("%08X", int(pstHeadModel.StVpHead.DeviceID))
	ip := udpAddress.IP
	clientAddr.IP = append(clientAddr.IP, ip[0])
	clientAddr.IP = append(clientAddr.IP, ip[1])
	clientAddr.IP = append(clientAddr.IP, ip[2])
	clientAddr.IP = append(clientAddr.IP, ip[3])
	clientAddr.Port = udpAddress.Port
	clientAddr.Zone = udpAddress.Zone
	redisObj.SetModelData(redisKey, &clientAddr, uint16(expireTime))

	//VP层处理
	wStopIndex = dwLen - 3
	if err := obj.VpUl(pstHeadModel, pstTailModel, dataList[14:wStopIndex], dwLen-psmodel.PS_FRAME_MIN_LEN); err != nil {
		return err
	}

	return nil
}

// 协议栈上行模块
// tcpAddress:客户端地址
// dataList:数据队列
// dataListLen:数据队列长度
func (obj *PsUl) PsUlTcp(clientAddress string, dataList []byte, dataListLen int) error {
	var dwLen int = dataListLen
	var wStopIndex = 0
	var redisObj redisapi.RedisApi
	var clientAddr socketmodel.ClientAddr

	//AP层处理
	pstHeadModel, pstTailModel, err := obj.apApi.ApUl(dataList, &dwLen)
	if err != nil {
		return err
	}

	//更新redis中的客户端连接
	myViper := util.GetViper()
	expireTime := myViper.GetInt("token.pc_expire")
	if expireTime <= 0 {
		expireTime = 10 //10分钟
	}

	//保存客户端IP和端口资料
	redisKey := fmt.Sprintf("%08X", int(pstHeadModel.StVpHead.ProjectID)) + "-" + fmt.Sprintf("%08X", int(pstHeadModel.StVpHead.DeviceID))
	clientAddr.Address = clientAddress
	redisObj.SetModelData(redisKey, &clientAddr, uint16(expireTime))

	//VP层处理
	wStopIndex = dwLen - 3
	if err := obj.VpUl(pstHeadModel, pstTailModel, dataList[14:wStopIndex], dwLen-psmodel.PS_FRAME_MIN_LEN); err != nil {
		return err
	}

	return nil
}

// VP层上行
func (obj *PsUl) VpUl(stHeadModel *psmodel.PS_HEAD_T, stTailModel *psmodel.PS_TAIL_T, dataList []byte, dwLen int) error {
	vpModel := &stHeadModel.StVpHead

	//vp层解析
	if vpModel.McpType == psmodel.MCP_A { //MCP-A
		switch vpModel.VpFlag {
		case psmodel.VP_CMMD: //MCP-A命令
			if err := obj.McpUlCmdA(stHeadModel, stTailModel, dataList, dwLen); err != nil {
				return err
			}
		case psmodel.VP_RESP: //MCP-A应答
			obj.McpUlRespA(stHeadModel, dataList, dwLen)
		default:
			return errors.New("VP层格式错误")
		}
	} else if vpModel.McpType == psmodel.MCP_B { //MCP-B
		if vpModel.VpFlag == psmodel.VP_RESP {
			obj.mcpbApi.McpUlRespB(stHeadModel, dataList, dwLen)
		}
	} else {
		return errors.New("MCP层格式错误")
	}

	return nil
}

// MCP-A设置命令
// dataList:MCP层数据队列
// wLen:数据队列长度
func (obj *PsUl) McpUlCmdA(stHeadModel *psmodel.PS_HEAD_T, stTailModel *psmodel.PS_TAIL_T, dataList []byte, wLen int) error {
	var wCurrentLen uint16 = 0
	var wLtvLen uint16 = 0
	var wCommand uint16 = 0
	ltvData := make([]byte, psmodel.PS_MCP_A_DATA_LEN)
	var byRespFlag uint8 = 0

	//遍历数据队列
	for {
		if wCurrentLen >= uint16(wLen) {
			break
		}

		//组织一个ltv数据
		wLtvLen = uint16(binary.LittleEndian.Uint16(dataList[wCurrentLen : wCurrentLen+2]))    //长度
		wCommand = uint16(binary.LittleEndian.Uint16(dataList[wCurrentLen+2 : wCurrentLen+4])) //命令
		copy(ltvData, dataList[wCurrentLen+4:wCurrentLen+wLtvLen])                             //数据

		//根据监控命令处理
		if wCommand >= 0x0201 && wCommand <= 0x02FF { // 上报
			obj.oamReportApi.OamReportCmd(stHeadModel, wCommand, ltvData, wLtvLen-4)
			byRespFlag = 1
		}

		//数据后移
		wCurrentLen += wLtvLen
	}

	//发送上行命令的应答
	if byRespFlag == 1 {
		if err := obj.psDlApi.PsDlResp(stHeadModel, dataList); err != nil {
			return err
		}
	}

	return nil
}

// MCP-A层上行应答
// stHeadModel:协议头
// dataList:MCP层数据队列
// dataListLen:数据队列长度
func (obj *PsUl) McpUlRespA(stHeadModel *psmodel.PS_HEAD_T, dataList []byte, dwLen int) error {
	mcpModel := stHeadModel.StMcpHead

	//应答标识符检查
	if mcpModel.Resp != psmodel.MCP_RESP_SUCC {
		return errors.New("响应消息失败")
	}

	//MCP命令检查
	switch mcpModel.Comd {
	case psmodel.MCP_A_REPORT: //上报
	case psmodel.MCP_A_QUERY: //查询
		obj.mcpApi.McpAUlRespQuery(stHeadModel, dataList, dwLen) //响应
	case psmodel.MCP_A_CONFIGURE: //配置
		obj.mcpApi.McpAUlRespSet(stHeadModel, dataList, dwLen) //响应
	default:
		return errors.New("MCP命令类型错误")
	}

	return nil
}
