package future_good

import (
	"errors"
	"eta/eta_mobile/models/data_manage"
	"eta/eta_mobile/models/data_manage/future_good"
	"eta/eta_mobile/models/data_manage/future_good/request"
	"eta/eta_mobile/services/data"
	"eta/eta_mobile/utils"
	"fmt"
	"github.com/shopspring/decimal"
	"github.com/yidane/formula"
	"sort"
	"strconv"
	"strings"
	"time"
)

// GetProfitChartEdbData 获取利润图表的指标数据
func GetProfitChartEdbData(baseEdbInfo *data_manage.EdbInfo, edbInfoList []*data_manage.EdbInfo, zlFutureGoodEdbInfoList []*future_good.FutureGoodEdbInfo, chartInfoDateList []request.ChartInfoDateReq, formulaStr string, edbInfoFromTagList []data_manage.EdbInfoFromTag, reqXDataList []data_manage.XData) (barConfigEdbInfoIdList []data_manage.BarChartInfoEdbItemReq, edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, xDataList []data_manage.XData, yDataList []data_manage.YData, err error) {
	edbList = make([]*data_manage.ChartEdbInfoMapping, 0)

	if baseEdbInfo == nil {
		err = errors.New("ETA指标未选取")
		return
	}
	if len(edbInfoList) == 0 {
		edbInfoList = append(edbInfoList, baseEdbInfo)
	}
	if len(zlFutureGoodEdbInfoList) <= 0 {
		err = errors.New("商品指标未选取")
		return
	}

	// 标签与期货商品指标的关联关系
	tagEdbIdMap := make(map[string]int)
	// 有效的期货商品指标
	futureGoodEdbInfoIdMap := make(map[int]int)
	{
		tmpTagEdbIdMap := make(map[string]int)
		for _, v := range edbInfoFromTagList {
			tmpTagEdbIdMap[v.FromTag] = v.EdbInfoId
		}
		formulaMap := CheckFormula(formulaStr)
		for _, tag := range formulaMap {
			tagEdbIdMap[tag] = tmpTagEdbIdMap[tag]
			futureGoodEdbInfoIdMap[tmpTagEdbIdMap[tag]] = tmpTagEdbIdMap[tag]
		}
	}
	// 指标对应的所有数据
	//edbDataListMap := make(map[int][]*data_manage.EdbDataList)

	item := new(data_manage.ChartEdbInfoMapping)
	item.FrequencyEn = data.GetFrequencyEn(baseEdbInfo.Frequency)

	if baseEdbInfo.Unit == `无` {
		item.Unit = ``
	}

	// 普通的指标数据
	baseDataListMap := make(map[int][]*data_manage.EdbDataList)
	for _, v := range edbInfoList {
		baseDataList := make([]*data_manage.EdbDataList, 0)
		baseDataList, err = data_manage.GetEdbDataList(v.Source, v.SubSource, v.EdbInfoId, "", "")
		if err != nil {
			return
		}
		baseDataListMap[v.EdbInfoId] = baseDataList
	}

	latestDate := zlFutureGoodEdbInfoList[0].EndDate
	latestDateTime, _ := time.ParseInLocation(utils.FormatDate, latestDate, time.Local)

	earliestDateTime := latestDateTime // 数据的最早日期，目的是为了找出最早的合约
	for _, barChartInfoDate := range chartInfoDateList {
		var findDateTime time.Time
		switch barChartInfoDate.Type {
		case 1: //最新值
			findDateTime = latestDateTime
		case 2: //近期几天
			findDateTime = latestDateTime.AddDate(0, 0, -barChartInfoDate.Value)
		case 3: // 固定日期
			//寻找固定日期的数据
			tmpFindDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, barChartInfoDate.Date, time.Local)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			findDateTime = tmpFindDateTime
		default:
			err = errors.New(fmt.Sprint("日期类型异常,Type:", barChartInfoDate.Type))
			return
		}
		if findDateTime.IsZero() {
			err = errors.New("错误的日期")
			return
		}
		if findDateTime.Before(earliestDateTime) {
			earliestDateTime = findDateTime
		}
	}

	monthNum := (latestDateTime.Year()-earliestDateTime.Year())*12 + int(latestDateTime.Month()-earliestDateTime.Month())

	// 存储主力合约下的所有月份合约
	futureGoodEdbInfoDateMap := make(map[int]map[string]*future_good.FutureGoodEdbInfo)
	futureGoodDataListMap := make(map[int][]*data_manage.EdbDataList, 0)
	// 特殊的商品期货合约（只有M+N的合约，没有固定日期的合约）
	specialFutureGoodEdbInfoMap := make(map[int]map[int]*future_good.FutureGoodEdbInfo, 0)

	isAllChina := true // 是否都是国内的期货合约
	for _, v := range zlFutureGoodEdbInfoList {
		if v.RegionType != "国内" {
			isAllChina = false
			break
		}
	}

	nMap := make(map[string]string)
	var maxN int // 最大N值
	for _, v := range zlFutureGoodEdbInfoList {
		// 如果不是有效的商品期货指标，那么就过滤掉，不做数据查询处理，避免没必要的请求
		if _, ok := futureGoodEdbInfoIdMap[v.FutureGoodEdbInfoId]; !ok {
			continue
		}
		// 获取期货指标以及期货数据
		tmpFutureGoodEdbInfoList, tmpErr := future_good.GetChildFutureGoodEdbInfoListByParentId(v.FutureGoodEdbInfoId)
		if tmpErr != nil {
			err = tmpErr
			return
		}

		childFutureGoodEdbInfoMap, tmpMaxN, tmpErr := getProfitFutureGoodEdbInfoList(earliestDateTime, v, tmpFutureGoodEdbInfoList, isAllChina, monthNum)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		if maxN < tmpMaxN {
			maxN = tmpMaxN
		}
		futureGoodEdbInfoDateMap[v.FutureGoodEdbInfoId] = childFutureGoodEdbInfoMap

		if v.FutureGoodEdbType == 2 {
			specialFutureGoodEdbInfoMap[v.FutureGoodEdbInfoId] = make(map[int]*future_good.FutureGoodEdbInfo)
		}
		// 获取数据
		for date, childFutureGoodEdbInfo := range childFutureGoodEdbInfoMap {
			nMap[date] = date
			dataList := make([]*data_manage.EdbDataList, 0)

			tmpDataList, tmpErr := future_good.GetFutureGoodEdbDataListByDate(childFutureGoodEdbInfo.FutureGoodEdbInfoId, "", "")
			if tmpErr != nil {
				return
			}
			for _, tmpData := range tmpDataList {
				dataList = append(dataList, &data_manage.EdbDataList{
					EdbDataId:     tmpData.FutureGoodEdbDataId,
					EdbInfoId:     tmpData.FutureGoodEdbInfoId,
					DataTime:      tmpData.DataTime.Format(utils.FormatDate),
					DataTimestamp: tmpData.DataTimestamp,
					Value:         tmpData.Close,
				})
			}
			futureGoodDataListMap[childFutureGoodEdbInfo.FutureGoodEdbInfoId] = dataList

			if childFutureGoodEdbInfo.FutureGoodEdbType == 2 {
				specialFutureGoodEdbInfoMap[v.FutureGoodEdbInfoId][childFutureGoodEdbInfo.Month] = childFutureGoodEdbInfo
			}
		}
	}

	// 找出所有的N值，并进行正序排列
	dateList := make([]string, 0)
	for _, n := range nMap {
		dateList = append(dateList, n)
	}
	sort.Slice(dateList, func(i, j int) bool {
		return dateList[i] < dateList[j]
	})
	var reqEdbInfoIds []int
	for _, v := range edbInfoList {
		reqEdbInfoIds = append(reqEdbInfoIds, v.EdbInfoId)
		tmp := data_manage.XData{
			Name:   v.EdbName,
			NameEn: v.EdbNameEn,
		}
		xDataList = append(xDataList, tmp)
	}
	var edbIdList []int

	edbIdList, yDataList, err = ProfitChartChartData(baseEdbInfo, baseDataListMap, futureGoodEdbInfoDateMap, futureGoodDataListMap, chartInfoDateList, baseEdbInfo.EndDate, specialFutureGoodEdbInfoMap, formulaStr, tagEdbIdMap, dateList, maxN, reqEdbInfoIds)

	// todo 最后处理数据
	tmpXDataList, newYDataList, err := handleProfitResultData(xDataList, baseEdbInfo, yDataList, earliestDateTime, edbIdList)
	if err != nil {
		return
	}
	if len(reqXDataList) == 0 {
		xDataList = tmpXDataList
	} else {
		xDataList = reqXDataList
	}

	yDataList = newYDataList

	return
}

