package device

import (
	"encoding/json"
	"fmt"
	"github.com/gomodule/redigo/redis"
	"math/rand"
	"miads/adslib/ads_redis"
	"miads/adslib/utils"
	"strconv"
	"strings"
	"time"
)


type DeviceConf struct {
	Imei       string `json:"imei"`
	OriginImei string `json:"origin_imei"`
	Ua         string `json:"ua"`
}

func SetAdsTagLog(adv string, reqSource string, key string, cityCode int) {
	k := fmt.Sprintf("%s___%s___%s___%d",adv,reqSource,key,cityCode)
	setTagLog(k)
}

func setTagLog(key string) {
	conn := ads_redis.RedisConn.Get()
	defer conn.Close()

	dateInt, _ := strconv.Atoi(time.Now().Format("20060102"))
	k := fmt.Sprintf("{%s}___{%d}",key, dateInt)
	conn.Do("INCR", k)
	conn.Do("SADD", "fresh_all_keys", k)
}

// 存储ip上一次请求时间
func SetIpReqTime(ip string, reqTime int64) {
	conn := ads_redis.RedisConn.Get()
	defer conn.Close()

	ipKey := strings.ReplaceAll(ip, ".", "")
	redisKey := "adip_" + ipKey
	conn.Do("SET", redisKey, reqTime)
}

// 获取这个ip最近一次请求的时间
func GetIpReqTime(ip string) (int64, error) {
	conn := ads_redis.RedisConn.Get()
	defer conn.Close()

	ipKey := strings.ReplaceAll(ip, ".", "")
	redisKey := "adip_" + ipKey
	rsp, err := conn.Do("GET", redisKey)
	if err != nil {
		return 0, err
	}
	if rsp == nil {
		return 0, err
	}
	lastReqTime, _ := redis.Int64(rsp, err)
	return lastReqTime,nil
}

func SetMiDeviceConf(key string, d DeviceConf) error {
	conn := ads_redis.RedisConn.Get()
	defer conn.Close()

	deviceConfBytes, err := json.Marshal(d)
	if err != nil {
		return err
	}
	conn.Do("set", key, deviceConfBytes,86400)
	return nil
}

// 获取设备
func GetMiDeviceConf(ip string , randNum int, specialDeviceNum int) (*DeviceConf, string, error){
	conn := ads_redis.RedisConn.Get()
	defer conn.Close()

	dateInt, _ := strconv.Atoi(time.Now().Format("20060102"))
	rd := 0
	if specialDeviceNum==0 {
		rd = rand.Intn(randNum - 1) + 1
	} else {
		rd = specialDeviceNum
	}

	redisKey := fmt.Sprintf("adur_%s_%d_%d_v4", ip, dateInt, rd)
	rsp, err := conn.Do("GET", redisKey)
	if err != nil {
		return nil, redisKey, err
	}

	if rsp == nil {
		return nil, redisKey, nil
	}

	rspBytes, _ := redis.Bytes(rsp, err)

	d := DeviceConf{}
	err = json.Unmarshal(rspBytes, &d)
	if err != nil {
		return nil, redisKey, err
	}
	return &d, redisKey, nil
}

// 设置每天的city_code的值
func SetDailyFakeDeviceConfByCityCode(cityCode int, d DeviceConf, dateInt int) error {
	conn := ads_redis.RedisConn.Get()
	defer conn.Close()

	redisKey := fmt.Sprintf("amdu_%d_%d", cityCode, dateInt)
	deviceConfBytes, err := json.Marshal(d)
	if err != nil {
		return err
	}
	conn.Do("SADD", redisKey, deviceConfBytes)
	conn.Do("expire", redisKey, 129600)

	return nil
}

// 获取每天的设备imei
func GetDailyFakeDeviceConfByCityCode(cityCode int) (*DeviceConf, int, error){
	conn := ads_redis.RedisConn.Get()
	defer conn.Close()

	dateInt, _ := strconv.Atoi(time.Now().Format("20060102"))
	redisKey := fmt.Sprintf("amdu_%d_%d", cityCode, dateInt)

	var validDeviceConf *DeviceConf
	// 防止无限跑
	maxLoopCnt := 6
	for i := 0; i < maxLoopCnt; i++ {
		rsp, err := conn.Do("srandmember", redisKey)
		if err != nil {
			return nil, 0, err
		}

		if rsp == nil {
			return nil, 0, nil
		}

		rspBytes, _ := redis.Bytes(rsp, err)
		d := DeviceConf{}
		err = json.Unmarshal(rspBytes, &d)
		if err != nil {
			continue
		}

		isBlackItem, err := CheckIsBlackImei(d.Imei, false)
		if err != nil {
			continue
		}

		if !isBlackItem {
			validDeviceConf = &d
			break
		}

		AddCityCodeBlackImei(cityCode, d.Imei)
	}

	if validDeviceConf != nil {
		// 用过的device_id放入明天的key中
		tomorryDateInt, _ :=  strconv.Atoi(time.Now().AddDate(0, 0, 1).Format("20060102"))
		SetDailyFakeDeviceConfByCityCode(cityCode, *validDeviceConf, tomorryDateInt)
	}

	// 获取剩余的量
	leftCnt, err := redis.Int(conn.Do("SCARD", redisKey))
	if err != nil {
		return nil, 0, err
	}
	return validDeviceConf, leftCnt, nil
}

// 检查是否是黑名单
func CheckIsBlackImei(imei string, needMd5 bool) (bool, error) {
	conn := ads_redis.RedisConn.Get()
	defer conn.Close()

	checkImei := imei
	if needMd5 {
		checkImei = utils.Md5(imei)
	}

	redisKey := "ads_black_device_" + checkImei[0:2]
	isBlackImei, err := redis.Bool(conn.Do("sismember", redisKey, checkImei))
	if err != nil {
		return false, err
	}

	return isBlackImei, nil
}

// 存储city_code对应下的设备黑名单
func AddCityCodeBlackImei(cityCode int, imei string) {
	conn := ads_redis.RedisConn.Get()
	defer conn.Close()

	redisKey := fmt.Sprintf("blic_%d", cityCode)
	conn.Do("sadd", redisKey, imei)
}
