package raftNode

import (
	"PPOSUtils/utils"
	"errors"
	"fmt"
	"runtime"
	"runtime/debug"
	"strings"
	"time"
)

func NewRaftNode(config *RaftConfig) *RaftNode {
	_raftNode := new(RaftNode)
	_raftNode.start(config)
	raftNode = _raftNode
	return raftNode
}

type RaftNode struct {
	raftHost            *RaftHost
	leaderEventHandlers []func(isLeader bool) error
	loadHandler         []func(tree, key string, value interface{}, expire int64)
	loadUUidHandler     []func(tree, key string, value interface{}, preDomain string)
	loadLockHandler     []func(tree, key string, value interface{}, preDomain string)
}

func (that *RaftNode) LeaderID() string {
	return that.raftHost.LeaderID()
}

func (that *RaftNode) IsLeader() bool {
	return that.raftHost.IsLeader()
}

func (that *RaftNode) SetCanWrite(b bool) {
	that.raftHost.SetCanWrite(b)
}

//
func (that *RaftNode) CanWrite() bool {
	return that.raftHost.CanWrite()
}

//ForceUUID ...
func (that *RaftNode) ForceUUID(name string, id, preDomain int64) (int64, error) {
	if !that.CanWrite() {
		return 0, errors.New("not leader")
	}
	//如果前置域大于0，并且尾数不等于0，则强制将尾数变成0
	if preDomain > 0 && (preDomain%10) > 0 {
		preDomain = preDomain - (preDomain % 10)
	}
	_uuid := id
	if preDomain > 0 {
		_uuid = preDomain + id
	}
	if _err := raftNode.SetUUid(name, id, utils.ToString(preDomain)); _err != nil {
		return 0, _err
	}
	uidCache.InitStart(name, id, preDomain)
	return _uuid, nil
}

//NewUUID ...
func (that *RaftNode) NewUUID(name string, id, preDomain int64, step ...int64) (int64, error) {
	if !that.CanWrite() {
		return 0, errors.New("not leader")
	}
	//如果前置域大于0，并且尾数不等于0，则强制将尾数变成0
	if preDomain > 0 && (preDomain%10) > 0 {
		preDomain = preDomain - (preDomain % 10)
	}
	log.Debug("[NewUUID] params:", name, id, preDomain, step)
	_id, _preDomain := uidCache.newID(name, id, preDomain, step...)
	_uuid := _id
	if _preDomain > 0 {
		_uuid = _preDomain + _id
	}
	log.Debug("[NewUUID] success, id:", _uuid)
	//
	that.Task(0, func() {
		_name := name
		_lastUid := _id
		_lastPreDomain := _preDomain
		//
		_uidData := uidAsyncSave.getUidUpdate(_name)
		if _uidData != nil && _uuid <= (_uidData.preDomain+_uidData.uid) {
			return
		}
		//
		if raftNode != nil {
			if _err := raftNode.SetUUid(_name, _lastUid, utils.ToString(_lastPreDomain)); _err != nil {
				//记录日志，并发出kill信号
			}
			uidAsyncSave.uidUpdateSign(uidData{
				name:      name,
				uid:       _lastUid,
				preDomain: _lastPreDomain,
			})
		}
	})
	return _uuid, nil
}

func (that *RaftNode) SessionLock(domain, sessionID string, maxActive, expire int64) (bool, error) {
	if !that.CanWrite() {
		return false, errors.New("not leader")
	}
	return sessionLock(domain, sessionID, maxActive, expire)
}

func (that *RaftNode) SessionUnLock(domain, sessionID string) error {
	if !that.CanWrite() {
		return errors.New("not leader")
	}
	return sessionUnLock(domain, sessionID)
}

func (that *RaftNode) Task(runTime int, action func()) {
	activeTasker.AddTask(runTime, action)
}

func (that *RaftNode) RegisterLeaderEventHandler(handler func(isLeader bool) error) {
	if that.leaderEventHandlers == nil {
		that.leaderEventHandlers = []func(isLeader bool) error{}
	}
	that.leaderEventHandlers = append(that.leaderEventHandlers, handler)
}