// ProfitChartChartData 获取数据
func ProfitChartChartData(baseEdbInfo *data_manage.EdbInfo, baseDataListMap map[int][]*data_manage.EdbDataList, futureGoodEdbInfoMap map[int]map[string]*future_good.FutureGoodEdbInfo, futureGoodEdbDataListMap map[int][]*data_manage.EdbDataList, chartInfoDateList []request.ChartInfoDateReq, latestDate string, specialFutureGoodEdbInfoMap map[int]map[int]*future_good.FutureGoodEdbInfo, formulaStr string, tagEdbIdMap map[string]int, dateList []string, maxN int, reqEdbInfoIds []int) (edbIdList []int, yDataList []data_manage.YData, err error) {
	// 指标数据数组（10086:{"2022-12-02":100.01,"2022-12-01":102.3}）
	//earliestDateTime time.Time
	// ETA指标数据
	allBaseEdbDateDataMap := make(map[int]map[string]float64)
	for edbInfoId, baseDataList := range baseDataListMap {
		baseEdbDateData := make(map[string]float64)
		for _, edbData := range baseDataList {
			baseEdbDateData[edbData.DataTime] = edbData.Value
		}
		allBaseEdbDateDataMap[edbInfoId] = baseEdbDateData
	}

	// 商品指标数据
	edbDataMap := make(map[int]map[string]float64)
	for edbInfoId, edbDataList := range futureGoodEdbDataListMap {
		edbDateData := make(map[string]float64)
		for _, edbData := range edbDataList {
			edbDateData[edbData.DataTime] = edbData.Value
		}
		edbDataMap[edbInfoId] = edbDateData
	}

	latestDateTime, _ := time.ParseInLocation(utils.FormatDate, latestDate, time.Local)

	yDataList = make([]data_manage.YData, 0) //y轴的数据列表

	// 将计算公式中的字母转大写
	formulaStr = strings.ToUpper(formulaStr)

	for _, barChartInfoDate := range chartInfoDateList {
		yDataMap := make(map[int]float64)
		var maxDate time.Time

		var findDateTime time.Time
		switch barChartInfoDate.Type {
		case 1: //最新值
			findDateTime = latestDateTime
		case 2: //近期几天
			findDateTime = latestDateTime.AddDate(0, 0, -barChartInfoDate.Value)
		case 3: // 固定日期
			//寻找固定日期的数据
			tmpFindDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, barChartInfoDate.Date, time.Local)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			findDateTime = tmpFindDateTime
		default:
			err = errors.New(fmt.Sprint("日期类型异常,Type:", barChartInfoDate.Type))
			return
		}
		if findDateTime.IsZero() {
			err = errors.New("错误的日期")
			return
		}

		findDataList := make([]float64, 0)  // 当前日期的数据值
		noDataIdList := make([]int, 0)      // 没有数据的指标id
		noDataIdMap := make(map[int]int, 0) // 没有数据的指标map
		xEdbInfoIdList := make([]int, 0)    // 当前数据的指标id列表

		// 现货指标
		index := 0
		var realDateTime time.Time
		// 现货指标
		baseEdbDateData, ok := allBaseEdbDateDataMap[baseEdbInfo.EdbInfoId]
		if !ok {
			err = fmt.Errorf("指标id: %d 没有数据", baseEdbInfo.EdbInfoId)
			return
		}
		realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, baseDataListMap[baseEdbInfo.EdbInfoId], baseEdbDateData, edbDataMap)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		if isFind {
			maxDate = realDateTime
		}
		edbIdList = make([]int, 0) //普通指标ID
		for _, edbInfoId := range reqEdbInfoIds {
			if edbInfoId == baseEdbInfo.EdbInfoId {
				findDataList = append(findDataList, findDataValue)
				yDataMap[index] = findDataValue
				xEdbInfoIdList = append(xEdbInfoIdList, edbInfoId)
				edbIdList = append(edbIdList, edbInfoId)
				index += 1
				continue
			}
			baseEdbDateDataTmp, ok := allBaseEdbDateDataMap[edbInfoId]
			if !ok {
				err = fmt.Errorf("指标id: %d 没有数据", edbInfoId)
				return
			}
			findDataValueTmp, isFindTmp := baseEdbDateDataTmp[realDateTime.Format(utils.FormatDate)]
			if !isFindTmp {
				noDataIdList = append(noDataIdList, edbInfoId)
				noDataIdMap[edbInfoId] = edbInfoId
			}
			findDataList = append(findDataList, findDataValueTmp)
			yDataMap[index] = findDataValueTmp

			xEdbInfoIdList = append(xEdbInfoIdList, edbInfoId)
			edbIdList = append(edbIdList, edbInfoId)
			index += 1
		}

		mList := make([]int, 0) // 间隔月份

		// 最小开始的n值
		//minN := (findDateTime.Year()-earliestDateTime.Year())*12 + int(findDateTime.Month()-earliestDateTime.Month())
		for _, date := range dateList {
			currDate, _ := time.ParseInLocation(utils.FormatYearMonthDate, date, time.Local)
			// 如果当前的n值小于最小开始的n值，那么就不处理
			//if n < minN {
			//	continue
			//}
			//findDateTime

			// 获取当前日期相对开始日期的期数
			tmpN := (currDate.Year()-realDateTime.Year())*12 + int(currDate.Month()-realDateTime.Month())
			if tmpN <= 0 {
				continue
			}

			// 如果期数大于最大期数，那么就退出当前匹配
			if tmpN >= maxN {
				break
			}

			zlAndChildEdbId := make(map[int]int)
			childFutureGoodEdbInfoIdList := make([]int, 0)
			for zlFutureGoodEdbInfoId, futureGoodEdbInfoList := range futureGoodEdbInfoMap {
				// 判断是否特殊合约
				if childFutureGoodEdbInfoIdMap, ok := specialFutureGoodEdbInfoMap[zlFutureGoodEdbInfoId]; ok {
					if childFutureGoodEdbInfo, ok2 := childFutureGoodEdbInfoIdMap[tmpN]; ok2 {
						childFutureGoodEdbInfoIdList = append(childFutureGoodEdbInfoIdList, childFutureGoodEdbInfo.FutureGoodEdbInfoId)
						zlAndChildEdbId[zlFutureGoodEdbInfoId] = childFutureGoodEdbInfo.FutureGoodEdbInfoId
					}

				} else {
					if childFutureGoodEdbInfo, ok2 := futureGoodEdbInfoList[date]; ok2 {
						childFutureGoodEdbInfoIdList = append(childFutureGoodEdbInfoIdList, childFutureGoodEdbInfo.FutureGoodEdbInfoId)
						zlAndChildEdbId[zlFutureGoodEdbInfoId] = childFutureGoodEdbInfo.FutureGoodEdbInfoId
					}
				}
			}

			// 合约不全，不参与计算
			//if len(childFutureGoodEdbInfoIdList) != lenZlFutureGoodEdbInfo {
			//	continue
			//}

			calculateMap := make(map[int]float64)
			for _, childFutureGoodEdbInfoId := range childFutureGoodEdbInfoIdList {
				tmpFindDataValue, tmpIsFind := edbDataMap[childFutureGoodEdbInfoId][realDateTime.Format(utils.FormatDate)]

				if tmpIsFind && tmpFindDataValue != 0 {
					calculateMap[childFutureGoodEdbInfoId] = tmpFindDataValue
				}
			}
			// 合约的数据不全，不参与计算
			//if len(calculateMap) != lenZlFutureGoodEdbInfo {
			//	continue
			//}

			newTagEdbIdMap := make(map[string]int)
			for tag, zlEdbId := range tagEdbIdMap {
				newTagEdbIdMap[tag] = zlAndChildEdbId[zlEdbId]
			}
			//, formulaStr string, tagEdbIdMap map[string]int
			formulaFormStr := ReplaceFormula(newTagEdbIdMap, calculateMap, formulaStr)
			//计算公式异常，那么就移除该指标
			if formulaFormStr == `` {
				//removeDateList = append(removeDateList, sk)
				fmt.Println("异常了")
				continue
			}

			expression := formula.NewExpression(formulaFormStr)
			calResult, evaluateErr := expression.Evaluate()
			if evaluateErr != nil {
				// 分母为0的报错
				if strings.Contains(evaluateErr.Error(), "divide by zero") {
					//removeDateList = append(removeDateList, sk)
					continue
				}
				err = errors.New("计算失败：Err:" + evaluateErr.Error() + ";formulaStr:" + formulaFormStr)
				fmt.Println(err)
				continue
			}
			// 如果计算结果是NAN，那么就退出当前循环
			if calResult.IsNan() {
				continue
			}
			calVal, tmpErr := calResult.Float64()
			if tmpErr != nil {
				err = errors.New("计算失败：获取计算值失败 Err:" + tmpErr.Error() + ";formulaStr:" + formulaFormStr)
				fmt.Println(err)
				continue
			}
			//yDataMap[n] = calVal
			//xEdbInfoIdList = append(xEdbInfoIdList, n)
			calVal, _ = decimal.NewFromFloat(calVal).Round(4).Float64()
			yDataMap[tmpN] = calVal
			xEdbInfoIdList = append(xEdbInfoIdList, tmpN)
			findDataList = append(findDataList, calVal)
		}
		yName := barChartInfoDate.Name
		yNameEn := barChartInfoDate.Name
		if yName == `` {
			if barChartInfoDate.Type == 2 {
				yName = strconv.Itoa(barChartInfoDate.Value) + "天前"
				if barChartInfoDate.Value == 1 {
					yNameEn = strconv.Itoa(barChartInfoDate.Value) + "day ago"
				} else {
					yNameEn = strconv.Itoa(barChartInfoDate.Value) + " days ago"
				}
			} else {
				yName = maxDate.Format(utils.FormatDate)
				yNameEn = maxDate.Format(utils.FormatDate)
			}
		}
		yDate := "0000-00-00"
		if !maxDate.IsZero() {
			yDate = maxDate.Format(utils.FormatDate)
		}

		{
			hasDataIndexList := make([]int, 0)
			for dataK, edbInfoId := range xEdbInfoIdList {
				if _, ok := noDataIdMap[edbInfoId]; !ok { // 如果是没有数据的指标id
					hasDataIndexList = append(hasDataIndexList, dataK)
				}
			}
			lenHasDataIndex := len(hasDataIndexList)
			if lenHasDataIndex > 0 {
				for lenHasDataI := 1; lenHasDataI < lenHasDataIndex; lenHasDataI++ {
					perK := hasDataIndexList[lenHasDataI-1] //上一个有数据的指标下标
					currK := hasDataIndexList[lenHasDataI]  //当前有数据的指标下标
					preVal := findDataList[perK]            //上一个有数据的坐标的值
					currVal := findDataList[currK]          //当前有数据的指标的值

					// 环差值
					hcValDeci := decimal.NewFromFloat(currVal).Sub(decimal.NewFromFloat(preVal)).Div(decimal.NewFromInt(int64(currK - perK)))
					var tmpI int64
					// 将两个中间的数据做平均值补全
					for hcI := perK + 1; hcI < currK; hcI++ {
						tmpI++
						findDataList[hcI], _ = decimal.NewFromFloat(preVal).Add(hcValDeci.Mul(decimal.NewFromInt(tmpI))).RoundCeil(4).Float64()
					}
				}
			}
		}

		yDataList = append(yDataList, data_manage.YData{
			Date:           yDate,
			ConfigDate:     realDateTime,
			Value:          findDataList,
			NoDataEdbList:  noDataIdList,
			XEdbInfoIdList: xEdbInfoIdList,
			Color:          barChartInfoDate.Color,
			Name:           yName,
			NameEn:         yNameEn,
			EdbValMap:      yDataMap,
			M:              mList,
		})
	}

	return
}

