package addata

import (
	"fmt"
	"math/rand"
	"miads/adslib"
	"miads/adslib/redis_data"
	"miads/adslib/utils"
	"strconv"
	"strings"
	"time"
)

func CombineOrderBy(adData *AdData, advertiser string, dsp *utils.DspParam) (*AdData, error) {
	customAdData, err := GetCustomAdsInfos(dsp, advertiser, 1, 0, 0)
	if err != nil {
		return adData, err
	}
	if customAdData == nil {
		return adData, nil
	}

	if len(customAdData.TargetAddition) == 0 {
		return adData, nil
	}

	maxExchangeLen := len(customAdData.TargetAddition)
	// 最多替换数量, 不知道为啥是2
	if maxExchangeLen > 2 {
		maxExchangeLen = 2
	}

	hasClickTarget := false
	for i := 0; i < maxExchangeLen; i++ {
		adData.TargetAddition[i].Urls = customAdData.TargetAddition[i].Urls
		if customAdData.TargetAddition[i].Type == "CLICK" {
			adData.TargetAddition[i].Type = "CLICK"
			hasClickTarget = true
		}
	}

	if hasClickTarget {
		adData.Target = customAdData.Target
		adData.JsOrderId = customAdData.JsOrderId
	}
	return adData, nil
}

// 获取一个广告
func getOneAds(dsp *utils.DspParam, orderType int, fixFlag int) (*redis_data.AdOrderInfo, error) {
	// 取出广告
	orders, err := redis_data.GetOrderInfos(dsp, fixFlag)
	if err != nil {
		return nil, err
	}
	if len(orders) == 0 {
		return nil, nil
	}

	gotOrders := make([]redis_data.AdOrderInfo, 0, 1000)
	allKpi := int64(0)
	for _, order := range orders {
		if order.OrderType == int64(orderType) {
			gotOrders = append(gotOrders, order)
			allKpi += order.ShowKpi
		}
	}

	orderRange := make([]int, 0, 1000)

	curRateIdx := 0

	// orderRange中记录的是当前同索引位置的gotOrders里的order的比例上限, 比如如果有两个order [ShowKpi:40, ShowKpi: 60]
	// 那么orderRange就是 [rate:400, rate: 1000], 所以要按比例取order, 只需要获得在比例上限里随机取一个数, 然后判断落在那个orderRange里,
	// 对应去gotOrders取同索引里的order即可, 因为算法里有对小于1的比例做补偿， 所以rate上限可能超出1000, rate乘1000而不是100主要是为了
	// 如果showKpi差异过大， 对大量小于1的订单做补偿, 会影响整体流量分布, 这里放到1000倍， 降低补偿1的影响, 算法复杂度是O(n), 只有三个非嵌套循环
	for _, order := range gotOrders {
		rate := int(float32(order.ShowKpi) / float32(allKpi) * 1000)

		// 防止比例过小, 取int后变为0
		if rate < 1 {
			rate = 1
		}

		curRateIdx = curRateIdx + rate
		orderRange = append(orderRange, curRateIdx)
	}

	randNum := rand.Intn(curRateIdx)
	for i, rateRange := range orderRange {
		if randNum <= rateRange {
			return &gotOrders[i], nil
		}
	}
	return nil, nil
}

// 获取投放数量
func getNeedDispatchCount(adData *redis_data.AdOrderInfo) (int, error) {
	beginTime := time.Unix(adData.BeginTime, 0)

	// 获取当前分钟值
	beginMinute := beginTime.Minute() + (beginTime.Hour() * 60)

	// 获取起点分钟, 不知道原因, 不加会有bug
	beginMinute += 2

	// 获取分钟数到24点还能跑多少值
	key := "time_all_count_" + strconv.Itoa(beginMinute)
	// 0 默认曲线, 1 定制曲线
	if adData.LineType == 1 {
		key = fmt.Sprintf("time_all_count_%d_%d", adData.OrderID, beginMinute)
	}

	// 起始剩余值
	beginRemainDispatchCount, err := redis_data.GetRemainDispatchCount(key)
	if err != nil {
		return 0, err
	}

	// 计算最后分钟
	endTime := time.Unix(adData.EndTime, 0)

	endMinute := endTime.Minute() + (endTime.Hour() * 60)
	if endMinute > 1439 {
		// 不懂这里逻辑
		endMinute = endMinute - 1440 + 2
	}

	key = "time_all_count_" + strconv.Itoa(endMinute)
	if adData.LineType == 1 {
		// 定制曲线
		key = fmt.Sprintf("time_all_count_%d_%d", adData.OrderID, endMinute)
	}

	endRemainDispatchCnt, err := redis_data.GetRemainDispatchCount(key)
	if err != nil {
		return 0, err
	}

	// 结束的剩余值 - 起始剩余值 = 获取区间能跑的值
	needDispatchCount := beginRemainDispatchCount - endRemainDispatchCnt
	return needDispatchCount, nil
}

