package com

import (
	"time"

	"mongo.games.com/goserver/core/basic"
	"mongo.games.com/goserver/core/logger"
	"mongo.games.com/goserver/core/task"
)

func NewListMgr[T any](cacheTime func() int64, loadFunc func(platform string, index int32) ([]T, error)) *ListMgr[T] {
	return &ListMgr[T]{
		platform:  make(map[string]map[int32]*DataItem[T]),
		LoadFunc:  loadFunc,
		CacheTime: cacheTime,
	}
}

type funcCall[T any] func([]T, error)

type DataItem[T any] struct {
	Ts   int64 // 更新时间
	List []T
	cb   []funcCall[T]
}

type ListMgr[T any] struct {
	platform map[string]map[int32]*DataItem[T]

	// 数据库查询方法
	// 参数 平台id,类型
	LoadFunc  func(string, int32) ([]T, error)
	CacheTime func() int64
}

// Get 从缓存中获取数据
func (r *ListMgr[T]) Get(platform string, index int32, f func([]T, error)) {
	tp := r.platform[platform]
	if tp == nil {
		r.platform[platform] = map[int32]*DataItem[T]{}
	}
	item := r.platform[platform][index]
	if item != nil {
		f(item.List, nil)
		return
	}
}

// Take 从缓存中获取数据，如果缓存中没有数据或缓存过期，则从数据库中获取数据
func (r *ListMgr[T]) Take(platform string, index int32, f func([]T, error)) {
	tp := r.platform[platform]
	if tp == nil {
		r.platform[platform] = map[int32]*DataItem[T]{}
	}
	item := r.platform[platform][index]
	if item != nil && time.Now().Unix()-item.Ts < r.CacheTime() {
		f(item.List, nil)
		return
	}

	if item == nil {
		item = &DataItem[T]{
			cb: []funcCall[T]{f},
		}
		r.platform[platform][index] = item
	} else {
		if len(item.cb) > 0 {
			item.cb = append(item.cb, f)
			return
		} else {
			item.cb = []funcCall[T]{f}
		}
	}

	var list []T
	var err error
	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		list, err = r.LoadFunc(platform, index)
		return nil
	}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
		r.platform[platform][index] = &DataItem[T]{
			List: list,
			Ts:   time.Now().Unix(),
		}
		for _, v := range item.cb {
			v(list, err)
		}
	})).Start()
}

// UpdateCache 更新缓存
func (r *ListMgr[T]) UpdateCache(platform string, index int32) {
	tp := r.platform[platform]
	if tp == nil {
		r.platform[platform] = map[int32]*DataItem[T]{}
	}
	item := r.platform[platform][index]
	if item == nil {
		item = &DataItem[T]{
			cb: []funcCall[T]{},
		}
		r.platform[platform][index] = item
	}

	var list []T
	var err error
	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		list, err = r.LoadFunc(platform, index)
		if err != nil {
			logger.Logger.Errorf("UpdateCache LoadFunc error:%v", err)
		}
		return nil
	}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
		if err == nil {
			r.platform[platform][index] = &DataItem[T]{
				List: list,
				Ts:   time.Now().Unix(),
			}
		}
	})).Start()
}
