package common

import (
	log "app.yhyue.com/moapp/jylog"
	"encoding/json"
	"github.com/go-redis/redis"
	"time"
)

type Redis struct {
	Addr        string
	MaxConn     int
	Db          int
	IdleTimeOut int
	Client      *redis.Client
}

type RedisConf struct {
	Addr     string `json:"address"`
	PoolSize int    `json:"poolSize"`
	DB       int    `json:"db"`
}

func InitRedis(conf RedisConf) *Redis {
	r := &Redis{Addr: conf.Addr, MaxConn: conf.PoolSize, Db: conf.DB}
	r.Init()
	return r
}

func (r *Redis) Init() {
	opt := &redis.Options{
		Addr:               r.Addr,
		DB:                 r.Db,
		DialTimeout:        10 * time.Second,
		ReadTimeout:        300 * time.Second,
		WriteTimeout:       30 * time.Second,
		PoolSize:           r.MaxConn,
		PoolTimeout:        30 * time.Second,
		IdleTimeout:        time.Minute,
		IdleCheckFrequency: 5 * time.Second,
	}
	r.Client = redis.NewClient(opt)
}

func (r *Redis) Set(k string, v interface{}, timeout int64) bool {
	bt, _ := json.Marshal(v)
	cmd := r.Client.Set(k, bt, time.Duration(timeout)*time.Second)
	b, err := cmd.Result()
	if err != nil {
		log.Errorf("redis Set err %s", err.Error())
	}
	return "OK" == b
}

func (r *Redis) Get(k string) interface{} {
	cmd := r.Client.Get(k)
	bt, _ := cmd.Bytes()
	if bt != nil && len(bt) > 0 {
		var res interface{}
		if err := json.Unmarshal(bt, &res); err != nil {
			log.Errorf("redis Get Unmarshal err %v", err)
		}
		return res
	}
	return nil
}

func (r *Redis) GetBytes(k string) []byte {
	cmd := r.Client.Get(k)
	bt, err := cmd.Bytes()
	if err != nil {
		if err.Error() != "redis: nil" {
			log.Errorf("redis GetBytes err %s", err.Error())
		}
		return nil
	}
	return bt
}

func (r *Redis) MGet(k ...string) []interface{} {
	cmd := r.Client.MGet(k...)
	arr, err := cmd.Result()
	if err != nil {
		log.Errorf("redis MGet err %s", err.Error())
	}
	return arr
}

func (r *Redis) Incr(k string) int64 {
	cmd := r.Client.Incr(k)
	res, err := cmd.Result()
	if err != nil {
		log.Errorf("redis Incr err %s", err.Error())
	}
	return res
}

func (r *Redis) Del(k string) bool {
	_, err := r.Client.Del(k).Result()
	if err != nil {
		log.Errorf("redis Del err %s", err.Error())
		return false
	}
	return true
}

func (r *Redis) Exists(k string) bool {
	res, err := r.Client.Exists(k).Result()
	if err != nil {
		log.Errorf("redis Exists err %s", err.Error())
	}
	return res == 1
}

func (r *Redis) IncrTimeout(k string, duration time.Duration) int64 {
	if r.Client.TTL(k).Val().Nanoseconds() < 0 {
		r.Client.Set(k, 1, duration)
		return 1
	} else {
		return r.Incr(k)
	}
}

func (r *Redis) GetTTL(key string) int64 {
	cmd := r.Client.TTL(key)
	t, err := cmd.Result()
	if err != nil {
		log.Errorf("redis GetTTL err %s", err.Error())
	}
	if t.Nanoseconds() < 0 {
		return -1
	}
	return time.Unix(time.Now().Unix(), t.Nanoseconds()).Unix()
}