func GetCustomAdsInfos(dsp *utils.DspParam, advertiser string, orderType int, fixFlag int, xiaomiHasFlag int) (*AdData, error) {
	order, err := getOneAds(dsp, orderType, fixFlag)
	if err != nil {
		return nil, err
	}
	if order == nil {
		return nil, nil
	}

	if xiaomiHasFlag == 1 {
		if strings.Index(order.Title, "_ios") > 0 {
			return nil, nil
		}
	}

	// 获取剩余时间内的值
	needDispatchCnt, err := getNeedDispatchCount(order)
	if err != nil {
		return nil, err
	}

	if needDispatchCnt < 1 {
		return nil, nil
	}

	curTime := time.Now()

	// #已经投放的key
	finishShowCnt, err := redis_data.GetFinishedDispatchCount(order.OrderID, "show", curTime)
	if err != nil {
		return nil, err
	}

	fmt.Sprintf("finish show cnt: %d\n", finishShowCnt)
	redis_data.SetPlanDispatchCount(order.OrderID, "show", needDispatchCnt, curTime)

	// 计算曲线比例
	rate := float32(order.ShowKpi) / float32(needDispatchCnt)

	lineValue := 0
	if order.LineType == 1 {
		// 订单定制曲线
		lineValue, err = redis_data.GetOrderPerMinuteNeedDispatchCnt(order.OrderID, curTime)
	} else {
		lineValue, err = redis_data.GetPerMinuteNeedDispatchCnt(curTime)
	}
	if err != nil {
		return nil, err
	}
	// 当前分钟需要放出去的数量
	curMinuteNeedDispatchCnt := int(float32(lineValue) * rate)
	if curMinuteNeedDispatchCnt < 1 {
		curMinuteNeedDispatchCnt = 1
	}

	redis_data.SetOrderPlanDispatchCount(order.OrderID, "show", curMinuteNeedDispatchCnt, curTime)

	// 获取当前分钟已经完成的下发
	curMinuteFinishedDispatchCnt, err := redis_data.GetPreMinuteFinishedDispatchCount(order.OrderID, "show", curTime)
	if curMinuteFinishedDispatchCnt < curMinuteNeedDispatchCnt {
		data := AdData{
			Duration:  5,
			JsOrderId: order.JsOrderID,
			OrderName: order.Title,
			UserAgent: dsp.UaOrigin,
		}

		//放量
		_, err := redis_data.IncrFinishedDispatchCount(order.OrderID, "show", 1, curTime)
		if err != nil {
			return nil, err
		}
		_, err = redis_data.IncrPreMinuteFinishedDispatchCount(order.OrderID, "show", 1, curTime)
		if err != nil {
			return nil, err
		}

		showUrl := order.ShowURL
		clickUrl := order.ClickURL
		targetUrl := order.TargetURL

		if strings.Index(order.Title, "_ios") != -1 {
			iosImei, iosUa, err := redis_data.GetIosUaImei(dsp.Ip)
			if err != nil {
				return nil, err
			}
			if iosUa != "" {
				data.UserAgent = iosUa
			}
			if order.ImeiReplaceFlag == 1 && iosImei != "" {
				showUrl = strings.ReplaceAll(showUrl, "__IDFA__", iosImei)
				clickUrl = strings.ReplaceAll(clickUrl, "__IDFA__", iosImei)
				targetUrl = strings.ReplaceAll(targetUrl, "__IDFA__", iosImei)
			}

			if strings.Index(order.Title, "__OS__") != -1 {
				showUrl = strings.ReplaceAll(showUrl, "__OS__", "1")
				clickUrl = strings.ReplaceAll(clickUrl, "__OS__", "1")
				targetUrl = strings.ReplaceAll(targetUrl, "__OS__", "1")
			}
		} else if strings.Index(order.Title, "_android") != -1 {
			// 判断是否需要替换imei
			if order.ImeiReplaceFlag == 1 {
				showUrl = strings.ReplaceAll(showUrl, "__IMEI__", dsp.RealMd5Imei)
				clickUrl = strings.ReplaceAll(clickUrl, "__IMEI__", dsp.RealMd5Imei)
				targetUrl = strings.ReplaceAll(targetUrl, "__IMEI__", dsp.RealMd5Imei)
			}

			if strings.Index(order.Title, "__OS__") != -1 {
				showUrl = strings.ReplaceAll(showUrl, "__OS__", "0")
				clickUrl = strings.ReplaceAll(clickUrl, "__OS__", "0")
				targetUrl = strings.ReplaceAll(targetUrl, "__OS__", "0")
			}
		} else {
			r := rand.Intn(100)
			if r < 40 && xiaomiHasFlag == 0 {
				iosImei, iosUa, err := redis_data.GetIosUaImei(dsp.Ip)
				if err != nil {
					return nil, err
				}
				if iosUa != "" {
					data.UserAgent = iosUa
				}
				if order.ImeiReplaceFlag == 1 && iosImei != "" {
					showUrl = strings.ReplaceAll(showUrl, "__IDFA__", iosImei)
					clickUrl = strings.ReplaceAll(clickUrl, "__IDFA__", iosImei)
					targetUrl = strings.ReplaceAll(targetUrl, "__IDFA__", iosImei)
				}

				if strings.Index(order.Title, "__OS__") != -1 {
					showUrl = strings.ReplaceAll(showUrl, "__OS__", "1")
					clickUrl = strings.ReplaceAll(clickUrl, "__OS__", "1")
					targetUrl = strings.ReplaceAll(targetUrl, "__OS__", "1")
				}
			} else {
				// 判断是否需要替换imei
				if order.ImeiReplaceFlag == 1 {
					showUrl = strings.ReplaceAll(showUrl, "__IMEI__", dsp.RealMd5Imei)
					clickUrl = strings.ReplaceAll(clickUrl, "__IMEI__", dsp.RealMd5Imei)
					targetUrl = strings.ReplaceAll(targetUrl, "__IMEI__", dsp.RealMd5Imei)
				}

				if strings.Index(order.Title, "__OS__") != -1 {
					showUrl = strings.ReplaceAll(showUrl, "__OS__", "0")
					clickUrl = strings.ReplaceAll(clickUrl, "__OS__", "0")
					targetUrl = strings.ReplaceAll(targetUrl, "__OS__", "0")
				}
			}
		}

		if strings.Index(order.Title, "__IP__") != -1 {
			showUrl = strings.ReplaceAll(showUrl, "__IP__", dsp.Ip)
			clickUrl = strings.ReplaceAll(clickUrl, "__IP__", dsp.Ip)
			targetUrl = strings.ReplaceAll(targetUrl, "__IP__", dsp.Ip)
		}

		var addi *AdAction
		if orderType == 0 {
			addi = genMonitorAction("VIEW", order.Title, dsp.ReqSource, showUrl)
		} else {
			addi = genMonitorAction("VIEW", order.Title, "follow", showUrl)
		}

		data.TargetAddition = append(data.TargetAddition, *addi)

		r := rand.Intn(1000)
		clickRate := int(float32(order.ClickKpi) / float32(order.ShowKpi) * 1000)
		if r < clickRate {
			//下发点击
			addi = genMonitorAction("CLICK", order.Title, dsp.ReqSource, clickUrl)
			data.TargetAddition = append(data.TargetAddition, *addi)
			md5Skip := utils.Md5(targetUrl)
			redis_data.IncrFinishedDispatchCount(order.OrderID, "click", 1, curTime)
			realTarget := adslib.GetConf().Host + fmt.Sprintf("?action=LOADING&req_source=%s&advertiser=%s&skip=%s&skip_other=%s",
				dsp.ReqSource, "", order.Title, md5Skip)
			// 塞入缓存中
			redis_data.SetSkipInfo(md5Skip, targetUrl)
			data.Target = realTarget
			return &data, nil
		}
	}

	return nil, nil
}

func genMonitorAction(action string, title string, reqSource string, url string) *AdAction {
	duration := 5
	if action == "VIDEO_TIMER" {
		duration = 7
	}

	urlArr := make([]string, 0, 50)
	if url != "" {
		urlArr = strings.Split(url, "||")
	}
	adAction := AdAction{
		Type:     action,
		Duration: duration,
		Urls:     urlArr,
	}
	urlHost := adslib.GetConf().HostIos
	actionUrl := fmt.Sprintf("%s?action=%s&advertiser=%s&req_source=%s",
		urlHost, action, reqSource, title)
	adAction.Urls = append(adAction.Urls, actionUrl)
	return &adAction
}
