package redis

import (
	"encoding/json"
	"fmt"
	"time"

	"git.rosy.net.cn/baseapi/utils"
	"github.com/go-redis/redis"
)

type Cacher struct {
	client *redis.Client
}

func New(host string, port int, password string) *Cacher {
	if port == 0 {
		port = 6379
	}
	return &Cacher{
		client: redis.NewClient(&redis.Options{
			Addr:     fmt.Sprintf("%s:%d", host, port),
			Password: password,
		},
		),
	}
}

func (c *Cacher) FlushKeys(prefix string) (err error) {
	if prefix == "" {
		return c.client.FlushAll().Err()
	}
	keys, err := c.Keys(prefix)
	if err == nil {
		for _, key := range keys {
			if err = c.Del(key); err != nil {
				break
			}
		}
	}
	return err
}

func (c *Cacher) Set(key string, value interface{}, expiration time.Duration) error {
	strValue := string(utils.MustMarshal(value))
	return c.client.Set(key, strValue, expiration).Err()
}

func (c *Cacher) Del(key string) error {
	return c.client.Del(key).Err()
}

func (c *Cacher) Get(key string) interface{} {
	result, err := c.client.Get(key).Result()
	if err == nil {
		var retVal interface{}
		if err = utils.UnmarshalUseNumber([]byte(result), &retVal); err == nil {
			return retVal
		}
	}
	return nil
}

func (c *Cacher) GetString(key string) string {
	result, err := c.client.Get(key).Result()
	if err == nil {
		//return result
		var retVal interface{}
		if err = json.Unmarshal([]byte(result), &retVal); err == nil {
			return retVal.(string)
		}
	}
	return ""
}

func (c *Cacher) GetAs(key string, ptr interface{}) error {
	result, err := c.client.Get(key).Result()
	if err == nil {
		if err = utils.UnmarshalUseNumber([]byte(result), ptr); err == nil {
			return nil
		}
	}
	return err
}

func (c *Cacher) Keys(prefix string) ([]string, error) {
	return c.client.Keys(prefix + "*").Result()
}

func (c *Cacher) RPush(key string, value interface{}) error {
	return c.client.RPush(key, value).Err()
}

func (c *Cacher) FlushDB() error {
	return c.client.FlushDB().Err()
}

func (c *Cacher) Expire(key string, expiration time.Duration) error {
	return c.client.Expire(key, expiration).Err()
}

func (c *Cacher) ExpireResult(key string, expiration time.Duration) (bool, error) {
	ok, err := c.client.Expire(key, expiration).Result()
	if err != nil {
		return false, err
	}
	return ok, nil
}

func (c *Cacher) Exists(keys ...string) (int64, error) {
	ret := c.client.Exists(keys...)
	return ret.Val(), ret.Err()
}

func (c *Cacher) Incr(key string) error {
	return c.client.Incr(key).Err()
}

func (c *Cacher) LRange(key string) (retVal []string) {
	if c.client.LLen(key).Val() > 0 {
		retVal = c.client.LRange(key, 0, -1).Val()
	}
	return retVal
}

func (c *Cacher) LSet(key string, index int, value interface{}) error {
	return c.client.LSet(key, int64(index), value).Err()
}

func (c *Cacher) LRem(key string, count int, value interface{}) error {
	return c.client.LRem(key, int64(count), value).Err()
}