// getFutureGoodEdbInfoList 获取适用的指标列表
func getProfitFutureGoodEdbInfoList(earliestDateTime time.Time, zlFutureGoodEdbInfo *future_good.FutureGoodEdbInfo, tmpFutureGoodEdbInfoList []*future_good.FutureGoodEdbInfo, isAllChina bool, monthNum int) (futureGoodEdbInfoDateMap map[string]*future_good.FutureGoodEdbInfo, newMaxN int, err error) {
	maxN := 36 //最大36期合约
	futureGoodEdbInfoList := make([]*future_good.FutureGoodEdbInfo, 0)
	futureGoodEdbInfoDateMap = make(map[string]*future_good.FutureGoodEdbInfo)

	earliestDateTime = time.Date(earliestDateTime.Year(), earliestDateTime.Month(), 1, 0, 0, 0, 0, time.Local)
	if zlFutureGoodEdbInfo.RegionType == "国内" {
		startMonth := int(earliestDateTime.Month())
		if startMonth == 1 {
			futureGoodEdbInfoList = tmpFutureGoodEdbInfoList
		} else {
			// 因为是下标，所以对应想下标是需要-1的
			index := startMonth - 1
			futureGoodEdbInfoList = tmpFutureGoodEdbInfoList[index:]
			futureGoodEdbInfoList = append(futureGoodEdbInfoList, tmpFutureGoodEdbInfoList[:index]...)
		}

		lenFutureGoodEdbInfoList := len(futureGoodEdbInfoList)
		//futureGoodEdbInfoList
		//if isAllChina {
		//}
		// 如果全是国内指标，那么只需要拼上多出的几期合约即可
		maxN = lenFutureGoodEdbInfoList + monthNum

		for i := 1; i < maxN; i++ {
			k := i % lenFutureGoodEdbInfoList
			futureGoodEdbInfoDateMap[earliestDateTime.AddDate(0, i, 0).Format(utils.FormatYearMonthDate)] = futureGoodEdbInfoList[k]
		}

		//需求池604，只要是国内合约，最大必须是12期
		newMaxN = 12

		return
	}

	for _, v := range tmpFutureGoodEdbInfoList {
		//海外的连续日期,目前
		if v.FutureGoodEdbType == 2 {
			if v.Month <= maxN {
				futureGoodEdbInfoDateMap[earliestDateTime.AddDate(0, v.Month, 0).Format(utils.FormatYearMonthDate)] = v
				if v.Month > newMaxN {
					newMaxN = v.Month
				}
			}
			continue
		}

		if v.Year < earliestDateTime.Year() {
			continue
		}
		// 小于等于当前年，那么就肯定是ok的
		if v.Year == earliestDateTime.Year() && v.Month <= int(earliestDateTime.Month()) {
			continue
		}

		subYear := v.Year - earliestDateTime.Year()
		subMonth := v.Month - int(earliestDateTime.Month())
		// 如果（当前年-最新日期的年份） * 12个月 + (当前月-最新日期的月份) 小于总月份
		tmpN := subYear*12 + subMonth
		if tmpN < maxN {
			tmpDateTime := time.Date(v.Year, time.Month(v.Month), 0, 0, 0, 0, 0, time.Local)
			futureGoodEdbInfoDateMap[tmpDateTime.Format(utils.FormatYearMonthDate)] = v
			if tmpN > newMaxN {
				newMaxN = tmpN
			}
			continue
		}
	}

	return
}

