package logic

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"fusenapi/server/websocket/internal/config"
	"github.com/zeromicro/go-zero/core/logx"
	"net"
	"time"
)

var (
	//取消unity僵尸任务控制通道
	cancelUnityCtlChan              = make(chan cancelUnityCtlChanItem, 1000)
	cancelRenderContextPanicMsg any = "cancel_render_context_panic_msg"
)

// 控制通道元素
type cancelUnityCtlChanItem struct {
	Wid          string `json:"wid"`           //ws的唯一id
	DeadlineTime int64  `json:"deadline_time"` //截断时间
	Sign         string `json:"sign"`          //有效签名
}

// 取消渲染抛出的异常
func cancelRenderPanic() {
	panic(cancelRenderContextPanicMsg)
}

// 判断是否是取消渲染的异常
func isCancelRenderPanic(err any) bool {
	return err == cancelRenderContextPanicMsg
}

// 发送取消上下文消息给unity
func sendCancelRenderMsgToUnity(wid string, deadlineTime int64) {
	data := cancelUnityCtlChanItem{
		Wid:          wid,
		DeadlineTime: deadlineTime,
		Sign:         signMessage(wid, deadlineTime),
	}
	select {
	case cancelUnityCtlChan <- data:
	case <-time.After(time.Millisecond * 200):
		logx.Error("sendCancelRenderMsgToUnity数据超时丢弃")
	}
}

// 拨号udp
func DialUdp(config config.Config) error {
	localAddr := &net.UDPAddr{IP: net.ParseIP(config.Unity.Udp.LocalAddr), Port: config.Unity.Udp.LocalPort}
	remoteAddr := &net.UDPAddr{IP: net.ParseIP(config.Unity.Udp.RemoteAddr), Port: config.Unity.Udp.RemotePort}
	conn, err := net.DialUDP("udp", localAddr, remoteAddr)
	if err != nil {
		return err
	}
	go ConsumeCancelUnityChanMessage(conn)
	return nil
}

// 签名消息
func signMessage(wid string, deadlineTime int64) string {
	h := md5.New()
	h.Write([]byte(fmt.Sprintf("%s_fusen_control_unity_%d", wid, deadlineTime)))
	return hex.EncodeToString(h.Sum(nil))
}

// 消费数据
func ConsumeCancelUnityChanMessage(conn *net.UDPConn) {
	defer func() {
		if err := recover(); err != nil {
			logx.Error("ConsumeCancelUnityChanMessage 异常:", err)
		}
	}()
	defer conn.Close()
	for {
		select {
		case data := <-cancelUnityCtlChan:
			d, _ := json.Marshal(data)
			_, err := conn.Write(d)
			if err != nil {
				//logx.Error("发送udp包通知Unity失败:", err)
				continue
			}
		}
	}
}