package data

import (
	"fmt"
	"eta/eta_api/models/data_manage"
	"eta/eta_api/utils"
	"sort"
	"strconv"
	"time"
)

func InitPositionTask() (err error) {
	exchanges := []string{"zhengzhou", "dalian", "shanghai", "cffex", "ine"} //郑商所,大商所,上期所,中金所,上期能源
	startDate := "2023-02-14"
	endDate := time.Now().Format(utils.FormatDate)
	for _, v := range exchanges {
		endDateTmpStr := endDate
		exchange := v
		fmt.Println("InitPositionTask:	启动:" + exchange)
		utils.FileLog.Info("InitPositionTask:	启动:" + exchange)
		startDateTmpTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
		startDateStr := startDateTmpTime.Format(utils.FormatDate)
		for {
			if startDateStr > endDate {
				break
			}
			endDateTmpTime := startDateTmpTime.AddDate(0, 1, 0)
			endDateTmpStr = endDateTmpTime.Format(utils.FormatDate)
			if endDateTmpStr > endDate {
				endDateTmpStr = endDate
			}
			fmt.Println("开始" + startDateStr + "结束" + endDateTmpStr)
			utils.FileLog.Info(fmt.Sprintf("InitTradePosition:开始:%s; 结束:%s", startDateStr, endDateTmpStr))
			//err :=data.DealYesterdayData(exchange, startDateStr)
			tErr, errMsg := InitTradePosition(exchange, startDateStr, endDateTmpStr)
			if tErr != nil {
				err = tErr
				fmt.Println("InitTradePosition: 操作失败:" + errMsg + tErr.Error())
				utils.FileLog.Info(fmt.Sprintf("InitTradePosition: 操作失败:%s:%s", errMsg, tErr.Error()))
				return
			}
			startDateTmpTime = endDateTmpTime.AddDate(0, 0, 1)
			startDateStr = startDateTmpTime.Format(utils.FormatDate)
		}
		fmt.Println("InitTradePosition:" + exchange + "已完成")
		utils.FileLog.Info("InitTradePosition:" + exchange + "已完成")
	}
	return
}

