package main

import (
	"mongo.games.com/goserver/core/basic"
	"mongo.games.com/goserver/core/module"
	"mongo.games.com/goserver/core/signal"
	"os"
	"time"

	"mongo.games.com/goserver/core/timer"

	"mongo.games.com/game/common"
	"mongo.games.com/game/proto"
	"mongo.games.com/game/protocol/server"
	"mongo.games.com/goserver/core"
	"mongo.games.com/goserver/core/logger"
	"mongo.games.com/goserver/core/transact"
	"mongo.games.com/goserver/srvlib"
)

const (
	STOPAPI_TRANSACTE_UD int = iota
)

type StopAPIUserData struct {
	wait    chan struct{}
	srvtype int
	timeout time.Duration
}

type InterruptSignalHandler struct {
}

func (ish *InterruptSignalHandler) Process(s os.Signal, ud interface{}) error {
	logger.Logger.Warn("Receive Interrupt signal, process be close!!!")
	wait := make(chan struct{}, 1)

	//wait all world server close
	StopServer(wait, srvlib.WorldServerType, time.Minute*5)

	//shutdown all server
	ShutdownAllServer(wait, time.Minute*10)

	//close self
	core.CoreObject().SendCommand(basic.CommandWrapper(func(o *basic.Object) error {
		module.Stop()
		return nil
	}), false)
	return nil
}

func StopServer(wait chan struct{}, srvtype int, timeout time.Duration) {
	core.CoreObject().SendCommand(basic.CommandWrapper(func(o *basic.Object) error {
		logger.Logger.Infof("StopApi start transcate srvtype(%v) timeout(%v)", srvtype, timeout)
		tnp := &transact.TransNodeParam{
			Tt:     common.TransType_StopServer,
			Ot:     transact.TransOwnerType(common.GetSelfSrvType()),
			Oid:    common.GetSelfSrvId(),
			AreaID: common.GetSelfAreaId(),
		}
		tNode := transact.DTCModule.StartTrans(tnp, &StopAPIUserData{wait: wait, srvtype: srvtype, timeout: timeout}, timeout)
		if tNode != nil {
			tNode.Go(core.CoreObject())
		}
		return nil
	}), false)
	select {
	case _ = <-wait:
		logger.Logger.Infof("StopApi transcate srvtype(%v) all done!!!", srvtype)
	case <-time.After(timeout):
		logger.Logger.Infof("StopApi transcate srvtype(%v) timeout force stop!!!", srvtype)
	}
}

func ShutdownAllServer(wait chan struct{}, timeout time.Duration) {
	core.CoreObject().SendCommand(basic.CommandWrapper(func(o *basic.Object) error {
		logger.Logger.Infof("StopApi start shutdown all server")
		ctrlPacket := &server.ServerCtrl{
			CtrlCode: proto.Int32(common.SrvCtrlCloseCode),
		}
		proto.SetDefaults(ctrlPacket)
		srvlib.ServerSessionMgrSington.Broadcast(int(server.SSPacketID_PACKET_MS_SRVCTRL), ctrlPacket, common.GetSelfAreaId(), srvlib.GameServerType)
		srvlib.ServerSessionMgrSington.Broadcast(int(server.SSPacketID_PACKET_MS_SRVCTRL), ctrlPacket, common.GetSelfAreaId(), srvlib.GateServerType)
		srvlib.ServerSessionMgrSington.Broadcast(int(server.SSPacketID_PACKET_MS_SRVCTRL), ctrlPacket, common.GetSelfAreaId(), srvlib.WorldServerType)

		//启动定时器检测
		timer.StartTimer(timer.TimerActionWrapper(func(h timer.TimerHandle, ud interface{}) bool {
			gameId := srvlib.ServerSessionMgrSington.GetServerId(common.GetSelfAreaId(), srvlib.GameServerType)
			if gameId != -1 {
				logger.Logger.Infof("StopApi start shutdown all server gameId:%v", gameId)
				return true
			}
			gateId := srvlib.ServerSessionMgrSington.GetServerId(common.GetSelfAreaId(), srvlib.GateServerType)
			if gateId != -1 {
				logger.Logger.Infof("StopApi start shutdown all server gateId:%v", gateId)
				return true
			}
			worldId := srvlib.ServerSessionMgrSington.GetServerId(common.GetSelfAreaId(), srvlib.WorldServerType)
			if worldId != -1 {
				logger.Logger.Infof("StopApi start shutdown all server worldId:%v", worldId)
				return true
			}
			wait <- struct{}{}
			timer.StopTimer(h)
			return true
		}), nil, time.Second, -1)
		return nil
	}), false)

	select {
	case _ = <-wait:
		logger.Logger.Info("StopApi ShutdownAllServer all done!!!")
	case <-time.After(timeout):
		logger.Logger.Info("StopApi ShutdownAllServer timeout force stop!!!")
	}
}
func init() {
	core.RegisteHook(core.HOOK_BEFORE_START, func() error {
		signal.SignalHandlerModule.ClearHandler(os.Interrupt)
		signal.SignalHandlerModule.RegisteHandler(os.Interrupt, &InterruptSignalHandler{}, nil)
		return nil
	})

	transact.RegisteHandler(common.TransType_StopServer, &transact.TransHanderWrapper{
		OnExecuteWrapper: transact.OnExecuteWrapper(func(tNode *transact.TransNode, ud interface{}) transact.TransExeResult {
			logger.Logger.Info("StopApi start TransType_StopServer OnExecuteWrapper ")
			if stopUD, ok := ud.(*StopAPIUserData); ok {
				tNode.TransEnv.SetField(STOPAPI_TRANSACTE_UD, ud)
				ids := srvlib.ServerSessionMgrSington.GetServerIds(common.GetSelfAreaId(), stopUD.srvtype)
				for _, id := range ids {
					tnp := &transact.TransNodeParam{
						Tt:     common.TransType_StopServer,
						Ot:     transact.TransOwnerType(stopUD.srvtype),
						Oid:    id,
						AreaID: common.GetSelfAreaId(),
						Tct:    transact.TransactCommitPolicy_TwoPhase,
					}
					tNode.StartChildTrans(tnp, nil, stopUD.timeout)
				}
				return transact.TransExeResult_Success
			}
			return transact.TransExeResult_Failed
		}),
		OnCommitWrapper: transact.OnCommitWrapper(func(tNode *transact.TransNode) transact.TransExeResult {
			logger.Logger.Info("StopApi start TransType_StopServer OnCommitWrapper")
			field := tNode.TransEnv.GetField(STOPAPI_TRANSACTE_UD)
			if field != nil {
				if ud, ok := field.(*StopAPIUserData); ok {
					ud.wait <- struct{}{}
				}
			}
			return transact.TransExeResult_Success
		}),
		OnRollBackWrapper: transact.OnRollBackWrapper(func(tNode *transact.TransNode) transact.TransExeResult {
			logger.Logger.Info("StopApi start TransType_StopServer OnRollBackWrapper")
			field := tNode.TransEnv.GetField(STOPAPI_TRANSACTE_UD)
			if field != nil {
				if ud, ok := field.(*StopAPIUserData); ok {
					ud.wait <- struct{}{}
				}
			}
			return transact.TransExeResult_Success
		}),
		OnChildRespWrapper: transact.OnChildRespWrapper(func(tNode *transact.TransNode, hChild transact.TransNodeID, retCode int, ud interface{}) transact.TransExeResult {
			logger.Logger.Infof("StopApi start TransType_StopServer OnChildRespWrapper ret:%v childid:%x", retCode, hChild)
			return transact.TransExeResult(retCode)
		}),
	})
}
