package raftNode

import (
	"PPOSUtils/utils"
	"encoding/json"
	"errors"
	"strings"
)

const (
	DATATYPE_UUID = "uuid"
	DATATYPE_LOCK = "lock"
	DATATYPE_BASE = "base"
)

type FsmDataInterface interface {
	GetTree() string
	GetType() string
	GetKey() string
	GetData() interface{}
	GetPreDomain() string
	CenerateFsmData() string
}

type FsmEntryInterface interface {
	GetKey() string
	GetVal() string
	GetEntryKey() (FsmEntryKeyInterface, error)
	GetEntry() (FsmDataInterface, error)
	CenerateEntry() []byte
}

type FsmEntryKeyInterface interface {
	GetTree() string
	GetKey() string
	CenerateEntryKey() string
}

/////////////////////////////////////////////////////////////

//FsmData ...
type FsmData struct {
	Tr  string      `json:"tr"`
	Ke  string      `json:"ke"`
	Ty  string      `json:"ty"`
	Val interface{} `json:"val"`
}

func (that FsmData) GetType() string {
	return that.Ty
}

func (that FsmData) GetTree() string {
	return that.Tr
}

func (that FsmData) GetKey() string {
	return that.Ke
}

func (that FsmData) GetData() interface{} {
	return that.Val
}

func (that FsmData) CenerateFsmData() string {
	_val, _ := json.Marshal(that)
	return string(_val)
}

/////////////////////////////////////////////////////////////

type FsmUUidData struct {
	FsmData
	PreDomain string `json:"pre_domain"`
}

func (that FsmUUidData) GetPreDomain() string {
	return that.PreDomain
}

/////////////////////////////////////////////////////////////

type FsmLockData struct {
	FsmData
	PreDomain string `json:"pre_domain"` //共享域
}

func (that FsmLockData) GetPreDomain() string {
	return that.PreDomain
}

/////////////////////////////////////////////////////////////

type FsmKvData struct {
	FsmData
	PreDomain string `json:"pre_domain"` //过期时间
}

func (that FsmKvData) GetPreDomain() string {
	return that.PreDomain
}

/////////////////////////////////////////////////////////////

type FsmEntryKey struct {
	Tr string `json:"tr"`
	Ke string `json:"ke"`
}

func (that FsmEntryKey) GetTree() string {
	return that.Tr
}

func (that FsmEntryKey) GetKey() string {
	return that.Ke
}

func (that FsmEntryKey) CenerateEntryKey() string {
	return that.Tr + "|" + that.Ke
}

/////////////////////////////////////////////////////////////

type FsmEntry struct {
	Ke  string `json:"ke"`
	Val string `json:"val"`
}

func (that FsmEntry) GetKey() string {
	return that.Ke
}

func (that FsmEntry) GetVal() string {
	return that.Val
}

func (that FsmEntry) GetEntryKey() (FsmEntryKeyInterface, error) {
	return parseEntryKey(that.Ke)
}

func (that FsmEntry) GetEntry() (FsmDataInterface, error) {
	return parseFsmData([]byte(that.Val))
}

func (that FsmEntry) CenerateEntry() []byte {
	_val, _ := json.Marshal(that)
	return _val
}

/////////////////////////////////////////////////////////////

func newEntryKey(tree, key string) FsmEntryKey {
	_key := FsmEntryKey{
		tree,
		key,
	}
	return _key
}

func newEntry(data FsmDataInterface) FsmEntryInterface {
	_val, _ := json.Marshal(data)
	//为空则是删除
	if data.GetData() == nil {
		_val = []byte{}
	}
	return FsmEntry{
		Ke:  newEntryKey(data.GetTree(), data.GetKey()).CenerateEntryKey(),
		Val: string(_val),
	}
}

func parseEntryKey(key string) (FsmEntryKeyInterface, error) {
	_slice := strings.Split(key, "|")
	if len(_slice) < 2 {
		return nil, errors.New("key parse error")
	}
	return FsmEntryKey{
		_slice[0],
		strings.Join(_slice[1:], "|"),
	}, nil
}

func parseEntry(data []byte) (FsmEntryInterface, error) {
	_fsmEntry := &FsmEntry{}
	if _err := json.Unmarshal(data, &_fsmEntry); _err != nil {
		return nil, _err
	}
	return FsmEntry{
		_fsmEntry.Ke,
		_fsmEntry.Val,
	}, nil
}

func parseFsmData(data []byte) (FsmDataInterface, error) {
	//_fsmEntry := &FsmEntry{}
	//if _err := json.Unmarshal(data, &_fsmEntry); _err != nil {
	//	return nil, _err
	//}
	_mp := map[string]interface{}{}
	if _err := json.Unmarshal(data, &_mp); _err != nil {
		return nil, _err
	}
	return parseData(_mp), nil
}

func parseData(v interface{}) FsmDataInterface {
	switch _t := v.(type) {
	case FsmLockData:
		return _t
	case FsmUUidData:
		return _t
	case FsmKvData:
		return _t
	case map[string]interface{}:
		_type := utils.ToString(_t["ty"])
		//fmt.Println(_type, "====== parseData ======", _t)
		switch _type {
		case DATATYPE_LOCK:
			_data := FsmLockData{
				FsmData: FsmData{
					Tr:  utils.ToString(_t["tr"], true),
					Ty:  _type,
					Ke:  utils.ToString(_t["ke"], true),
					Val: _t["val"],
				},
				PreDomain: utils.ToString(_t["pre_domain"], true),
			}
			return _data
		case DATATYPE_UUID:
			_data := FsmUUidData{
				FsmData: FsmData{
					Tr:  utils.ToString(_t["tr"], true),
					Ty:  _type,
					Ke:  utils.ToString(_t["ke"], true),
					Val: _t["val"],
				},
				PreDomain: utils.ToString(_t["pre_domain"], true),
			}
			return _data
		case DATATYPE_BASE:
			_data := FsmKvData{
				FsmData: FsmData{
					Tr:  utils.ToString(_t["tr"], true),
					Ty:  _type,
					Ke:  utils.ToString(_t["ke"], true),
					Val: _t["val"],
				},
				PreDomain: utils.ToString(_t["pre_domain"], true),
			}
			return _data
		}
	}
	return nil
}
