package controller

import (
	"github.com/mitchellh/mapstructure"
	"log/slog"
	"slgserver/config"
	"slgserver/constant"
	"slgserver/middleware"
	"slgserver/net"
	chat_proto "slgserver/server/chatserver/proto"
	"slgserver/server/slgserver/proto"
	"strings"
	"sync"
)

var GHandle = Handle{
	proxys: make(map[string]map[int64]*net.ProxyClient),
}

type Handle struct {
	proxyMutex sync.Mutex
	proxys     map[string]map[int64]*net.ProxyClient
	slgProxy   string
	chatProxy  string
	loginProxy string
}

func isAccount(msgName string) bool {
	sArr := strings.Split(msgName, ".")
	prefix := ""
	if len(sArr) == 2{
		prefix = sArr[0]
	}
	if prefix == "account"{
		return true
	}else{
		return false
	}
}

func isChat(msgName string) bool {
	sArr := strings.Split(msgName, ".")
	prefix := ""
	if len(sArr) == 2{
		prefix = sArr[0]
	}
	if prefix == "chat"{
		return true
	}else{
		return false
	}
}



func (this*Handle) InitRouter(r *net.Router) {
	this.init()
	g := r.Group("*").Use(middleware.ElapsedTime(), middleware.Log())
	g.AddRouter("*", this.all)
}

func (this*Handle) init() {
	this.slgProxy = config.GetString("gateserver.slg_proxy", "ws://127.0.0.1:8001")
	this.chatProxy = config.GetString("gateserver.chat_proxy", "ws://127.0.0.1:8002")
	this.loginProxy = config.GetString("gateserver.login_proxy", "ws://127.0.0.1:8003")
}

func (this*Handle) onPush(conn *net.ClientConn, body *net.RspBody) {
	gc, err := conn.GetProperty("gateConn")
	if err != nil{
		return
	}
	gateConn := gc.(net.WSConn)
	gateConn.Push(body.Name, body.Msg)
}

func (this*Handle) onProxyClose(conn *net.ClientConn) {
	p, err := conn.GetProperty("proxy")
	if err == nil {
		proxyStr := p.(string)
		this.proxyMutex.Lock()
		_, ok := this.proxys[proxyStr]
		if ok {
			c, err := conn.GetProperty("cid")
			if err == nil{
				cid := c.(int64)
				delete(this.proxys[proxyStr], cid)
			}
		}
		this.proxyMutex.Unlock()
	}
}

func (this*Handle) OnServerConnClose (conn net.WSConn){
	c, err := conn.GetProperty("cid")
	arr := make([]*net.ProxyClient, 0)

	if err == nil{
		cid := c.(int64)
		this.proxyMutex.Lock()
		for _, m := range this.proxys {
			proxy, ok := m[cid]
			if ok {
				arr = append(arr, proxy)
			}
			delete(m, cid)
		}
		this.proxyMutex.Unlock()
	}

	for _, client := range arr {
		client.Close()
	}

}

func (this*Handle) all(req *net.WsMsgReq, rsp *net.WsMsgRsp) {
	slog.Info("gateserver handle all begin",
		"proxyStr", req.Body.Proxy,
		"msgName", req.Body.Name)
	this.deal(req, rsp)

	if req.Body.Name == "role.enterServer" && rsp.Body.Code == constant.OK  {
		//登录聊天服
		rspObj := &proto.EnterServerRsp{}
		mapstructure.Decode(rsp.Body.Msg, rspObj)
		r := &chat_proto.LoginReq{RId: rspObj.Role.RId, NickName: rspObj.Role.NickName, Token: rspObj.Token}
		reqBody := &net.ReqBody{Seq: 0, Name: "chat.login", Msg: r, Proxy: ""}
		rspBody := &net.RspBody{Seq: 0, Name: "chat.login", Msg: r, Code: 0}
		this.deal(&net.WsMsgReq{Body: reqBody, Conn:req.Conn}, &net.WsMsgRsp{Body: rspBody})
	}

	slog.Info("gateserver handle all end",
		"proxyStr", req.Body.Proxy,
		"msgName", req.Body.Name)
}

func (this*Handle) deal(req *net.WsMsgReq, rsp *net.WsMsgRsp) {
	//协议转发
	proxyStr := req.Body.Proxy
	if isAccount(req.Body.Name){
		proxyStr = this.loginProxy
	}else if isChat(req.Body.Name){
		proxyStr = this.chatProxy
	} else{
		proxyStr = this.slgProxy
	}

	if proxyStr == ""{
		rsp.Body.Code = constant.ProxyNotInConnect
		return
	}

	this.proxyMutex.Lock()
	_, ok := this.proxys[proxyStr]
	if ok == false {
		this.proxys[proxyStr] = make(map[int64]*net.ProxyClient)
	}

	var err error
	var proxy *net.ProxyClient
	d, _ := req.Conn.GetProperty("cid")
	cid := d.(int64)
	proxy, ok = this.proxys[proxyStr][cid]
	this.proxyMutex.Unlock()

	if ok == false {
		proxy = net.NewProxyClient(proxyStr)

		this.proxyMutex.Lock()
		this.proxys[proxyStr][cid] = proxy
		this.proxyMutex.Unlock()

		//发起链接,这里是阻塞的，所以不要上锁
		err = proxy.Connect()
		if err == nil{
			proxy.SetProperty("cid", cid)
			proxy.SetProperty("proxy", proxyStr)
			proxy.SetProperty("gateConn", req.Conn)
			proxy.SetOnPush(this.onPush)
			proxy.SetOnClose(this.onProxyClose)
		}
	}

	if err != nil {
		this.proxyMutex.Lock()
		delete(this.proxys[proxyStr], cid)
		this.proxyMutex.Unlock()
		rsp.Body.Code = constant.ProxyConnectError
		return
	}

	rsp.Body.Seq = req.Body.Seq
	rsp.Body.Name = req.Body.Name

	r, err := proxy.Send(req.Body.Name, req.Body.Msg)
	if err == nil{
		rsp.Body.Code = r.Code
		rsp.Body.Msg = r.Msg
	}else{
		rsp.Body.Code = constant.ProxyConnectError
		rsp.Body.Msg = nil
	}
}