func InitTradePosition(exchange, startDate, endDate string) (err error, errMsg string) {
	// 批量插入今日的初始值
	count, err := data_manage.GetTradePositionTopCountByExchangeDataTime(exchange, startDate, endDate)
	if err != nil {
		errMsg = "查询原始数据失败,GetTradePositionTopCountByExchangeDataTime() Err: "
		return
	}
	if count > 0 {
		err = fmt.Errorf("数据已存在,无需处理")
		return
	}
	err = data_manage.MultiInsertTradeBaseDataToTop(exchange, startDate, endDate)
	if err != nil {
		errMsg = "新增原始数据失败,MultiInsertTradeBaseDataToTop() Err: "
		return
	}
	originList, err := data_manage.GetTradePositionTopByExchangeDataTime(exchange, startDate, endDate)
	if err != nil {
		errMsg = "查询原始数据失败, GetTradePositionTopByExchangeDataTime() Err: "
		return
	}
	if len(originList) <= 0 {
		err = fmt.Errorf("原始数据没有值")
		return
	}

	now := time.Now()
	dataTimeMap := make(map[string]*data_manage.TradePositionTop)
	onlyEmptyMap := make(map[string]bool)
	onlyEmptyNameMap := make(map[string]*data_manage.TradePositionTop)
	topLastMap := make(map[string]int)
	topLastRankMap := make(map[string]int)
	list := make([]*data_manage.TradePositionTop, 0)
	for _, v := range originList {
		tmp0, tmpErr := dealTradeOriginData(dataTimeMap, onlyEmptyMap, onlyEmptyNameMap, v, topLastMap, topLastRankMap, startDate, now)
		if tmpErr != nil {
			err = tmpErr
			errMsg = "处理原始数据失败 dealTradeOriginData() Err: "
			return
		}
		if tmp0 != nil {
			list = append(list, tmp0)
		}
		if len(list) >= 1000 {
			err = data_manage.InsertMultiTradePositionTop(exchange, list)
			if err != nil {
				errMsg = "批量新增昨日数据失败,InsertMultiTradePositionTop() Err: "
				return
			}
			list = make([]*data_manage.TradePositionTop, 0)
		}
	}
	if len(list) > 0 {
		err = data_manage.InsertMultiTradePositionTop(exchange, list)
		if err != nil {
			errMsg = "批量新增昨日数据失败,InsertMultiTradePositionTop() Err: "
			return
		}
		list = make([]*data_manage.TradePositionTop, 0)
	}
	// 处理某个期货公司只有买单没有卖单,或者只有卖单没有买单的情况
	for k, v := range onlyEmptyNameMap {
		_, ok1 := onlyEmptyMap[k+"_1"]
		_, ok2 := onlyEmptyMap[k+"_2"]
		var dealType int
		if ok1 && !ok2 {
			dealType = 2 //只有买单没有卖单
		} else if !ok1 && ok2 {
			dealType = 1 //只有卖单没有买单的情况
		} else {
			continue
		}
		if dealType > 0 {
			str := v.ClassifyName + "_" + v.ClassifyType + "_" + v.DataTime + "_" + strconv.Itoa(dealType)
			dealValue := 0
			if lastVal, ok := topLastMap[str]; ok {
				dealValue = int(float64(lastVal)*0.7 + 0.5)
			}

			tmp := &data_manage.TradePositionTop{
				ClassifyName:  v.ClassifyName,
				ClassifyType:  v.ClassifyType,
				DealShortName: v.DealShortName,
				DataTime:      v.DataTime,
				DealValue:     dealValue,
				CreateTime:    now,
				ModifyTime:    now,
				DealType:      dealType,
				SourceType:    2,
			}
			list = append(list, tmp)
			if len(list) >= 1000 {
				err = data_manage.InsertMultiTradePositionTop(exchange, list)
				if err != nil {
					errMsg = "批量新增前日数据失败,InsertMultiTradePositionTop() Err: "
					return
				}
				list = make([]*data_manage.TradePositionTop, 0)
			}
		}
	}

	if len(list) > 0 {
		err = data_manage.InsertMultiTradePositionTop(exchange, list)
		if err != nil {
			errMsg = "批量新增前日数据失败,InsertMultiTradePositionTop() Err: "
			return
		}
	}

	//生成净多单,净空单榜单
	err = createAnalysisCleanTop(exchange, startDate, endDate)
	if err != nil {
		errMsg = "创建净多单,净空单数据失败,createAnalysisCleanTop() Err: "
		return
	}
	// 特殊处理起始日期前一天的数据
	err = DealYesterdayData(exchange, startDate)
	if err != nil {
		errMsg = "处理昨日数据失败,DealYesterdayData() Err: "
		return
	}
	return
}

