package cache

import (
	"context"
	"fmt"
	"time"

	cache "github.com/patrickmn/go-cache"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/log"
	"go.uber.org/zap"
	"golang.org/x/sync/singleflight"
)

var (
	defaultExpiration = 5 * time.Minute
	ClusterCache      = cache.New(5*time.Minute, 10*time.Minute)

	// group 用于合并并发请求
	g singleflight.Group
)

func GetWithCache[T any](ctx context.Context, myCache *cache.Cache, key string, fetchFunc func() (T, error)) (T, error) {

	// 1. 查缓存
	if val, found := myCache.Get(key); found {
		log.Info(ctx, fmt.Sprintf("get oject from cache , key:%s", key), zap.Any("cache value", val))
		return val.(T), nil
	}

	// 2. 使用 SingleFlight 合并并发的 DB 请求
	// Do 方法确保同一个 key 在同一时间只有一个 fetchFunc 在执行
	val, err, _ := g.Do(key, func() (interface{}, error) {
		// 双重检查：万一在排队等待时，前一个请求已经把数据放入缓存了
		if v, found := myCache.Get(key); found {
			return v, nil
		}
		log.Info(ctx, fmt.Sprintf("not found object in cache , key:%s", key))
		// 执行查询
		res, err := fetchFunc()
		if err != nil {
			return res, err
		}

		// 回填缓存
		myCache.Set(key, res, defaultExpiration)
		return res, nil
	})

	if err != nil {
		var zero T

		return zero, err
	}

	return val.(T), nil
}