// handleProfitResultData 处理成最终的结果数据
func handleProfitResultData(xDataListInit []data_manage.XData, baseEdbInfo *data_manage.EdbInfo, yDataList []data_manage.YData, earliestDateTime time.Time, allEdbInfoIds []int) (xDataList []data_manage.XData, newYDataList []data_manage.YData, err error) {
	newYDataList = yDataList
	xDataList = xDataListInit

	nMap := make(map[int]int)
	nList := make([]int, 0)
	nListEdbMap := make(map[int]struct{})
	for _, v := range yDataList {
		for _, n := range v.XEdbInfoIdList {
			if utils.InArrayByInt(allEdbInfoIds, n) {
				if _, ok := nListEdbMap[n]; !ok {
					nList = append(nList, n)
					nListEdbMap[n] = struct{}{}
				}
			} else {
				nMap[n] = n
			}
		}
	}

	// 找出所有的N值，并进行正序排列
	nListTmp := make([]int, 0)
	for _, n := range nMap {
		nListTmp = append(nListTmp, n)
	}
	sort.Slice(nListTmp, func(i, j int) bool {
		return nListTmp[i] < nListTmp[j]
	})
	nList = append(nList, nListTmp...)
	for _, n := range nList {
		if utils.InArrayByInt(allEdbInfoIds, n) {
			continue
		}
		xDataList = append(xDataList, data_manage.XData{
			Name:   fmt.Sprint("M+", n),
			NameEn: fmt.Sprint("M+", n),
		})
	}

	for yIndex, yData := range yDataList {
		newYDataList[yIndex].XEdbInfoIdList = []int{}
		newYDataList[yIndex].Value = []float64{}
		tmpNList := nList

		xEdbInfoIdList := yData.XEdbInfoIdList
		valIndex := 0
		needNum := 0
		for _, n := range tmpNList {
			if len(xEdbInfoIdList) > 0 {
				currN := xEdbInfoIdList[0]
				// 当前距离最早的日期相差的N数
				if n == currN { // todo 改成所有的基础现货指标
					if needNum > 0 {
						currVal := yData.Value[valIndex]
						preVal := yData.Value[valIndex-1]
						hcValDeci := decimal.NewFromFloat(currVal).Sub(decimal.NewFromFloat(preVal)).Div(decimal.NewFromInt(int64(needNum + 1)))

						for tmpNum := 0; tmpNum < needNum; tmpNum++ {
							newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, 0)

							// 赋值平均值
							tmpVal, _ := decimal.NewFromFloat(preVal).Add(hcValDeci.Mul(decimal.NewFromInt(int64(tmpNum + 1)))).RoundCeil(4).Float64()
							newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, tmpVal)
						}
					}
					if utils.InArrayByInt(allEdbInfoIds, currN) {
						newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, currN)
					} else {
						newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, currN+1)
					}

					newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, yData.Value[valIndex])
					valIndex++
					needNum = 0
					if len(xEdbInfoIdList) > 0 {
						xEdbInfoIdList = xEdbInfoIdList[1:]
					}
				} else {
					needNum++
				}
			}
		}
	}

	maxI := 0
	for _, yData := range newYDataList {
		lenEdb := len(yData.XEdbInfoIdList)
		for i := 0; i < lenEdb; i++ {
			if yData.XEdbInfoIdList[i] != 0 && !utils.InArrayByInt(yData.NoDataEdbList, yData.XEdbInfoIdList[i]) {
				if maxI < i {
					maxI = i
				}
			}
		}
	}

	earliestDateTime = time.Date(earliestDateTime.Year(), earliestDateTime.Month(), 1, 0, 0, 0, 0, time.Local)
	xDataList = xDataList[0 : maxI+1]
	for yIndex, yData := range newYDataList {
		if len(yData.XEdbInfoIdList) > maxI+1 {
			newYDataList[yIndex].XEdbInfoIdList = yData.XEdbInfoIdList[0 : maxI+1]
		}
		if len(yData.Value) > maxI+1 {
			newYDataList[yIndex].Value = yData.Value[0 : maxI+1]
		}

		currDate, _ := time.ParseInLocation(utils.FormatDate, yData.Date, time.Local)

		nameList := make([]string, 0)
		enNameList := make([]string, 0)
		for k1, n := range newYDataList[yIndex].XEdbInfoIdList {
			if utils.InArrayByInt(allEdbInfoIds, n) { // 现货价不处理
				tmpItem := xDataListInit[k1]
				nameList = append(nameList, tmpItem.Name)
				enNameList = append(enNameList, tmpItem.NameEn)
				continue
			}
			if n <= 0 {
				nameList = append(nameList, `无合约`)
				enNameList = append(enNameList, `no contract`)
			} else {
				var date string

				currDateTime := currDate.AddDate(0, n-1, 0)
				month := int(currDateTime.Month())
				date = fmt.Sprintf("%d%d", currDateTime.Year(), month)
				if month < 10 {
					date = fmt.Sprintf("%d0%d", currDateTime.Year(), month)
				}
				nameList = append(nameList, date)
				enNameList = append(enNameList, date)
			}
		}
		newYDataList[yIndex].NameList = nameList
		newYDataList[yIndex].EnNameList = enNameList
	}
	return
}

