package main

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"math/rand"
	"miads/adslib"
	"miads/adslib/addata"
	"miads/adslib/ads_checker"
	"miads/adslib/city"
	"miads/adslib/device"
	"miads/adslib/encrypt"
	"miads/adslib/graylog"
	"miads/adslib/ip2region"
	"miads/adslib/redis_data"
	"miads/adslib/utils"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type Response struct {
	Result    int    `json:"result"`
	Msg       string `json:"msg"`
	AdsResult string `json:"ads_result"`
	addata.AdData
}

func adsHandler(c *gin.Context) {
	c.Header("Content-Type", "application/json")

	request := adslib.Request{}
	request.Parse(c)

	fmt.Printf("%+v\n", request)
	advertiser := "xiaomi"
	uaClient := request.UaClient
	// 获取ua
	if uaClient == "" {
		uaClient = c.GetHeader("User-Agent")
		if uaClient == "" {
			uaClient = "Dalvik/2.1.0 (Linux; U; Android 6.0.1; MI 4LTE MIUI/6.9.1)"
		}
	}

	// 获取ip
	checkReqSourceFlag, err := ads_checker.CheckReqSource(request.ReqSource)
	if err != nil {
		c.String(404, "check req source failed: %s", err)
		return
	}

	ip := ""
	if checkReqSourceFlag {
		ip = request.ReqSourceIp
	}

	if ip == "" {
		ip = c.GetHeader("X-Forwarded-For")
	}

	if ip == "" {
		ip = c.GetHeader("X-Real-IP")
	}
	if ip == "" {
		ip = c.Request.RemoteAddr
	}
	if strings.Index(ip, ",") != -1 {
		ip = strings.Split(ip, ",")[0]
	}

	ipInfo, err := ip2region.Ip2Region(ip)
	if err != nil {
		c.String(404, "ip 2 region failed: %s", err)
		return
	}
	fmt.Printf("ip 2 region: %s, %+v\n", ip, ipInfo)

	// 上報
	if request.NewAdsFlag == 1 {
		grayLogData := struct {
			Ip           string
			Imei         string
			Model        string
			NetworkType  int `json:"network_type"`
			Province     string
			City         string
			ScreeSize    string `json:"screen_size"`
			Ua           string
			Brand        string
			Androidid    string `json:"android_id"`
			ShortMessage string `json:"short_message"`
			ReqSource    string `json:"req_source"`
		}{
			Ip:           ip,
			Imei:         request.Imei,
			Model:        request.Model,
			NetworkType:  request.NetworkType,
			Province:     ipInfo.Province,
			City:         ipInfo.City,
			ScreeSize:    request.ScreenSize,
			Ua:           request.UaClient,
			Brand:        request.Brand,
			Androidid:    request.Androidid,
			ShortMessage: "ads_api_log",
			ReqSource:    "zhiku",
		}

		graylog.Log(grayLogData)
	}

	cityCode, err := city.GetCityCode(ipInfo.City)
	if err != nil {
		c.String(404, "get city code failed: %s", err)
		return
	}

	// 是否是安卓
	if request.Imei == "" {
		device.SetAdsTagLog(advertiser, request.ReqSource, "DS_IOS", cityCode)
		graylog.LogApi("ios_device", request.Idfa, "", request.ReqSource)
	} else {
		device.SetAdsTagLog(advertiser, request.ReqSource, "DS_ANDRIOID", cityCode)
	}

	freqControlInterval := 600
	// 深圳，东莞强行用600秒控制, 其他地区从配置读取
	if strings.Index(ipInfo.City, "深圳") == -1 && strings.Index(ipInfo.City, "东莞") == -1 {
		// 频率控制
		freqControlConf, err := redis_data.GetFreqCrontolConf(request.ReqSource)
		if err != nil {
			c.String(404, "get freq control conf failed: %s", err)
			return
		}

		fmt.Printf("freq control conf: %+v\n", freqControlConf)
		hour, _ := strconv.Atoi(time.Now().Format("01"))
		tmpControlInterval, ok := freqControlConf.GetControlTime(hour)
		if ok {
			freqControlInterval = tmpControlInterval
		}
	}

	lastReqTime, err := device.GetIpReqTime(ip)
	if err != nil {
		fmt.Println(err)
		c.String(404, "get last req time failed: %s", err)
		return
	}

	needControl := false
	if request.ReqSource != "wzb_h5" && lastReqTime != 0 && time.Now().Unix()-lastReqTime < int64(freqControlInterval) {
		// 需要凭空
		needControl = true
		device.SetAdsTagLog(advertiser, request.ReqSource, "DS_FREQ_0", cityCode)
	} else {
		device.SetIpReqTime(ip, time.Now().Unix())
		device.SetAdsTagLog(advertiser, request.ReqSource, "DS_FREQ_1", cityCode)
	}

	//### 检查是否是ip黑名单
	isIpBlack, err := ads_checker.CheckBlackIp(ip)
	if err != nil {
		c.String(404, "check black ip failed: %s", err)
		return
	}
	if isIpBlack {
		graylog.LogApi("black_ip_list", ip, "", request.ReqSource)
		device.SetAdsTagLog(advertiser, request.ReqSource, "DS_BLACK_IP", cityCode)
	}

	// 获取渠道的黑白性
	reqChannelFlag, err := redis_data.GetChannelFlag(request.ReqSource, "ads_req")
	if err != nil {
		c.String(404, "get req channel flag failed: %s", err)
		return
	}
	flowWeight := reqChannelFlag.Weigth
	flowRandomNum := rand.Intn(100)

	flowFlag := 0 // 有效的百分比
	if flowRandomNum <= flowWeight {
		flowFlag = 1
	}
	if reqChannelFlag.ChannelFlag == 1 {
		device.SetAdsTagLog(advertiser, request.ReqSource, fmt.Sprintf("DS_REQ_SOURCE_{%d}", reqChannelFlag.ChannelFlag), cityCode)
	}

	// 替换成小米的设备
	replaceFlag := 0
	imei := request.Imei
	sendPhoneType := 0
	userFlag := 0
	originImei := ""

	// 检查是否是小米的设备
	specialDeviceNum := 0
	if request.ReqSource == "wzb_h5" {
		specialDeviceNum = 6 // wzb_h5渠道只綁定一个imei, 具体愿意不知道
	}
	if request.ReqSource == "moyuntv" || (!request.IsMiDevice() &&
		(!isIpBlack && !needControl && reqChannelFlag.ChannelFlag == 1) && flowFlag == 1) {
		randomNum := 3
		deviceConf, realRedisKey, err := device.GetMiDeviceConf(ip, randomNum, specialDeviceNum)
		if err != nil {
			c.String(404, "get req channel flag failed")
			return
		}
		if deviceConf != nil {
			device.SetAdsTagLog(advertiser, request.ReqSource, "DS_CACHE", cityCode) // 通过缓存请求
			imei = deviceConf.Imei
			uaClient = deviceConf.Ua
			originImei = deviceConf.OriginImei
			if imei != "" {
				replaceFlag = 1
				userFlag = 1
			}
		} else {
			// 先从对应的城市找,找不到在走原来的逻辑
			// 上报事件
			graylog.LogApi("city_search_city_code", strconv.Itoa(cityCode), ipInfo.City, request.ReqSource)
			device.SetAdsTagLog(advertiser, request.ReqSource, "DS_CODE_REQ", cityCode) // 可做城市替换
			if cityCode != 0 {
				device.SetAdsTagLog(advertiser, request.ReqSource, "DS_CODE", cityCode) // 替换成功

				fakeImei := ""
				fakeDeviceConf, leftCnt, err := device.GetDailyFakeDeviceConfByCityCode(cityCode)
				if err != nil {
					c.String(404, "get device conf failed")
					return
				}

				// 0 没有获取到， 1 获取到了
				gotCityFakeDeviceConfFlag := 0
				replaceUa := ""
				if fakeDeviceConf != nil {
					device.SetAdsTagLog(advertiser, request.ReqSource, "DS_REPL", cityCode)
					device.SetMiDeviceConf(realRedisKey, *fakeDeviceConf)
					imei = fakeDeviceConf.Imei
					uaClient = fakeDeviceConf.Ua
					originImei = fakeDeviceConf.OriginImei
					fakeImei = fakeDeviceConf.Imei
					if fakeDeviceConf.Imei != "" {
						gotCityFakeDeviceConfFlag = 1
						userFlag = 2
						replaceFlag = 1
					}
				}

				grayLogData := struct {
					ReqSource    string `json:"req_source"`
					OldImei      string `json:"old_imei"`
					NewImei      string `json:"new_imei"`
					IP           string `json:"ip"`
					City         string `json:"city"`
					CityCode     int    `json:"city_code"`
					Province     string
					HitFlag      int    `json:"hit_flag"`
					LeftCnt      int    `json:"left_cnt"`
					ReplaceUa    string `json:"replace_ua"`
					ShortMessage string `json:"short_message"`
				}{
					ReqSource:    request.ReqSource,
					OldImei:      request.Imei,
					NewImei:      fakeImei,
					IP:           ip,
					City:         ipInfo.City,
					CityCode:     cityCode,
					Province:     ipInfo.Province,
					HitFlag:      gotCityFakeDeviceConfFlag,
					LeftCnt:      leftCnt,
					ReplaceUa:    replaceUa,
					ShortMessage: "",
				}

				// 进行日志的上报
				graylog.Log(grayLogData)
			}
		}

		// 解码ua_client
		uaClient, _ = url.QueryUnescape(uaClient)
	} else if request.IsMiDevice() {
		device.SetAdsTagLog(advertiser, request.ReqSource, "DS_MI_REAL", cityCode) // 是小米设备
		userFlag = 3
		sendPhoneType = 1
	}

	// 检查下,替换后的设备是否是黑名单, 再次检查， 防止放入cache后， 新增了黑名单
	isBlackImei, err := device.CheckIsBlackImei(imei, false)
	if err != nil {
		c.String(404, "get device conf failed")
		return
	}

	if isBlackImei {
		if replaceFlag == 1 {
			device.SetAdsTagLog(advertiser, request.ReqSource, "DS_BLACK_IMEI_REPLACE", cityCode)
		} else {
			device.SetAdsTagLog(advertiser, request.ReqSource, "DS_BLACK_IMEI", cityCode)
		}
	}

	// 组装公共的dsp_info
	dspInfo := utils.DspParam{}
	dspInfo.Init()
	dspInfo.DspCityCode = cityCode
	dspInfo.Imei = imei
	dspInfo.OriginImei = originImei
	dspInfo.OsVersion = request.OsVersion
	dspInfo.Mac = strings.ToUpper(request.Mac)
	dspInfo.OriginMac = request.Mac
	dspInfo.Idfa = request.Idfa
	dspInfo.Model = request.Model
	dspInfo.Brand = request.Brand
	dspInfo.ScreenSize = request.ScreenSize
	dspInfo.NetworkType = request.NetworkType
	dspInfo.Androidid = request.Androidid
	dspInfo.Platform = request.Platform
	dspInfo.Ip = ip
	dspInfo.Ua = uaClient
	dspInfo.City = ipInfo.City
	dspInfo.Province = ipInfo.Province
	dspInfo.UaOrigin = request.UaClient
	dspInfo.ReqSource = request.ReqSource
	if request.IsMiDevice() {
		dspInfo.RealMiFlag = 1
	}
	dspInfo.ReplaceFlag = replaceFlag
	dspInfo.RealReqSource = request.ReqSource
	dspInfo.SendPhoneType = sendPhoneType
	md5Imei := imei
	if dspInfo.ReplaceFlag == 0 {
		md5Imei = utils.Md5(imei)
	}

	dspInfo.RealMd5Imei = md5Imei
	//ads_item = None
	//xiaomi_response = []
	hour, _ := strconv.Atoi(time.Now().Format("01"))

	canRequest := true
	if 0 <= hour && hour <= 1 {
		randNum := rand.Intn(100)
		if randNum > 5 {
			canRequest = false
		}
	}

	var adData *addata.AdData

	// 非频率控制，设备黑名单，ip黑名单，白名单渠道,并且替换了小米设备的
	if canRequest && !isBlackImei && reqChannelFlag.ChannelFlag == 1 && flowFlag == 1 && !isIpBlack && advertiser == "xiaomi" && request.ReqSource != "" && !needControl && (replaceFlag == 1 || request.IsMiDevice()) {
		adData, err = addata.GetAdsInfos(&dspInfo, advertiser)
	}

	canMixFlag := 0
	xiaomiResponseFlag := 0
	response := Response{}
	if adData != nil && len(adData.TargetAddition) > 1 {
		xiaomiResponseFlag = 1
		realTarget := ""
		if adData.Target != "" {
			md5Skip := utils.Md5(adData.Target)
			conf := adslib.GetConf()
			realTarget = conf.Host + fmt.Sprintf("?action=LOADING&req_source=%s&advertiser=video&skip=%s&brand=%s&request_id=%s&skip_other=%s",
				dspInfo.ReqSource, "", dspInfo.Brand, dspInfo.RequestId, md5Skip)

			// 塞入Redis中
			redis_data.SetSkipInfo(md5Skip, adData.Target)
		}
		adData.Target = realTarget
		adData.JsOrderId, _ = redis_data.GetMinScriptOrderByAdv(advertiser)
		adData.UserAgent = uaClient

		if dspInfo.ReqSource == "kuxin" && adData.Target != "" {
			adData.DpReport = fmt.Sprintf("%s?action=DP_CLICK&advertiser=video&req_source=%s", adslib.GetConf().HostIos, dspInfo.ReqSource)
			adData.Dp = adslib.GetConf().DpTest
		}
		if dspInfo.SendPhoneType == 0 {
			device.SetAdsTagLog(advertiser, dspInfo.ReqSource, "ADS_GET", cityCode) // 广告获取成功
		} else if dspInfo.SendPhoneType == 1 {
			device.SetAdsTagLog(advertiser, dspInfo.ReqSource, "ADS_GET_1", cityCode) // 广告获取成功
		}
		device.SetAdsTagLog(advertiser, dspInfo.ReqSource, fmt.Sprintf("ADS_USER_%d", userFlag), cityCode) //  广告类型，缓存，新用户，小米手机
		// 判断这个渠道是否要去融合和融合的流量占比
		mixChannelFlag, err := redis_data.GetChannelFlag(dspInfo.ReqSource, "ads_mix")
		if err != nil {
			c.String(404, "get device conf failed")
			return
		}
		flowRandomNum = rand.Intn(100)
		isOverFlow := false
		//flow_flag = 0
		if flowRandomNum > mixChannelFlag.Weigth {
			isOverFlow = true
		}
		if mixChannelFlag.ChannelFlag != 1 || isOverFlow {
			//extra_infos = []
		}

		// 组装返回去的action
		serverActionResponse := map[string]int{"server_view": 0, "server_click": 0, "server_close": 0, "server_video_finish": 0, "server_video_timer": 0}
		for _, targetInfo := range adData.TargetAddition {
			if targetInfo.Type == "VIEW" {
				serverActionResponse["server_view"] = 1
				redis_data.SetReqSourceView(advertiser, dspInfo.ReqSource, "xiafa")
			} else if targetInfo.Type == "CLICK" {
				serverActionResponse["server_click"] = 1
			} else if targetInfo.Type == "CLOSE" {
				serverActionResponse["server_close"] = 1
			} else if targetInfo.Type == "VIDEO_FINISH" {
				serverActionResponse["server_video_finish"] = 1
			} else if targetInfo.Type == "VIDEO_TIMER" {
				serverActionResponse["server_video_timer"] = 1
			}
		}

		// 增加跟随订单
		if len(adData.TargetAddition) == 2 && serverActionResponse["server_video_finish"] == 1 && (dspInfo.ReqSource == "kuxin" || dspInfo.ReqSource == "zhiku") {
			adData, err = addata.CombineOrderBy(adData, advertiser, &dspInfo)
			if err != nil {
				c.String(404, "combine order failed: %s", err.Error())
				return
			}
		}

		//# 检查最后是否有click
		//last_target_addition_infos = ads_item_new.get('target_addition',[])
		for _, targetAddition := range adData.TargetAddition {
			if targetAddition.Type == "CLICK" || targetAddition.Type == "VIDEO_TIMER" {
				canMixFlag = 0
				break
			}
		}

		if request.NewAdsFlag == 0 {
			//response.update(ads_item_new)
		} else {
			jsonBytes, err := json.Marshal(*adData)
			if err != nil {
				c.String(404, "marshal AdData failed: %s", err.Error())
				return
			}
			encryptData, _ := encrypt.Encrypt(jsonBytes, []byte(adslib.GetConf().SecretKey))
			response.AdsResult = encryptData
		}
	}
	if canMixFlag == 1 {
		response.Result = 2
		response.Msg = "no ads"
		if xiaomiResponseFlag == 1 {
			response.Result = 0
			response.Msg = "ok"
		}
		// 增加打底广告
		if (dspInfo.ReqSource == "kuxin" || dspInfo.ReqSource == "zhiku") && !needControl && !isBlackImei {
			shortMessage := "kong"
			customAdData, err := addata.GetCustomAdsInfos(&dspInfo, advertiser, 0, 0, xiaomiResponseFlag)
			if err != nil {
				c.String(404, "get custom ads info failed: %s", err.Error())
				return
			}

			// 定投没有就跑其他的
			if customAdData == nil {
				customAdData, err = addata.GetCustomAdsInfos(&dspInfo, advertiser, 0, 1, xiaomiResponseFlag)
				if err != nil {
					c.String(404, "get fix custom ads info failed: %s", err.Error())
					return
				}
			}
			device.SetAdsTagLog(advertiser, dspInfo.ReqSource, "ADS_ZIYOU_GET", cityCode) // 广告获取成功
			if customAdData != nil {
				shortMessage = "ads_tt_thirds"
			}

			if customAdData != nil && (shortMessage == "ads_vast_response" || shortMessage == "ads_tt_thirds") {
				adDataBytes, err := json.Marshal(*adData)
				if err != nil {
					fmt.Sprintf("marshal addata failed: %s\n", err)
				}
				grayLogData := struct {
					Ip           string
					ShortMessage string `json:"short_message"`
					ReqSource    string `json:"req_source"`
					ResponseVast string `json:"response_vast"`
					OrderName    string `json:"order_name"`
					Advertiser   string `json:"advertiser"`
				}{
					Ip:           ip,
					ShortMessage: "ads_api_log",
					ReqSource:    "zhiku",
					ResponseVast: string(adDataBytes),
					OrderName:    customAdData.OrderName,
					Advertiser:   advertiser,
				}

				graylog.Log(grayLogData)
			}
			if shortMessage == "ads_tt_thirds" {
				// 组装最后的信息
				lastAdData := addata.AdData{}
				rspTargetAddition := make([]addata.AdAction, 0, 50)
				//  当小米有填充的时候
				if len(response.TargetAddition) != 0 && len(customAdData.TargetAddition) != 0 {
					rspTargetAddition = response.TargetAddition
					lastAdData.UserAgent = response.UserAgent
				}
				//  当只有view的时候
				if len(customAdData.TargetAddition) == 1 {
					for _, url := range customAdData.TargetAddition[0].Urls {
						rspTargetAddition[0].Urls = append(rspTargetAddition[0].Urls, url)
					}
				} else {
					// 当自由订单有view和click的时候
					for _, url := range customAdData.TargetAddition[0].Urls {
						rspTargetAddition[0].Urls = append(rspTargetAddition[0].Urls, url)
					}

					for _, url := range customAdData.TargetAddition[1].Urls {
						rspTargetAddition[1].Urls = append(rspTargetAddition[1].Urls, url)
					}
					rspTargetAddition[1].Type = "CLICK"
				}
				lastAdData.Target = customAdData.Target
				lastAdData.JsOrderId = customAdData.JsOrderId
				lastAdData.TargetAddition = rspTargetAddition
				lastAdData.DpReport = response.DpReport
				lastAdData.Dp = response.Dp

				adDataBytes, err := json.Marshal(lastAdData)
				if err != nil {
					fmt.Sprintf("marshal addata failed: %s\n", err)
				}
				grayLogData := struct {
					ShortMessage string `json:"short_message"`
					ResponseVast string `json:"response_vast"`
				}{
					ShortMessage: "third_mix_xiaomi",
					ResponseVast: string(adDataBytes),
				}

				graylog.Log(grayLogData)
				customAdData = &lastAdData
			}
			if customAdData != nil {
				device.SetAdsTagLog(advertiser, dspInfo.ReqSource, "ADS_ZIYOU_HAVE", cityCode) // 广告获取成功
				if dspInfo.ReqSource == "zhiku" {
					response.Result = 0
					response.Msg = "ok"

					jsonBytes, err := json.Marshal(customAdData)
					if err != nil {
						c.String(404, "marsha custom addata failed: %s", err.Error())
						return
					}
					encryptData, _ := encrypt.Encrypt(jsonBytes, []byte(adslib.GetConf().SecretKey))
					response.AdsResult = encryptData
					graylog.ReportGrayLog(request, dspInfo, 0, 0)
					rspBytes, err := json.Marshal(response)
					if err != nil {
						c.String(404, "marshal Response failed: %s", err.Error())
						return
					}
					c.String(200, string(rspBytes))
					return
				} else {
					customAdData.Result = 0
					customAdData.Msg = "ok"
					graylog.ReportGrayLog(request, dspInfo, 0, 0)
					rspBytes, err := json.Marshal(customAdData)
					if err != nil {
						c.String(404, err.Error())
						return
					}
					c.String(200, string(rspBytes))
					return
				}
			}
		}
	}
	redis_data.SetAdsRealRequestNum(advertiser)
	rspBytes, err := json.Marshal(response)
	if err != nil {
		c.String(404, err.Error())
		return
	}

	if request.NewAdsFlag == 0 {
		graylog.ReportGrayLog(request, dspInfo, 0, 0)
	}
	device.SetAdsTagLog(advertiser, dspInfo.ReqSource, "DS_REQ", cityCode) // 所有请求
	c.String(200, string(rspBytes))
}
