package redis

import (
	"fmt"
	"github.com/beego/beego/v2/core/logs"
	beego "github.com/beego/beego/v2/server/web"
	"github.com/google/uuid"
	"gopkg.in/redis.v5"
	"strconv"
	"strings"
	"time"
)

var redisCache *redis.Client

func init() {
	//return
	host, _ := beego.AppConfig.String("tokenhost")
	db, _ := beego.AppConfig.Int("tokendb")
	pass, _ := beego.AppConfig.String("tokenpass")
	redisCache = createClient(host, pass, db)
}

func createClient(redisHost string, password string, dataBase int) *redis.Client {
	client := redis.NewClient(&redis.Options{
		Addr:     redisHost,
		Password: password,
		DB:       dataBase,
	})

	_, err := client.Ping().Result()
	if err != nil {
		logs.Error("连接失败,", err)
		panic(err.Error())
	}

	return client
}

func tryAcquire(rs *redis.Client, lockKey string, lockTimeout time.Duration) (acquired bool, release func(), _ error) {
	timeout := time.Now().Add(lockTimeout).UnixNano()
	lockToken := fmt.Sprintf("%d,%s", timeout, uuid.New().String())

	release = func() {
		// Best effort to check we're releasing the lock we think we have. Note that it
		// is still technically possible the lock token has changed between the GET and
		// DEL since these are two separate operations, i.e. when the current lock happen
		// to be expired at this very moment.
		get, _ := rs.Get(lockKey).Result()
		if get == lockToken {
			_ = rs.Del(lockKey)
		}
	}
	set, err := rs.SetNX(lockKey, lockToken, lockTimeout).Result()
	if err != nil {
		return false, nil, err
	} else if set {
		return true, release, nil
	}

	// We didn't get the lock, but we can check if the lock is expired.
	currentLockToken, err := rs.Get(lockKey).Result()
	if err == redis.Nil {
		// Someone else got the lock and released it already.
		return false, nil, nil
	} else if err != nil {
		return false, nil, err
	}

	currentTimeout, _ := strconv.ParseInt(strings.SplitN(currentLockToken, ",", 2)[0], 10, 64)
	if currentTimeout > time.Now().UnixNano() {
		// The lock is still valid.
		return false, nil, nil
	}

	// The lock has expired, try to acquire it.
	get, err := rs.GetSet(lockKey, lockToken).Result()
	if err != nil {
		return false, nil, err
	} else if get != currentLockToken {
		// Someone else got the lock
		return false, nil, nil
	}

	// We got the lock.
	return true, release, nil
}

func SetHeat(key string, value interface{}, time time.Duration) {

}

func SetKeyAndData(key string, value interface{}, time time.Duration) error {
	err := redisCache.Set(key, value, time).Err()
	if err != nil {
		logs.Error("set key:", key, ",value:", value, err)
		return err
	}
	return nil
}

func GetDataToString(key string) (string, error) {
	v, err := redisCache.Get(key).Result()
	if err != nil {
		return "", err
	}
	return v, nil
}

func GetDataToBytes(key string) ([]byte, error) {
	v, err := redisCache.Get(key).Bytes()
	if err != nil {
		return nil, err
	}
	return v, nil
}

func DeleteKey(key string) error {
	err := redisCache.Del(key).Err()
	return err
}