func dealTradeOriginData(dataTimeMap map[string]*data_manage.TradePositionTop, onlyEmptyMap map[string]bool, onlyEmptyNameMap map[string]*data_manage.TradePositionTop, currentItem *data_manage.TradePositionTop, topLastMap map[string]int, topLastRankMap map[string]int, startDate string, now time.Time) (tmp0 *data_manage.TradePositionTop, err error) {
	classifyName := currentItem.ClassifyName
	classifyType := currentItem.ClassifyType
	dealShortName := currentItem.DealShortName
	dealValue := currentItem.DealValue
	dealChange := currentItem.DealChange
	dataTime := currentItem.DataTime
	dealType := currentItem.DealType
	dealTypeStr := strconv.Itoa(dealType)
	dataTimeMap[classifyName+"_"+classifyType+"_"+dealTypeStr+"_"+dealShortName+"_"+dataTime] = currentItem
	onlyEmptyMap[classifyName+"_"+classifyType+"_"+dataTime+"_"+dealShortName+"_"+dealTypeStr] = true
	onlyEmptyNameMap[classifyName+"_"+classifyType+"_"+dataTime+"_"+dealShortName] = currentItem
	if currentItem.Rank > topLastRankMap[classifyName+"_"+classifyType+"_"+dataTime+"_"+dealTypeStr] {
		topLastMap[classifyName+"_"+classifyType+"_"+dataTime+"_"+dealTypeStr] = dealValue
		topLastRankMap[classifyName+"_"+classifyType+"_"+dataTime+"_"+dealTypeStr] = currentItem.Rank
	}
	if dataTime > startDate {
		tmpTimeStr, tErr := getYesterdayDate(dataTime)
		if tErr != nil {
			err = tErr
			return
		}
		if tmpTimeStr < startDate {
			return
		}
		// 判断T-1日是否有值, 如果T-1日为空,则根据T日的值计算出T-1的值
		if _, ok := dataTimeMap[classifyName+"_"+classifyType+"_"+dealTypeStr+"_"+dealShortName+"_"+tmpTimeStr]; !ok {
			yesterdayVal := dealValue - dealChange
			yesterdayChange := 0
			beforeYesterday, _ := getYesterdayDate(tmpTimeStr)
			beforeYesterdayItem, ok1 := dataTimeMap[classifyName+"_"+classifyType+"_"+dealTypeStr+"_"+dealShortName+"_"+beforeYesterday]
			if ok1 {
				yesterdayChange = yesterdayVal - beforeYesterdayItem.DealValue
			}
			tmp0 = &data_manage.TradePositionTop{
				ClassifyName:  classifyName,
				ClassifyType:  classifyType,
				DealShortName: dealShortName,
				DealValue:     yesterdayVal,
				DealChange:    yesterdayChange,
				DataTime:      tmpTimeStr,
				CreateTime:    now,
				ModifyTime:    now,
				DealType:      dealType,
				SourceType:    1,
			}
			dataTimeMap[classifyName+"_"+classifyType+"_"+dealTypeStr+"_"+dealShortName+"_"+tmpTimeStr] = tmp0
			onlyEmptyMap[classifyName+"_"+classifyType+"_"+tmpTimeStr+"_"+dealShortName+"_"+dealTypeStr] = true
			onlyEmptyNameMap[classifyName+"_"+classifyType+"_"+tmpTimeStr+"_"+dealShortName] = tmp0
		}
	}
	return
}

// 更新昨日数据
func DealYesterdayData(exchange, startDate string) (err error) {
	// 查询最早的日期
	firstItem, err := data_manage.GetFirstBaseFromTradeIndexByDate(exchange)
	if err != nil {
		return
	}
	if startDate == firstItem.DataTime { //如果当前是起始日,则无需统计修改前一天的数据
		return
	}

	yesterdayStr, err := getYesterdayDate(startDate)
	if err != nil {
		return
	}
	//查找前日的值,并更新对应的更改
	beforeYesterdayStr, err := getYesterdayDate(yesterdayStr)
	if err != nil {
		return
	}
	// 先查出T日最原始的数据
	originList, err := data_manage.GetTradePositionTopByExchangeDataTime(exchange, startDate, startDate)
	if err != nil {
		return
	}
	originBuyMap := make(map[string]*data_manage.TradePositionTop)
	originSoldMap := make(map[string]*data_manage.TradePositionTop)
	for _, v := range originList {
		if v.SourceType != 0 {
			continue
		}
		str := v.ClassifyName + "_" + v.ClassifyType + "_" + v.DealShortName
		if v.DealType == 1 {
			originBuyMap[str] = v
		} else if v.DealType == 2 {
			originSoldMap[str] = v
		}
	}

	// 然后查询T-1中数据来源类型是2的数据
	changeList, err := data_manage.GetTradePositionTopByExchangeSourceType(exchange, yesterdayStr, 2)
	if err != nil {
		return
	}
	if len(changeList) <= 0 {
		//err = fmt.Errorf("前天的数据无需修改")
		return
	}
	// 查询出前日的成交量
	beforeYesterdayList, err := data_manage.GetTradePositionTopByExchangeDataTime(exchange, beforeYesterdayStr, beforeYesterdayStr)
	if err != nil {
		return
	}
	beforeYesterdayMap1 := make(map[string]int)
	beforeYesterdayMap2 := make(map[string]int)
	if len(beforeYesterdayList) > 0 {
		for _, v := range beforeYesterdayList {
			if v.SourceType == 2 {
				continue
			}
			str := v.ClassifyName + "_" + v.ClassifyType + "_" + v.DealShortName
			if v.DealType == 1 {
				beforeYesterdayMap1[str] = v.DealValue
			} else if v.DealType == 2 {
				beforeYesterdayMap2[str] = v.DealValue
			}
		}
	}
	// 根据原始数据中的值推算出最新的值
	now := time.Now()
	// 批量更新到分析表中,
	var updateAnalysisData []data_manage.UpdateDealValueChange
	for _, v := range changeList {
		str := v.ClassifyName + "_" + v.ClassifyType + "_" + v.DealShortName
		dealValue := 0
		dealChange := 0
		if v.DealType == 1 {
			if n, ok := originBuyMap[str]; ok {
				dealValue = n.DealValue - n.DealChange
				if beforeVal, ok1 := beforeYesterdayMap1[str]; ok1 {
					dealChange = dealValue - beforeVal
				}
				tmp := data_manage.UpdateDealValueChange{
					Id:         v.Id,
					DealValue:  dealValue,
					DealChange: dealChange,
					SourceType: 1,
					ModifyTime: now,
				}
				updateAnalysisData = append(updateAnalysisData, tmp)
			}
		} else if v.DealType == 2 {
			if n, ok := originSoldMap[str]; ok {
				dealValue = n.DealValue - n.DealChange
				if beforeVal, ok1 := beforeYesterdayMap2[str]; ok1 {
					dealChange = dealValue - beforeVal
				}
				tmp := data_manage.UpdateDealValueChange{
					Id:         v.Id,
					DealValue:  dealValue,
					DealChange: dealChange,
					SourceType: 1,
					ModifyTime: now,
				}
				updateAnalysisData = append(updateAnalysisData, tmp)
			}
		}
	}
	if len(updateAnalysisData) > 0 {
		err = data_manage.MultiUpdatePositionTop(exchange, updateAnalysisData)
		if err != nil {
			return
		}
		//删除T-1日净多单和净空单的榜单
		err = data_manage.DeletePositionTopByDataTime(exchange, yesterdayStr, 3)
		if err != nil {
			return
		}

		err = data_manage.DeletePositionTopByDataTime(exchange, yesterdayStr, 4)
		if err != nil {
			return
		}

		//重新生成净多单和净空单的榜单
		err = createAnalysisCleanTop(exchange, yesterdayStr, yesterdayStr)
		if err != nil {
			return
		}
	}

	return
}