//RegisterUUidLoadHandler 注册"uuid"初始化载入句柄函数
func (that *RaftNode) RegisterUUidLoadHandler(loadHandler func(tree, key string, value interface{}, preDomain string)) {
	if that.loadUUidHandler == nil {
		that.loadUUidHandler = []func(tree, key string, value interface{}, preDomain string){}
	}
	that.loadUUidHandler = append(that.loadUUidHandler, loadHandler)
}

//RegisterLockLoadHandler 注册"锁"初始化载入句柄函数
func (that *RaftNode) RegisterLockLoadHandler(loadHandler func(tree, key string, value interface{}, preDomain string)) {
	if that.loadLockHandler == nil {
		that.loadLockHandler = []func(tree, key string, value interface{}, preDomain string){}
	}
	that.loadLockHandler = append(that.loadLockHandler, loadHandler)
}

//RegisterLoadHandler 注册"kv"模式的初始化载入句柄函数
func (that *RaftNode) RegisterLoadHandler(loadHandler func(tree, key string, value interface{}, expire int64)) {
	if that.loadHandler == nil {
		that.loadHandler = []func(tree, key string, value interface{}, expire int64){}
	}
	that.loadHandler = append(that.loadHandler, loadHandler)
}

func (that *RaftNode) ListenLeader() {
	// 监听leader变化
	go func() {
		_i := 0
		for _leader := range that.raftHost.LeaderCh() {
			func() {
				defer func() {
					if _err := recover(); _err != nil {
						//日志记录。。。
						switch _err.(type) {
						case runtime.Error: // 运行时错误
							log.Error("[LeaderCh] runtime error:", fmt.Sprint(_err))
						default: // 非运行时错误
							log.Error("[LeaderCh] error:", fmt.Sprint(_err))
						}
					}
				}()
				//flower要前置
				if !_leader {
					that.SetCanWrite(_leader)
					activeTasker.Clean()
				}
				if that.leaderEventHandlers != nil {
					for _, _handler := range that.leaderEventHandlers {
						//
						for {
							if _err := _handler(_leader); _err == nil {
								break
							}
							time.Sleep(100 * time.Millisecond)
						}
					}
				}
				//leader要后置
				if _leader {
					if _i == 0 {
						//服务首次启动
						time.Sleep(2000 * time.Millisecond)
					}
					//初始化
					that.LoadData()
					that.SetCanWrite(_leader)
				}
				_i++
			}()
		}
	}()
}

//initUid 初始化
func (that *RaftNode) start(config *RaftConfig) {
	that.raftHost = new(RaftHost)
	that.raftHost.init(config)
	//注册：数据初始化句柄函数
	that.RegisterUUidLoadHandler(func(tree, key string, value interface{}, preDomain string) {
		//fmt.Println("===== UUidLoad ====", key, value, preDomain)
		uidCache.InitStart(key, utils.ToInt64(value)+10, utils.ToInt64(preDomain))
	})
	//注册：分布式锁初始化句柄函数
	that.RegisterLockLoadHandler(func(tree, key string, value interface{}, preDomain string) {
		//fmt.Println("===== LockLoad ====", key, value, preDomain)
		lockInitStart(key, utils.ToInt64(value), preDomain)
	})
	//注册：leader事件
	that.RegisterLeaderEventHandler(func(isLeader bool) error {
		if isLeader {
			uidCache.Clear()
			uidAsyncSave.Clear()
			cleanActiveLock()
			_logSlice := []string{
				"*****************************************************",
				fmt.Sprintf("* [raft] Change to leader  ｜  %s ", utils.TimeStr("Y-m-d h:i:s")),
				"*****************************************************",
			}
			fmt.Println(strings.Join(_logSlice, "\r\n"))
			log.Infof("[raft] Change to leader  ｜  %s", utils.TimeStr("Y-m-d h:i:s"))
		} else {
			_logSlice := []string{
				"*****************************************************",
				fmt.Sprintf("* [raft] Change to follower  ｜  %s ", utils.TimeStr("Y-m-d h:i:s")),
				"*****************************************************",
			}
			fmt.Println(strings.Join(_logSlice, "\r\n"))
			log.Infof("[raft] Change to follower  ｜  %s", utils.TimeStr("Y-m-d h:i:s"))
		}
		return nil
	})
}

