package redis_client

import (
	"code.gitea.io/gitea/modules/labelmsg"
	"fmt"
	"github.com/gomodule/redigo/redis"
	"math"
	"strconv"
	"time"
)

func Setex(key, value string, timeout time.Duration) (bool, error) {
	redisClient := labelmsg.Get()
	defer redisClient.Close()

	seconds := int(math.Floor(timeout.Seconds()))
	reply, err := redisClient.Do("SETEX", key, seconds, value)
	if err != nil {
		return false, err
	}
	if reply != "OK" {
		return false, nil
	}
	return true, nil

}

func Setnx(key, value string, timeout time.Duration) (bool, error) {
	redisClient := labelmsg.Get()
	defer redisClient.Close()

	seconds := int(math.Floor(timeout.Seconds()))
	reply, err := redisClient.Do("SET", key, value, "NX", "EX", seconds)
	if err != nil {
		return false, err
	}
	if reply != "OK" {
		return false, nil
	}
	return true, nil

}

func SETNX(conn redis.Conn, key, value string, seconds int) (bool, error) {
	reply, err := conn.Do("SET", key, value, "NX", "EX", seconds)
	return redis.Bool(reply, err)

}

func SET(conn redis.Conn, key, value string, seconds int) (bool, error) {
	reply, err := conn.Do("SETEX", key, seconds, value)
	return redis.Bool(reply, err)

}

func HSETNX(conn redis.Conn, key, subKey string, value interface{}) error {
	_, err := conn.Do("HSETNX", key, subKey, value)
	return err

}

func HGET(conn redis.Conn, key, subKey string) (interface{}, error) {
	return conn.Do("HGET", key, subKey)
}
func EXISTS(conn redis.Conn, key string) (bool, error) {

	reply, err := conn.Do("EXISTS", key)
	return redis.Bool(reply, err)

}

func HEXISTS(conn redis.Conn, key string, subKey string) (bool, error) {

	reply, err := conn.Do("HEXISTS", key, subKey)
	return redis.Bool(reply, err)

}

func EXPIRE(conn redis.Conn, key string, seconds int) error {
	_, err := conn.Do("EXPIRE", key, seconds)
	return err

}

func HINCRBY(conn redis.Conn, key, subKey string, value int) error {
	_, err := conn.Do("HINCRBY", key, subKey, value)
	return err
}
func GET(conn redis.Conn, key string) (interface{}, error) {
	return conn.Do("GET", key)
}

func Ttl(conn redis.Conn, key string) (int, error) {

	reply, err := conn.Do("TTL", key)
	if err != nil {
		return 0, err
	}
	n, _ := strconv.Atoi(fmt.Sprint(reply))
	return n, nil

}

func Get(key string) (string, error) {
	redisClient := labelmsg.Get()
	defer redisClient.Close()

	reply, err := redisClient.Do("GET", key)
	if err != nil {
		return "", err
	}
	if reply == nil {
		return "", err
	}
	s, _ := redis.String(reply, nil)
	return s, nil

}

func Del(key string) (int, error) {
	redisClient := labelmsg.Get()
	defer redisClient.Close()

	reply, err := redisClient.Do("DEL", key)
	if err != nil {
		return 0, err
	}
	if reply == nil {
		return 0, err
	}
	s, _ := redis.Int(reply, nil)
	return s, nil

}

func TTL(key string) (int, error) {
	redisClient := labelmsg.Get()
	defer redisClient.Close()

	reply, err := redisClient.Do("TTL", key)
	if err != nil {
		return 0, err
	}
	n, _ := strconv.Atoi(fmt.Sprint(reply))
	return n, nil

}

func IncrBy(key string, n int64) (int64, error) {
	redisClient := labelmsg.Get()
	defer redisClient.Close()

	reply, err := redisClient.Do("INCRBY", key, n)
	if err != nil {
		return 0, err
	}
	i, err := strconv.ParseInt(fmt.Sprint(reply), 10, 64)
	return i, nil

}

func Expire(key string, expireTime time.Duration) error {
	redisClient := labelmsg.Get()
	defer redisClient.Close()

	_, err := redisClient.Do("EXPIRE", key, int64(expireTime.Seconds()))
	if err != nil {
		return err
	}
	return nil

}

//GetInt64 get redis value by Get(key)
//and then parse the value to int64
//return {isExist(bool)} {value(int64)} {error(error)}
func GetInt64(key string) (bool, int64, error) {
	str, err := Get(key)
	if err != nil {
		return false, 0, err
	}
	if str == "" {
		return false, 0, nil
	}

	i, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		return false, 0, err
	}
	return true, i, nil

}

func ZAdd(key, value string, score float64) error {
	redisClient := labelmsg.Get()
	defer redisClient.Close()

	_, err := redisClient.Do("ZADD", key, score, value)
	if err != nil {
		return err
	}
	return nil
}

func ZRangeByScore(key string, min, max float64) ([]string, error) {
	redisClient := labelmsg.Get()
	defer redisClient.Close()

	reply, err := redisClient.Do("ZRANGEBYSCORE", key, min, max)
	if err != nil {
		return nil, err
	}
	if reply == nil {
		return nil, err
	}
	s, _ := redis.Strings(reply, nil)
	return s, nil
}

func ZRemRangeByScore(key string, min, max float64) error {
	redisClient := labelmsg.Get()
	defer redisClient.Close()

	_, err := redisClient.Do("ZREMRANGEBYSCORE", key, min, max)
	if err != nil {
		return err
	}
	return nil
}
