/*
 * @Descripttion:
 * @version:
 * @Author: Neo,Huang
 * @Date: 2020-10-16 14:29:56
 * @LastEditors: Neo,Huang
 * @LastEditTime: 2021-12-15 01:45:00
 */
package utils

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

	"github.com/garyburd/redigo/redis"
	redigo "github.com/gomodule/redigo/redis"
)

type Redis struct {
	pool *redigo.Pool
}

// 连接池
var mapRedisPool = make(map[string](map[int]*Redis))
var mapAccountRedisPool = make(map[string]*Redis)

// 实例数量
var mapRedisCount = make(map[string]int)

// InitRedis 初始化redis
func InitRedis() bool {
	count := StringToInt(GetKeyConf("redis", "count"))

	mapRedisCount[project] = count
	return true
}

// 获取玩家连接池
func GetPlayerRedisPool(uid int) *redigo.Pool {
	project := GetProject()
	index := uid % mapRedisCount[project]
	if mapRedisPool[project] == nil {
		mapRedisPool[project] = make(map[int]*Redis)
	}
	redisConn := mapRedisPool[project][index]

	if redisConn == nil {
		configFile := GetConfigFile()
		redisAddr := GetConf(fmt.Sprintf("redis::host_%d", index), configFile) + ":" + GetConf(fmt.Sprintf("redis::port_%d", index), configFile)
		redisAuth := GetConf(fmt.Sprintf("redis::auth_%d", index), configFile)

		log.Println(fmt.Sprintf("GetPlayerRedisPool project[%s] connString[%s]", project, redisAddr))
		redisConn = new(Redis)

		redisConn.pool = &redigo.Pool{
			MaxIdle:     10,
			IdleTimeout: 300 * time.Second,
			MaxActive:   100,
			Dial: func() (redigo.Conn, error) {
				c, err := redigo.Dial("tcp", redisAddr)
				if err != nil {
					return nil, err
				}
				if redisAuth != "" {
					_, err := c.Do("AUTH", redisAuth)
					if err != nil {
						c.Close()
						return nil, err
					}
				}
				return c, err
			},
			TestOnBorrow: func(c redigo.Conn, t time.Time) error {
				_, err := c.Do("PING")
				return err
			},
		}
		mapRedisPool[project][index] = redisConn
	}
	return redisConn.pool
}

// 获取account redis连接池
func GetAccountRedisPool() *redigo.Pool {
	project := GetProject()
	redisConn := mapAccountRedisPool[project]

	if redisConn == nil {
		configFile := GetConfigFile()
		redisAddr := GetConf("redis::host_account", configFile) + ":" + GetConf("redis::port_account", configFile)
		redisAuth := GetConf("redis::auth_account", configFile)

		log.Println(fmt.Sprintf("GetAccountRedisPool project[%s] connString[%s]", project, redisAddr))
		redisConn = new(Redis)

		redisConn.pool = &redigo.Pool{
			MaxIdle:     10,
			IdleTimeout: 300 * time.Second,
			MaxActive:   100,
			Dial: func() (redigo.Conn, error) {
				c, err := redigo.Dial("tcp", redisAddr)
				if err != nil {
					return nil, err
				}
				if redisAuth != "" {
					_, err := c.Do("AUTH", redisAuth)
					if err != nil {
						c.Close()
						return nil, err
					}
				}
				return c, err
			},
			TestOnBorrow: func(c redigo.Conn, t time.Time) error {
				_, err := c.Do("PING")
				return err
			},
		}
		mapAccountRedisPool[project] = redisConn
	}
	return redisConn.pool
}

// Zadd
func Zadd(key string, score int, value string) {
	pool := GetPlayerRedisPool(0)
	if pool == nil {
		fmt.Println("get redis pool fail")
		return
	}
	redisConn := pool.Get()
	if redisConn == nil {
		fmt.Println("get redis conn fail")
		return
	}
	defer redisConn.Close()

	_, err := redisConn.Do("zadd", key, score, value)
	if err != nil {
		fmt.Println("Zadd err:", err)
	}
}

// Hincrby
func Hincrby(key, field string, value int) (err error) {
	pool := GetPlayerRedisPool(0)
	if pool == nil {
		fmt.Println("get redis pool fail")
		return ErrGetRedisFail
	}
	redisConn := pool.Get()
	if redisConn == nil {
		fmt.Println("get redis conn fail")
		return ErrGetRedisConnectFail
	}
	defer redisConn.Close()
	_, err = redisConn.Do("hincrby", key, field, value)
	if err != nil {
		fmt.Printf("redis hincrby err: %v", err)
		return err
	}
	return
}

// Sadd
func Sadd(key, value string) (err error) {
	pool := GetPlayerRedisPool(0)
	if pool == nil {
		fmt.Println("get redis pool fail")
		return ErrGetRedisFail
	}
	redisConn := pool.Get()
	if redisConn == nil {
		fmt.Println("get redis conn fail")
		return ErrGetRedisConnectFail
	}
	defer redisConn.Close()
	_, err = redisConn.Do("sadd", key, value)
	if err != nil {
		fmt.Printf("redis sadd err: %v", err)
		return err
	}
	return
}