//LoadData 初始化，载入数据到"应用层"
func (that *RaftNode) LoadData() {
	defer func() {
		if _err := recover(); _err != nil {
			fmt.Printf("LoadData PANIC: %v, stack: %s", _err, debug.Stack())
		}
	}()
	_list, _ := that.raftHost.List(time.Duration(5) * time.Second)
	for _, _v := range _list {
		//fmt.Println("====== LoadData =====", reflect.TypeOf(_v))
		switch _v.GetType() {
		case DATATYPE_BASE:
			for _, _f := range that.loadHandler {
				_f(_v.GetTree(), _v.GetKey(), _v.GetData(), utils.ToInt64(_v.GetPreDomain()))
			}
		case DATATYPE_UUID:
			for _, _f := range that.loadUUidHandler {
				_f(_v.GetTree(), _v.GetKey(), _v.GetData(), _v.GetPreDomain())
			}
		case DATATYPE_LOCK:
			for _, _f := range that.loadLockHandler {
				_f(_v.GetTree(), _v.GetKey(), _v.GetData(), _v.GetPreDomain())
			}
		}
	}
}

func (that *RaftNode) SetLock(key string, value interface{}, preDomain string) error {
	if !that.CanWrite() {
		return errors.New("not leader")
	}
	_value := ""
	switch _t := value.(type) {
	case int, int8, int16, int32, int64, uint8, uint16, uint32, uint64:
		_value = utils.ToString(_t)
	case string:
		_value = _t
	}
	_data := FsmUUidData{
		FsmData: FsmData{
			Tr:  DATATYPE_LOCK,
			Ty:  DATATYPE_LOCK,
			Ke:  key,
			Val: _value,
		},
		PreDomain: preDomain,
	}
	if _err := NewRaftBatch(that.raftHost).Put(_data).Commit(); _err != nil {
		return _err
	}
	return nil
}

func (that *RaftNode) SetUUid(key string, value interface{}, preDomain string) error {
	if !that.CanWrite() {
		return errors.New("not leader")
	}
	_value := ""
	switch _t := value.(type) {
	case int, int8, int16, int32, int64, uint8, uint16, uint32, uint64:
		_value = utils.ToString(_t)
	case string:
		_value = _t
	}
	_data := FsmUUidData{
		FsmData: FsmData{
			Tr:  DATATYPE_UUID,
			Ty:  DATATYPE_UUID,
			Ke:  key,
			Val: _value,
		},
		PreDomain: preDomain,
	}
	if _err := NewRaftBatch(that.raftHost).Put(_data).Commit(); _err != nil {
		return _err
	}
	return nil
}
func (that *RaftNode) MSet(tree, key string, value interface{}, expire ...int64) error {
	if _err := NewRaftBatch(that.raftHost).MSet(tree, key, value, expire...).Commit(); _err != nil {
		return _err
	}
	return nil
}

func (that *RaftNode) Set(key string, value interface{}, expire ...int64) error {
	return that.MSet(DATATYPE_BASE, key, value, expire...)
}

func (that *RaftNode) MDel(tree, key string) error {
	if _err := NewRaftBatch(that.raftHost).MDel(tree, key).Commit(); _err != nil {
		return _err
	}
	return nil
}

func (that *RaftNode) Del(key string) error {
	return that.MDel(DATATYPE_BASE, key)
}

func (that *RaftNode) Get(key string) (interface{}, int64) {
	return that.MGet(DATATYPE_BASE, key)
}

func (that *RaftNode) MGet(tree, key string) (interface{}, int64) {
	_data, _err := that.raftHost.Find(tree, key, time.Duration(5)*time.Second)
	if _err != nil {
		return nil, 0
	}
	return _data.GetData(), utils.ToInt64(_data.GetPreDomain())
}

func (that *RaftNode) Batch() BatchInterface {
	return NewRaftBatch(that.raftHost)
}

func (that *RaftNode) Close() {
	that.raftHost.Close()
	that.raftHost = nil
}
