package timercache

import (
	"leafstalk/otherutils/snowflake"
	"log"
	"sync"
	"time"
)

type CacheKeys struct {
	locker      sync.Mutex
	tc          *timerCache
	queryMap    map[int64]*TimerEntry
	interval    time.Duration
	msgSequence *snowflake.Node
}

func NewCacheKeys(d time.Duration) *CacheKeys {

	cache := newCache()
	cw := &CacheKeys{
		tc:       cache,
		queryMap: make(map[int64]*TimerEntry),
		interval: d,
	}
	cache.SetPrecallBack(cw.preCallBack)

	var err error
	msgSequence, err := snowflake.NewSecondNode(0, 0)
	if err != nil {
		log.Panic(err)
	}
	cw.msgSequence = msgSequence

	//runtime.SetFinalizer(cw, Stop)
	return cw
}

func StopCacheKeys(c *CacheKeys) {
	c.tc.stop <- struct{}{}
}

func (h *CacheKeys) preCallBack(e *TimerEntry) bool {

	k, ok := e.GetKey().(int64)
	if ok {
		h.locker.Lock()
		defer h.locker.Unlock()

		if _, ok := h.queryMap[k]; ok {
			delete(h.queryMap, k)
			return true
		}

	} else {
		log.Panicf("type convert fail %v", e.GetKey())
	}
	return false
}

func (h *CacheKeys) generateMsgId() int64 {
	return h.msgSequence.Generate().Int64()
}

func (h *CacheKeys) Add(val interface{}, callBack func(e *TimerEntry), msgId int64) int64 {

	h.locker.Lock()
	defer h.locker.Unlock()

	if msgId == 0 {
		msgId = h.generateMsgId()
	}
	// k := h.generateMsgId()
	te := h.tc.Add(h.interval, msgId, val, callBack)
	h.queryMap[msgId] = te

	return msgId
}

func (h *CacheKeys) Remove(key int64) interface{} {
	h.locker.Lock()
	defer h.locker.Unlock()

	if v, ok := h.queryMap[key]; ok {
		val := v.GetVal()
		delete(h.queryMap, key)
		h.tc.Remove(v)
		return val
	}
	return nil
}

// func (h *CacheKeys) RemoveKey(key int64) {
// 	delete(h.queryMap, key)
// }

type CustomCacheKeys struct {
	locker   sync.Mutex
	tc       *timerCache
	queryMap map[string]*TimerEntry
	Interval time.Duration
}

func NewCustomKeys(d time.Duration) *CustomCacheKeys {

	cache := newCache()
	cw := &CustomCacheKeys{
		tc:       cache,
		queryMap: make(map[string]*TimerEntry),
		Interval: d,
	}
	cache.SetPrecallBack(cw.preCallBack)

	//runtime.SetFinalizer(cw, Stop)
	return cw
}

func StopCustomCacheKeys(c *CustomCacheKeys) {
	c.tc.stop <- struct{}{}
}

func (h *CustomCacheKeys) preCallBack(e *TimerEntry) bool {

	k, ok := e.GetKey().(string)
	if ok {
		h.locker.Lock()
		defer h.locker.Unlock()

		if _, ok := h.queryMap[k]; ok {
			delete(h.queryMap, k)
			return true
		}
	} else {
		log.Panicf("type convert fail %v", e.GetKey())
	}
	return false
}

// Add时，如果不在queryMap中，必定不在tc中，可能正在预回调后，或完全不牵涉
// 如果在queryMap中，v处在等待到预回调前的这个阶段中
func (h *CustomCacheKeys) Add(key string, val interface{}, callBack func(e *TimerEntry)) {

	h.locker.Lock()
	defer h.locker.Unlock()

	if v, ok := h.queryMap[key]; ok {
		v.SetVal(val, callBack)
		return
	}
	te := h.tc.Add(h.Interval, key, val, callBack)
	h.queryMap[key] = te
}

// queryMap中存在时，v处在等待到预执行前的这个阶段中
func (h *CustomCacheKeys) Remove(key string) {

	h.locker.Lock()
	defer h.locker.Unlock()

	if v, ok := h.queryMap[key]; ok {
		delete(h.queryMap, key)
		h.tc.Remove(v)
	}
}

// func (h *CustomCacheKeys) RemoveKey(key string) {
// 	delete(h.queryMap, key)
// }