// createAnalysisCleanTop 生成净多单,净空单榜单
func createAnalysisCleanTop(exchange, startDate, endDate string) (err error) {
	topList := make([]*data_manage.TradePositionTop, 0)
	now := time.Now()
	var subDataList data_manage.TradePositionSubList

	subChangeMap1 := make(map[string]int) //净多单map
	subChangeMap2 := make(map[string]int) //净空单map
	//查询所有差值数据,
	yesterday, err := getYesterdayDate(startDate)
	if err != nil {
		return
	}
	yesterdayTopList1, tErr := data_manage.GetTradePositionTopByExchangeDataTimeType(exchange, yesterday, 3)
	if tErr != nil {
		err = tErr
		return
	}
	if len(yesterdayTopList1) > 0 {
		for _, v := range yesterdayTopList1 {
			nameStr := v.ClassifyName + "_" + v.ClassifyType + "_" + v.DataTime + "_" + v.DealShortName
			subChangeMap1[nameStr] = v.DealValue
		}
	}

	yesterdayTopList2, tErr := data_manage.GetTradePositionTopByExchangeDataTimeType(exchange, yesterday, 4)
	if tErr != nil {
		err = tErr
		return
	}
	if len(yesterdayTopList2) > 0 {
		for _, v := range yesterdayTopList2 {
			nameStr := v.ClassifyName + "_" + v.ClassifyType + "_" + v.DataTime + "_" + v.DealShortName
			subChangeMap2[nameStr] = v.DealValue
		}
	}

	originDataList, err := data_manage.GetTradePositionTopByExchangeDataTime(exchange, startDate, endDate)
	if err != nil {
		return
	}
	buyDataMap := make(map[string]int)
	for _, v := range originDataList {
		str := v.ClassifyName + "_" + v.ClassifyType + "_" + v.DataTime + "_" + v.DealShortName
		if v.DealType == 1 {
			buyDataMap[str] = v.DealValue
		} else if v.DealType == 2 {
			subValue := 0
			dealType := 0
			if buy, ok := buyDataMap[str]; ok {
				subValue = buy - v.DealValue
				if subValue >= 0 {
					dealType = 3
				} else {
					subValue = -subValue
					dealType = 4
				}
			}
			tmp := &data_manage.TradePositionSub{
				ClassifyName:  v.ClassifyName,
				ClassifyType:  v.ClassifyType,
				DataTime:      v.DataTime,
				DealShortName: v.DealShortName,
				SubValue:      subValue,
				DealType:      dealType,
			}
			subDataList = append(subDataList, tmp)
		}
	}
	if len(subDataList) > 0 {
		sort.Sort(subDataList)
	}
	var dealType int
	rankMap := make(map[string]int)
	for _, v := range subDataList {
		subValue := v.SubValue
		nameStr := v.ClassifyName + "_" + v.ClassifyType + "_" + v.DataTime + "_" + v.DealShortName
		if v.DealType == 3 {
			subChangeMap1[nameStr] = subValue
			dealType = 3
			if _, ok := rankMap[v.ClassifyName+"_"+v.ClassifyType+"_"+v.DataTime+"_3"]; !ok {
				rankMap[v.ClassifyName+"_"+v.ClassifyType+"_"+v.DataTime+"_3"] = 1
			} else {
				rankMap[v.ClassifyName+"_"+v.ClassifyType+"_"+v.DataTime+"_3"]++
			}
		} else if v.DealType == 4 {
			subChangeMap2[nameStr] = subValue
			dealType = 4
			if _, ok := rankMap[v.ClassifyName+"_"+v.ClassifyType+"_"+v.DataTime+"_4"]; !ok {
				rankMap[v.ClassifyName+"_"+v.ClassifyType+"_"+v.DataTime+"_4"] = 1
			} else {
				rankMap[v.ClassifyName+"_"+v.ClassifyType+"_"+v.DataTime+"_4"]++
			}
		}
		//和T-1日比较差值
		var tmpTimeStr string
		tmpTimeStr, err = getYesterdayDate(v.DataTime)
		if err != nil {
			return
		}
		yesterdayStr := v.ClassifyName + "_" + v.ClassifyType + "_" + tmpTimeStr + "_" + v.DealShortName
		dealChange := 0
		if dealType == 3 {
			if c, ok := subChangeMap1[yesterdayStr]; ok {
				dealChange = subValue - c
			}
		} else if dealType == 4 {
			if c, ok := subChangeMap2[yesterdayStr]; ok {
				dealChange = subValue - c
			}
		}
		tmp := &data_manage.TradePositionTop{
			ClassifyName:  v.ClassifyName,
			ClassifyType:  v.ClassifyType,
			DataTime:      v.DataTime,
			CreateTime:    now,
			ModifyTime:    now,
			DealShortName: v.DealShortName,
			DealValue:     subValue,
			DealChange:    dealChange,
			DealType:      dealType,
			Rank:          rankMap[v.ClassifyName+"_"+v.ClassifyType+"_"+v.DataTime+"_"+strconv.Itoa(dealType)],
		}
		topList = append(topList, tmp)
		if len(topList) >= 1000 {
			err = data_manage.InsertMultiTradePositionTop(exchange, topList)
			if err != nil {
				return
			}
			topList = make([]*data_manage.TradePositionTop, 0)
		}
	}

	if len(topList) >= 0 {
		err = data_manage.InsertMultiTradePositionTop(exchange, topList)
		if err != nil {
			return
		}
	}
	return
}

func getYesterdayDate(today string) (yesterday string, err error) {
	i := 1
	tmpTime, err := time.ParseInLocation(utils.FormatDate, today, time.Local)
	if err != nil {
		return
	}
	tmpTimeDate := tmpTime.AddDate(0, 0, -i)
	weekStr := tmpTimeDate.Weekday().String()
	if weekStr == "Sunday" {
		i += 2
	} else if weekStr == "Saturday" {
		i += 1
	}
	tmpTimeDate = tmpTime.AddDate(0, 0, -i)
	yesterday = tmpTimeDate.Format(utils.FormatDate)
	return
}