package game

import (
	"context"
	"database/sql"
	"fmt"
	"server/GoUtil"
	"server/db"
	"server/game/mod/msg"
	"server/pkg/github.com/name5566/leaf/log"
	"server/pkg/github.com/name5566/leaf/timer"
	"sync"
	"time"
)

const (
	FRIEND_MGR_KEY    = "FRIEND_MGR"
	RANK_MGR_KEY      = "RANK_MGR"
	MAIL_MGR_KEY      = "MAIL_MGR"
	VAR_MGR_KEY       = "VAR_MGR"
	CHAMPSHIP_MGR_KEY = "CHAMPSHIP_MGR"
	PER_SAVE_TIME     = 60
)

type ServerMod struct {
	mDispatr *timer.Dispatcher
	lock     sync.Mutex
	msgChan  chan *msg.Msg
	key      string
	handler  map[int]interface{}
	timeout  time.Duration
	update   bool
	data     interface{}
}

// 初始化
func (s *ServerMod) init() {
	s.msgChan = make(chan *msg.Msg, 10)
	s.mDispatr = timer.NewDispatcher(10)
	s.timeout = time.Duration(time.Second * 10)
	s.handler = make(map[int]interface{})
	s.update = false
	s.LoadData()
	s.mDispatr.AfterFunc(time.Duration(PER_SAVE_TIME)*time.Second, func() {
		go s.SaveData()
	})
	go func() {
		defer func() {
			if r := recover(); r != nil {
				log.Debug("%s panic: %s", s.key, r)
				s.lock.Unlock()
			}
		}()

		for {
			select {
			case msg := <-s.msgChan:
				s.lock.Lock()
				s.Handle(msg)
				s.lock.Unlock()
			case Cb := <-s.mDispatr.ChanTimer:
				s.lock.Lock()
				Cb.Cb()
				s.lock.Unlock()
			}
		}
	}()

}

// 处理消息
func (s *ServerMod) Handle(m *msg.Msg) (interface{}, error) {
	if fun, ok := s.handler[m.Type]; ok {
		return fun.(func(*msg.Msg) (interface{}, error))(m)
	}
	log.Debug("server mod key:%s handle not exist handle type:%d", s.key, m.Type)
	return nil, fmt.Errorf("server mod handler err")
}

// 注册处理器
func (s *ServerMod) RegisterHandler(HandlerType int, fun interface{}) {
	switch fun.(type) {
	case func(*msg.Msg) (interface{}, error):
	default:
		log.Debug("RegisterHandler fun type err, key:%s, handler type :%d", s.key, HandlerType)
	}
	s.handler[HandlerType] = fun
}

// 发送消息队列
func (s *ServerMod) Send(msg *msg.Msg) {
	s.msgChan <- msg
}

// 同步请求
func (s *ServerMod) Call(m *msg.Msg) (interface{}, error) {
	responseChan := make(chan interface{})
	errorChan := make(chan error)

	go func() {
		defer func() {
			if r := recover(); r != nil {
				errorChan <- fmt.Errorf("panic: %v", r)
			}
		}()
		s.lock.Lock()
		defer s.lock.Unlock()
		result, err := s.Handle(m)
		if err != nil {
			errorChan <- err
			return
		}
		responseChan <- result
	}()

	select {
	case res := <-responseChan:
		return res, nil
	case err := <-errorChan:
		log.Debug("handle call err. %v", err)
		return nil, err
	case <-time.After(s.timeout):
		log.Debug("handle call timeout")
		return nil, fmt.Errorf("timeout after %v", s.timeout)
	}
}

// mysql 保存消息
func (s *ServerMod) SaveData() {
	s.mDispatr.AfterFunc(time.Duration(PER_SAVE_TIME+GoUtil.RandNum(5, 10))*time.Second, func() {
		go s.SaveData()
	})
	DbData := db.SqlServerModStruct{}
	DbData.Key = s.key
	DbData.UpdataTime = GoUtil.Now()
	var err error
	DbData.ModData, err = GoUtil.GobMarshal(s.data)
	if err != nil {
		log.Debug("SaveData Marshal failed,Mod Key: %s err:%v", s.key, err)
	}
	// log.Debug("SaveData Marshal success,Mod Key: %s", s.key)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	txOptions := &sql.TxOptions{}
	tx, err := db.SqlDb.BeginTx(ctx, txOptions)
	if err != nil {
		log.Debug("SaveData sql begin tx failed,Mod Key: %s err:%v", s.key, err)
		return
	}
	err = db.SaveServerData(&DbData)
	if err != nil {
		tx.Rollback()
		log.Debug("SaveData sql exec ,Mod Key: %s err:%v", s.key, err)
		return
	}
	tx.Commit()
}

func (s *ServerMod) LoadData() {
	DbData := db.SqlServerModStruct{}
	err := db.GetServerData(&DbData, s.key)
	if err != nil {
		DbData.Key = s.key
		DbData.UpdataTime = GoUtil.Now()
		err = db.InsertServerData(&DbData)
		if err != nil {
			log.Debug("LoadData sql exec ,Mod Key: %s err:%v", s.key, err)
		}
		return
	}
	if len(DbData.ModData) == 0 {
		return
	}
	err = GoUtil.GobUnmarshal(DbData.ModData, s.data)
	if err != nil {
		log.Debug("LoadData Unmarshal failed,Mod Key: %s err:%v", s.key, err)
		return
	}
}
