package filterPoly

import (
	log "app.yhyue.com/moapp/jylog"
	"fmt"
	"github.com/gogf/gf/v2/frame/g"
)

// ReqFilterPoly 代理应用下每一组action
type ReqFilterPoly struct {
	Code string   //别名【用于验证码分组统计】
	Rule *ReqRule //action分组rule【需要配合Alias使用】
}

/*
IdFilter 用户请求频率拦截
param
id：用户session值
return
statusCode：0通过 -1黑名单 1被拦截 2出现验证码
key
*/
func (a *ReqFilterPoly) IdFilter(ctx g.Ctx, id string) (statusCode int, key string, inWhite bool) {
	//是否开启白名单(开启白名单且在白名单中直接跳过)
	if a.Rule.CheckWhite && a.checkWhiteList(id) {
		return 0, id, true
	}
	//检测是否在黑名单中
	if a.Rule.CheckBlack && a.checkBackList(id) {
		return -1, id, false
	}
	//检测是否处于验证码校验状态
	if a.IsWaitVerify(id) {
		return 2, id, false
	}

	// 阈值校验
	for i, v := range a.Rule.IdThreshold {
		if i != (len(a.Rule.IdThreshold) - 1) {
			if !a.rateCheckOk(id, v) && statusCode != 2 {
				statusCode = 2
			}
		} else {
			if !a.finalRateCheckOk(id, v, "id") && statusCode != 2 {
				statusCode = 2
			}
		}
	}

	// 设置验证码状态
	if statusCode == 2 {
		log.WithContext(ctx).Infof("%s 超出验证码请求阈值,弹出验证码", id)
		go a.SetWaitVerify(id, a.Rule.IdTimeRange)
	}

	//最大值校验
	if !a.rateCheckOk(id, a.Rule.IdMax) {
		log.WithContext(ctx).Infof("%s 超出最大请求限制,加入临时黑名单", id)
		a.addBackList(id, "exceed IdMax")
		AllRedis.Del(fmt.Sprintf(RateDataKey, a.Rule.Alias, a.Rule.IdMax[0], id))
		return -1, id, false
	}
	return statusCode, id, false
}

/*
IpFilter ip请求频率拦截
param
ip:请求ip地址
return
statusCode：0通过 -1黑名单 1被拦截 2出现验证码
*/
func (a *ReqFilterPoly) IpFilter(ctx g.Ctx, ip string) (statusCode int, key string, inWhite bool) {
	if !a.Rule.BCheckIp {
		return 0, ip, false
	}
	//是否开启白名单(开启白名单且在白名单中直接跳过)
	if a.Rule.CheckWhite && a.checkWhiteList(ip) {
		return 0, ip, true
	}
	//检测是否在黑名单中
	if a.Rule.CheckBlack && a.checkBackList(ip) {
		return -1, ip, false
	}

	//检测是否处于验证码校验状态
	if a.IsWaitVerify(ip) {
		return 2, ip, false
	}

	for i, v := range a.Rule.IpThreshold {
		if i != (len(a.Rule.IdThreshold) - 1) {
			if !a.rateCheckOk(ip, v) && statusCode != 2 {
				statusCode = 2
			}
		} else {
			if !a.finalRateCheckOk(ip, v, "ip") && statusCode != 2 {
				statusCode = 2
			}
		}
	}
	if statusCode == 2 {
		log.WithContext(ctx).Infof("%s 超出验证码请求阈值,弹出验证码", ip)
		go a.SetWaitVerify(ip, a.Rule.IdTimeRange)
	}
	//最大值校验
	if !a.rateCheckOk(ip, a.Rule.IpMax) {
		log.WithContext(ctx).Infof("%s 超出最大请求限制,加入临时黑名单", ip)
		a.addBackList(ip, "exceed IdMax")
		AllRedis.Del(fmt.Sprintf(RateDataKey, a.Rule.Alias, a.Rule.IpMax[0], ip))
		return -1, ip, false
	}
	return statusCode, ip, false
}