// Scard
func Scard(key string) (reply interface{}, err error) {
	pool := GetPlayerRedisPool(0)
	if pool == nil {
		fmt.Println("get redis pool fail")
		return reply, ErrGetRedisFail
	}
	redisConn := pool.Get()
	if redisConn == nil {
		fmt.Println("get redis conn fail")
		return reply, ErrGetRedisConnectFail
	}
	defer redisConn.Close()
	reply, err = redisConn.Do("scard", key)
	if err != nil {
		fmt.Printf("redis scard  err: %v", err)
		return reply, err
	}
	return
}

// Hgetall
func Hgetall(key string) (info map[string]string, err error) {
	pool := GetPlayerRedisPool(0)
	if pool == nil {
		fmt.Println("get redis pool fail")
		return info, ErrGetRedisFail
	}
	redisConn := pool.Get()
	if redisConn == nil {
		fmt.Println("get redis conn fail")
		return info, ErrGetRedisConnectFail
	}
	defer redisConn.Close()

	reply, err := redisConn.Do("hgetall", key)
	if err != nil {
		fmt.Printf("redis hgetall err: %v", err)
		return info, err
	}

	vals, err := redis.Values(reply, err)
	if err != nil {
		fmt.Printf("redis.Values err: %v", err)
		return info, err
	}

	info = make(map[string]string)
	for i := 0; i < len(vals)/2; i++ {
		subKey := string(vals[i*2].([]byte))
		val := string(vals[i*2+1].([]byte))
		info[subKey] = val
	}
	return
}

// Hget
func Hget(key, field string) (reply interface{}, err error) {
	pool := GetPlayerRedisPool(0)
	if pool == nil {
		fmt.Println("get redis pool fail")
		return reply, ErrGetRedisFail
	}
	redisConn := pool.Get()
	if redisConn == nil {
		fmt.Println("get redis conn fail")
		return reply, ErrGetRedisConnectFail
	}
	defer redisConn.Close()
	reply, err = redisConn.Do("hget", key, field)
	if err != nil {
		fmt.Printf("redis hget err: %v", err)
		return reply, err
	}
	return
}

// Hset
func Hset(key, field string, value int) (err error) {
	pool := GetPlayerRedisPool(0)
	if pool == nil {
		fmt.Println("get redis pool fail")
		return ErrGetRedisFail
	}
	redisConn := pool.Get()
	if redisConn == nil {
		fmt.Println("get redis conn fail")
		return ErrGetRedisConnectFail
	}
	defer redisConn.Close()
	_, err = redisConn.Do("hset", key, field, value)
	if err != nil {
		fmt.Printf("redis hset err: %v", err)
		return err
	}
	return
}

// Set
func Set(key, value string) (err error) {
	pool := GetPlayerRedisPool(0)
	if pool == nil {
		fmt.Println("get redis pool fail")
		return ErrGetRedisFail
	}
	redisConn := pool.Get()
	if redisConn == nil {
		fmt.Println("get redis conn fail")
		return ErrGetRedisConnectFail
	}
	defer redisConn.Close()
	_, err = redisConn.Do("set", key, value)
	if err != nil {
		fmt.Printf("redis hset err: %v", err)
		return err
	}
	return
}

// Get
func Get(key string) (reply interface{}, err error) {
	pool := GetPlayerRedisPool(0)
	if pool == nil {
		fmt.Println("get redis pool fail")
		return reply, ErrGetRedisFail
	}
	redisConn := pool.Get()
	if redisConn == nil {
		fmt.Println("get redis conn fail")
		return reply, ErrGetRedisConnectFail
	}
	defer redisConn.Close()
	reply, err = redisConn.Do("get", key)
	if err != nil {
		fmt.Printf("redis get err: %v", err)
		return reply, err
	}
	return
}

// 获取系统信息
func GetVersionInfo(version int) map[string]interface{} {
	var info = make(map[string]interface{})

	pool := GetAccountRedisPool()
	if pool == nil {
		fmt.Println("get redis pool fail")
		return info
	}
	rd := pool.Get()
	defer rd.Close()

	subKey := fmt.Sprintf("version:info:%d", version)
	val, _ := redis.String(rd.Do("hget", "tb_global:1", subKey))
	log.Println("GetVersionInfo val:", val)
	if val != "" {
		err := json.Unmarshal([]byte(val), &info)
		if err != nil {
			fmt.Println("GetVersionInfo err:", err)
		}
	}

	return info
}

// 更新系统信息
func UpdateVersionInfo(version int, data map[string]interface{}) bool {
	pool := GetAccountRedisPool()
	if pool == nil {
		fmt.Println("get redis pool fail")
		return false
	}
	rd := pool.Get()
	defer rd.Close()

	buff, _ := json.Marshal(data)
	subKey := fmt.Sprintf("version:info:%d", version)
	_, err := rd.Do("hset", "tb_global:1", subKey, buff)
	if err != nil {
		fmt.Println("UpdateVersionInfo err:", err)
		return false
	}
	return true
}

// 获取玩家昵称
func GetPlayerNickname(uid int) string {
	pool := GetPlayerRedisPool(0)
	if pool == nil {
		fmt.Println("get redis pool fail")
		return ""
	}
	redisConn := pool.Get()
	if redisConn == nil {
		fmt.Println("get redis conn fail")
		return ""
	}
	defer redisConn.Close()

	key := fmt.Sprintf("mdl:user:%d", uid)
	val, err := redis.String(redisConn.Do("hget", key, "nickname"))
	if err != nil {
		fmt.Printf("redis hset err: %v", err)
		return ""
	}
	return val
}