func CheckFormula(formula string) map[string]string {
	mathFormula := []string{"MAX", "MIN", "ABS", "ACOS", "ASIN", "CEIL", "MOD", "POW", "ROUND", "SIGN", "SIN", "TAN", "LOG10", "LOG2", "LOG", "LN"}

	str := strings.ToUpper(formula)
	for _, v := range mathFormula {
		str = strings.Replace(str, v, "", -1)
	}
	str = strings.Replace(str, "(", "", -1)
	str = strings.Replace(str, ")", "", -1)

	byteMap := make(map[string]string)
	for i := 0; i < len(str); i++ {
		byteInt := str[i]
		if byteInt >= 65 && byteInt <= 90 {
			byteStr := string(byteInt)
			if _, ok := byteMap[byteStr]; !ok {
				byteMap[byteStr] = byteStr
			}
		}
	}
	return byteMap
}

func ReplaceFormula(tagEdbIdMap map[string]int, valArr map[int]float64, formulaStr string) string {
	funMap := GetFormulaMap()
	for k, v := range funMap {
		formulaStr = strings.Replace(formulaStr, k, v, -1)
	}

	replaceCount := 0
	for tag, edbInfoId := range tagEdbIdMap {
		if val, valOk := valArr[edbInfoId]; valOk { //值存在
			dvStr := fmt.Sprintf("%v", val)
			formulaStr = strings.Replace(formulaStr, tag, dvStr, -1)
			replaceCount++
		}
	}
	for k, v := range funMap {
		formulaStr = strings.Replace(formulaStr, v, k, -1)
	}
	fmt.Println(formulaStr)
	if replaceCount == len(tagEdbIdMap) {
		return formulaStr
	} else {
		return ""
	}
}

func GetFormulaMap() map[string]string {
	funMap := make(map[string]string)
	funMap["MAX"] = "[@@]"
	funMap["MIN"] = "[@!]"
	funMap["ABS"] = "[@#]"
	funMap["CEIL"] = "[@$]"
	funMap["COS"] = "[@%]"
	funMap["FLOOR"] = "[@^]"
	funMap["MOD"] = "[@&]"
	funMap["POW"] = "[@*]"
	funMap["ROUND"] = "[@(]"
	return funMap
}
