// redis操作接口
// 秒寻科技
// 2024-01-08
// 周涛
package redisapi

import (
	"context"
	"encoding/json"
	"errors"
	"ipsomc/util"
	"reflect"
	"time"

	"github.com/go-redis/redis/v8"
)

type RedisApi struct {
}

// redis全局操作对象
var (
	ctx   context.Context
	rdsDb *redis.Client
)

// 打开redis
func OpenRds(c context.Context, item string) error {
	ctx = c //保存上下文
	viper := util.GetViper()
	viper.SetDefault(item, map[string]interface{}{
		"address":     "127.0.0.1:6379",
		"password":    "",
		"database":    0,
		"dialTimeout": 1,
		"poolSize":    20,
	})

	rdsDb = redis.NewClient(&redis.Options{
		Addr:        viper.GetString(item + ".address"),
		DB:          viper.GetInt(item + ".database"),
		Password:    viper.GetString(item + ".password"),
		DialTimeout: viper.GetDuration(item + ".dialTimeout"),
		PoolSize:    viper.GetInt(item + ".poolSize"),
	})

	if err := rdsDb.Ping(ctx).Err(); err != nil {
		panic("连接redis失败")
	}

	return nil
}

// 关闭redis
func CloseRds() error {
	if err := rdsDb.Close(); err != nil {
		return err
	}

	return nil
}

// 设置模型数据
// key:保存的键值，全局唯一
// dwExpire:过期时间，单位秒
func (obj *RedisApi) SetModelData(key string, dataModel interface{}, wExpire uint16) error {
	val := reflect.ValueOf(dataModel)
	if val.Kind() != reflect.Ptr {
		return errors.New("参数检查错误，应为指针类型")
	}
	val = val.Elem()
	if val.Kind() != reflect.Struct {
		return errors.New("参数检查错误，应为结构体指针类型")
	}

	//模型转map
	dataList, _ := json.Marshal(dataModel)

	//保存数据
	duration := time.Duration(wExpire)
	if err := rdsDb.Set(ctx, key, dataList, duration*time.Minute).Err(); err != nil {
		return err
	}

	return nil
}

// 获得模型数据
func (obj *RedisApi) GetModelData(key string, dataModel interface{}) error {
	val := reflect.ValueOf(dataModel)
	if val.Kind() != reflect.Ptr {
		return errors.New("参数检查错误，应为指针类型")
	}
	val = val.Elem()
	if val.Kind() != reflect.Struct {
		return errors.New("参数检查错误，应为结构体指针类型")
	}

	byteList, err := rdsDb.Get(ctx, key).Result()
	if err != nil {
		return errors.New(err.Error())
	}

	if err := json.Unmarshal([]byte(byteList), dataModel); err != nil {
		return errors.New(err.Error())
	}

	return nil
}

// 设置过期时间
func (obj *RedisApi) SetExpireTime(key string, byExpire uint8) {
	duration := time.Duration(byExpire)
	rdsDb.Expire(ctx, key, duration*time.Minute)
}
