package range_analysis

import (
	"encoding/json"
	"errors"
	"eta/eta_mobile/models/data_manage"
	"eta/eta_mobile/models/system"
	"eta/eta_mobile/services/alarm_msg"
	"eta/eta_mobile/services/data"
	"eta/eta_mobile/utils"
	"fmt"
	"github.com/shopspring/decimal"
	"math"
	"sort"
	"strconv"
	"strings"
	"time"
)

// GetAutoCalculateDateDataList 获取当前时间相关的区间作为计算依据
func GetAutoCalculateDateDataList(currentDate string, dataList []*data_manage.EdbDataList, req *data_manage.ChartRangeAnalysisExtraConf) (newDataList []*data_manage.EdbDataList, err error) {
	currentDateTime, _ := time.ParseInLocation(utils.FormatDate, currentDate, time.Local)
	switch req.DateRangeType {
	case 0:
		// 智能划分得到一个开始日期，和结束日期
		var startDateTime time.Time
		if req.AutoDateConf.IsAutoStartDate == 0 { //固定设置
			startDate := req.AutoDateConf.StartDate
			if startDate == "" {
				startDate = "2020-01-01"
			}
			startDateTime, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
		} else {
			startConf := req.AutoDateConf.StartDateConf
			startDate := ""
			if startConf.BaseDateType == 0 { //
				startDate = currentDate
			} else if startConf.BaseDateType == 1 {
				startDate = time.Now().Format(utils.FormatDate)
			}
			if startConf.MoveForward > 0 {
				startDate = GetEdbDateByMoveForward(startDate, startConf.MoveForward, dataList)
			}
			if len(startConf.DateChange) > 0 {
				startDate, err = HandleEdbDateChange(startDate, startConf.DateChange)
				if err != nil {
					err = fmt.Errorf("智能划分开始日期处理失败：%s", err.Error())
					return
				}
			}
			startDateTime, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
		}
		var calStartTime, calEndTime time.Time
		if currentDateTime.Before(startDateTime) {
			calStartTime = currentDateTime
			calEndTime = startDateTime
		} else {
			calStartTime = startDateTime
			calEndTime = currentDateTime
		}
		// 根据日期，获取数据
		for _, vv := range dataList {
			dataTimeT, _ := time.ParseInLocation(utils.FormatDate, vv.DataTime, time.Local)
			if (dataTimeT.After(calStartTime) && dataTimeT.Before(calEndTime)) ||
				dataTimeT.Equal(calStartTime) ||
				dataTimeT.Equal(calEndTime) {
				newDataList = append(newDataList, vv)
			}
		}
	}
	return
}

// HandleDataByCalculateType 根据计算公式处理数据
func HandleDataByCalculateType(originList []*data_manage.ChartRangeAnalysisDateDataItem, originDataList []*data_manage.EdbDataList, req *data_manage.ChartRangeAnalysisExtraConf) (newList []*data_manage.EdbDataList, err error) {
	if len(originList) == 0 {
		return
	}
	calculateType := req.CalculateType
	switch calculateType {
	case 0: //均值
		var sum float64
		if req.DateRangeType == 0 && req.AutoDateConf.IsAutoStartDate > 0 {
			for _, item := range originList {
				for _, v := range item.DataList {
					sum = 0
					//计算的数据返回需要重新确定
					calDataList, e := GetAutoCalculateDateDataList(v.DataTime, originDataList, req)
					if e != nil {
						err = fmt.Errorf("获取区间数据失败：%s", e.Error())
						return
					}
					for _, vv := range calDataList {
						sum += vv.Value
					}
					val := sum / float64(len(calDataList))
					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
					newList = append(newList, &data_manage.EdbDataList{
						DataTime:      v.DataTime,
						Value:         val,
						DataTimestamp: v.DataTimestamp,
					})
				}
			}
		} else {
			for _, item := range originList {
				sum = 0
				for k, v := range item.DataList {
					sum += v.Value
					val := sum / float64(k+1)
					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
					newList = append(newList, &data_manage.EdbDataList{
						DataTime:      v.DataTime,
						Value:         val,
						DataTimestamp: v.DataTimestamp,
					})
				}
			}
		}

	case 1: //累计值
		var sum float64
		if req.DateRangeType == 0 && req.AutoDateConf.IsAutoStartDate > 0 {
			for _, item := range originList {
				sum = 0
				for _, v := range item.DataList {
					sum = 0
					//计算的数据返回需要重新确定
					calDataList, e := GetAutoCalculateDateDataList(v.DataTime, originDataList, req)
					if e != nil {
						err = fmt.Errorf("获取区间数据失败：%s", e.Error())
						return
					}
					for _, vv := range calDataList {
						sum += vv.Value
					}
					val := sum
					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
					newList = append(newList, &data_manage.EdbDataList{
						DataTime:      v.DataTime,
						Value:         val,
						DataTimestamp: v.DataTimestamp,
					})
				}
			}
		} else {
			for _, item := range originList {
				sum = 0
				for _, v := range item.DataList {
					sum += v.Value
					val := sum
					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
					newList = append(newList, &data_manage.EdbDataList{
						DataTime:      v.DataTime,
						Value:         val,
						DataTimestamp: v.DataTimestamp,
					})
				}
			}
		}

	case 2: //涨幅
		if req.DateRangeType == 0 && req.AutoDateConf.IsAutoStartDate > 0 {
			for _, item := range originList {
				for _, v := range item.DataList {
					var baseVal float64
					//计算的数据返回需要重新确定
					calDataList, e := GetAutoCalculateDateDataList(v.DataTime, originDataList, req)
					if e != nil {
						err = fmt.Errorf("获取区间数据失败：%s", e.Error())
						return
					}
					if len(calDataList) == 0 {
						continue
					}
					baseVal = calDataList[0].Value
					baseDate := calDataList[0].DataTime
					if baseVal == 0 {
						continue
					}
					if v.DataTime == baseDate {
						continue
					}

					val := (v.Value - baseVal) / baseVal
					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
					newList = append(newList, &data_manage.EdbDataList{
						DataTime:      v.DataTime,
						Value:         val,
						DataTimestamp: v.DataTimestamp,
					})
				}
			}
		} else {
			for _, item := range originList {
				if len(item.DataList) == 0 {
					break
				}
				baseVal := item.DataList[0].Value
				baseDate := item.DataList[0].DataTime
				if baseVal == 0 {
					break
				}
				for _, v := range item.DataList {
					if v.DataTime == baseDate {
						continue
					}
					val := (v.Value - baseVal) / baseVal
					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
					newList = append(newList, &data_manage.EdbDataList{
						DataTime:      v.DataTime,
						Value:         val,
						DataTimestamp: v.DataTimestamp,
					})
				}
			}
		}
	case 3: //复合增长率
		if req.DateRangeType == 0 && req.AutoDateConf.IsAutoStartDate > 0 {
			for _, item := range originList {
				for _, v := range item.DataList {
					var baseVal float64
					var baseDate string
					calDataList, e := GetAutoCalculateDateDataList(v.DataTime, originDataList, req)
					if e != nil {
						err = fmt.Errorf("获取区间数据失败：%s", e.Error())
						return
					}
					if len(calDataList) == 0 {
						continue
					}
					baseVal = calDataList[0].Value
					baseDate = calDataList[0].DataTime
					if v.DataTime == baseDate {
						continue
					}
					if baseVal == 0 {
						continue
					}

					baseDateT, e := time.ParseInLocation(utils.FormatDate, baseDate, time.Local)
					if e != nil {
						err = fmt.Errorf("time.ParseInLocation err: %v", e)
						return
					}
					tmpT, e := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
					if e != nil {
						err = fmt.Errorf("time.ParseInLocation err: %v", e)
						return
					}
					// 计算两个日期相差的天数
					diff := tmpT.Sub(baseDateT).Hours() / 24 / 365
					val := v.Value / baseVal
					val = math.Pow(val, 1/diff) - 1
					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
					newList = append(newList, &data_manage.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
				}
			}
		} else {
			for _, item := range originList {
				if len(item.DataList) == 0 {
					break
				}
				baseVal := item.DataList[0].Value
				baseDate := item.DataList[0].DataTime
				if baseVal == 0 {
					break
				}
				for _, v := range item.DataList {
					if v.DataTime == baseDate {
						continue
					}
					baseDateT, e := time.ParseInLocation(utils.FormatDate, baseDate, time.Local)
					if e != nil {
						err = fmt.Errorf("time.ParseInLocation err: %v", e)
						return
					}
					tmpT, e := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
					if e != nil {
						err = fmt.Errorf("time.ParseInLocation err: %v", e)
						return
					}
					// 计算两个日期相差的天数
					diff := tmpT.Sub(baseDateT).Hours() / 24 / 365
					val := v.Value / baseVal
					val = math.Pow(val, 1/diff) - 1
					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
					newList = append(newList, &data_manage.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
				}
			}
		}
	case 4: //最大值
		var maxVal float64
		if req.DateRangeType == 0 && req.AutoDateConf.IsAutoStartDate > 0 {
			for _, item := range originList {
				for _, v := range item.DataList {
					calDataList, e := GetAutoCalculateDateDataList(v.DataTime, originDataList, req)
					if e != nil {
						err = fmt.Errorf("获取区间数据失败：%s", e.Error())
						return
					}
					for kk, vv := range calDataList {
						if kk == 0 {
							maxVal = vv.Value
						}
						if vv.Value > maxVal {
							maxVal = vv.Value
						}
					}

					val := maxVal
					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
					newList = append(newList, &data_manage.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
				}
			}
		} else {
			for _, item := range originList {
				for k, v := range item.DataList {
					if k == 0 {
						maxVal = v.Value
					}
					if v.Value > maxVal {
						maxVal = v.Value
					}
					val := maxVal
					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
					newList = append(newList, &data_manage.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
				}
			}
		}
	case 5: //最小值
		var minVal float64
		if req.DateRangeType == 0 && req.AutoDateConf.IsAutoStartDate > 0 {
			for _, item := range originList {
				for _, v := range item.DataList {
					calDataList, e := GetAutoCalculateDateDataList(v.DataTime, originDataList, req)
					if e != nil {
						err = fmt.Errorf("获取区间数据失败：%s", e.Error())
						return
					}
					for kk, vv := range calDataList {
						if kk == 0 {
							minVal = vv.Value
						}
						if vv.Value < minVal {
							minVal = vv.Value
						}
					}
					val := minVal
					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
					newList = append(newList, &data_manage.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
				}
			}
		} else {
			for _, item := range originList {
				for k, v := range item.DataList {
					if k == 0 {
						minVal = v.Value
					}
					if v.Value < minVal {
						minVal = v.Value
					}
					val := minVal
					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
					newList = append(newList, &data_manage.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
				}
			}
		}
	}

	return
}

// GetChartEdbInfoFormat 区间计算图表-获取指标信息
func GetChartEdbInfoFormat(chartInfoId int, edbInfoMappingList []*data_manage.ChartEdbInfoMapping) (edbList []*data_manage.ChartEdbInfoMapping, err error) {
	edbList = make([]*data_manage.ChartEdbInfoMapping, 0)
	for _, edbInfoMapping := range edbInfoMappingList {
		if edbInfoMapping == nil {
			err = fmt.Errorf("指标信息有误")
			return
		}

		edbInfoMapping.FrequencyEn = data.GetFrequencyEn(edbInfoMapping.Frequency)
		if edbInfoMapping.Unit == `无` {
			edbInfoMapping.Unit = ``
		}
		if chartInfoId <= 0 {
			edbInfoMapping.IsAxis = 1
			edbInfoMapping.LeadValue = 0
			edbInfoMapping.LeadUnit = ""
			edbInfoMapping.ChartEdbMappingId = 0
			edbInfoMapping.ChartInfoId = 0
			edbInfoMapping.IsOrder = false
			edbInfoMapping.EdbInfoType = 1
			edbInfoMapping.ChartStyle = ""
			edbInfoMapping.ChartColor = ""
			edbInfoMapping.ChartWidth = 0
		} else {
			edbInfoMapping.LeadUnitEn = data.GetLeadUnitEn(edbInfoMapping.LeadUnit)
		}
		edbList = append(edbList, edbInfoMapping)
	}
	return
}

// GetChartDataByEdbInfoList 区间计算图表-根据指标信息获取x轴和y轴
func GetChartDataByEdbInfoList(chartInfoId int, dateType, startYear int, startDate, endDate string, edbInfoMappingList []*data_manage.ChartEdbInfoMapping, req *data_manage.ChartRangeAnalysisExtraConf) (edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, dataResp data_manage.ChartRangeAnalysisDataResp, err error) {
	if chartInfoId > 0 && req.EdbInfoMode == 1 {
		edbList, xEdbIdValue, dataResp, err = GetChartDataByEdbInfoListBySeries(chartInfoId, dateType, startYear, startDate, endDate, edbInfoMappingList, req)
		return
	}
	for _, edbInfoMapping := range edbInfoMappingList {
		edbInfoMapping, err = getChartDataByEdbInfo(edbInfoMapping, req)
		if err != nil {
			return
		}
		edbInfoMapping.ConvertUnit = edbInfoMapping.Unit
		edbInfoMapping.ConvertEnUnit = edbInfoMapping.UnitEn
		if req.CalculateType == 2 || req.CalculateType == 3 {
			edbInfoMapping.ConvertUnit = "无"
			edbInfoMapping.ConvertEnUnit = "无"
		}
		if req.DataConvertType > 0 && req.DataConvertConf.Unit != "" {
			edbInfoMapping.ConvertUnit = req.DataConvertConf.Unit
			edbInfoMapping.ConvertEnUnit = req.DataConvertConf.Unit
		}
		if edbInfoMapping.ConvertUnit == "无" {
			edbInfoMapping.ConvertUnit = ""
		}
		if edbInfoMapping.ConvertEnUnit == "无" {
			edbInfoMapping.ConvertEnUnit = ""
		}
		dataList := edbInfoMapping.DataList.([]*data_manage.EdbDataList)
		// 处理上下限
		var maxData, minData float64
		if len(dataList) > 0 {
			maxData = dataList[0].Value
			minData = dataList[0].Value
			for _, v := range dataList {
				if v.Value > maxData {
					maxData = v.Value
				}
				if v.Value < minData {
					minData = v.Value
				}
			}
		}
		edbInfoMapping.MaxData = maxData
		edbInfoMapping.MinData = minData
		xEdbIdValue = append(xEdbIdValue, edbInfoMapping.EdbInfoId)
	}
	//根据时间类型来筛选最终的数据
	yearMax := 0
	if dateType == utils.DateTypeNYears {
		for _, v := range edbInfoMappingList {
			dataList := v.DataList.([]*data_manage.EdbDataList)
			if len(dataList) > 0 {
				latestDate := dataList[len(dataList)-1].DataTime
				if latestDate != "" {
					lastDateT, tErr := time.Parse(utils.FormatDate, latestDate)
					if tErr != nil {
						err = fmt.Errorf("获取图表日期信息失败，Err:" + tErr.Error())
						return
					}
					if lastDateT.Year() > yearMax {
						yearMax = lastDateT.Year()
					}
				}
			}
		}
	}
	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, yearMax)

	if startDate != "" {
		for k, v := range edbInfoMappingList {
			var maxData, minData float64
			dataList := v.DataList.([]*data_manage.EdbDataList)
			newDataList := make([]*data_manage.EdbDataList, 0)
			if len(dataList) == 0 {
				newDataList = dataList
			} else {
				firstFlag := true
				for _, d := range dataList {
					if endDate != "" && d.DataTime > endDate {
						continue
					}
					if d.DataTime < startDate {
						continue
					}
					newDataList = append(newDataList, d)
					if firstFlag {
						maxData = d.Value
						minData = d.Value
						firstFlag = false
					} else {
						if d.Value > maxData {
							maxData = d.Value
						}
						if d.Value < minData {
							minData = d.Value
						}
					}
				}
			}
			edbInfoMappingList[k].DataList = newDataList
			edbInfoMappingList[k].MinData = minData
			edbInfoMappingList[k].MaxData = maxData
		}
	}
	dataResp = data_manage.ChartRangeAnalysisDataResp{ChartRangeAnalysisExtraConf: req}
	if req.MultipleGraphConfigId > 0 {
		multipleGraphConfigEdbMappingList, e := data_manage.GetMultipleGraphConfigEdbMappingListByIdAndSource(req.MultipleGraphConfigId, utils.CHART_SOURCE_RANGE_ANALYSIS)
		if e != nil && e.Error() != utils.ErrNoRow() {
			err = fmt.Errorf("获取区间计算图表, 指标信息失败, Err:" + e.Error())
			return
		}
		// 查询是否已经生成指标
		dataResp.ConfigEdbNum = len(multipleGraphConfigEdbMappingList)
	}
	edbList, err = GetChartEdbInfoFormat(chartInfoId, edbInfoMappingList)
	if err != nil {
		err = fmt.Errorf("获取区间计算图表, 完善指标信息失败, Err:" + err.Error())
		return
	}
	return
}

func GetChartDataByEdbInfoListBySeries(chartInfoId int, dateType, startYear int, startDate, endDate string, edbInfoMappingList []*data_manage.ChartEdbInfoMapping, req *data_manage.ChartRangeAnalysisExtraConf) (edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, dataResp data_manage.ChartRangeAnalysisDataResp, err error) {
	//查询seriesId
	chartSeriesOb := new(data_manage.FactorEdbSeriesChartMapping)
	seriesMappingItem, err := chartSeriesOb.GetItemByChartInfoId(chartInfoId)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = fmt.Errorf("图表关联关系不存在")
			return
		} else {
			err = fmt.Errorf("获取图表关联失败, Err: " + err.Error())
			return
		}
	}
	//根据seriesId查询数据
	//并把数据放到dataList中
	for _, edbInfoMapping := range edbInfoMappingList {
		dataOb := new(data_manage.FactorEdbSeriesCalculateDataQjjs)
		dataList, e := dataOb.GetEdbDataList(seriesMappingItem.FactorEdbSeriesId, edbInfoMapping.EdbInfoId, startDate, endDate)
		if e != nil {
			err = e
			return
		}
		edbInfoMapping.ConvertUnit = edbInfoMapping.Unit
		edbInfoMapping.ConvertEnUnit = edbInfoMapping.UnitEn
		if req.CalculateType == 2 || req.CalculateType == 3 {
			edbInfoMapping.ConvertUnit = "无"
			edbInfoMapping.ConvertEnUnit = "无"
		}
		if req.DataConvertType > 0 && req.DataConvertConf.Unit != "" {
			edbInfoMapping.ConvertUnit = req.DataConvertConf.Unit
			edbInfoMapping.ConvertEnUnit = req.DataConvertConf.Unit
		}
		if edbInfoMapping.ConvertUnit == "无" {
			edbInfoMapping.ConvertUnit = ""
		}
		if edbInfoMapping.ConvertEnUnit == "无" {
			edbInfoMapping.ConvertEnUnit = ""
		}
		edbInfoMapping.DataList = dataList
		// 处理上下限
		var maxData, minData float64
		if len(dataList) > 0 {
			maxData = dataList[0].Value
			minData = dataList[0].Value
			for _, v := range dataList {
				if v.Value > maxData {
					maxData = v.Value
				}
				if v.Value < minData {
					minData = v.Value
				}
			}
		}
		edbInfoMapping.MaxData = maxData
		edbInfoMapping.MinData = minData
		xEdbIdValue = append(xEdbIdValue, edbInfoMapping.EdbInfoId)
	}
	yearMax := 0
	if dateType == utils.DateTypeNYears {
		for _, v := range edbInfoMappingList {
			dataList := v.DataList.([]*data_manage.EdbDataList)
			latestDate := dataList[len(dataList)-1].DataTime
			if latestDate != "" {
				lastDateT, tErr := time.Parse(utils.FormatDate, latestDate)
				if tErr != nil {
					err = fmt.Errorf("获取图表日期信息失败，Err:" + tErr.Error())
					return
				}
				if lastDateT.Year() > yearMax {
					yearMax = lastDateT.Year()
				}
			}
		}
	}
	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, yearMax)

	if startDate != "" {
		for k, v := range edbInfoMappingList {
			var maxData, minData float64
			dataList := v.DataList.([]*data_manage.EdbDataList)
			newDataList := make([]*data_manage.EdbDataList, 0)
			if len(dataList) == 0 {
				newDataList = dataList
			} else {
				firstFlag := true
				for _, d := range dataList {
					if endDate != "" && d.DataTime > endDate {
						continue
					}
					if d.DataTime < startDate {
						continue
					}
					newDataList = append(newDataList, d)
					if firstFlag {
						maxData = d.Value
						minData = d.Value
						firstFlag = false
					} else {
						if d.Value > maxData {
							maxData = d.Value
						}
						if d.Value < minData {
							minData = d.Value
						}
					}
				}
			}
			edbInfoMappingList[k].DataList = newDataList
			edbInfoMappingList[k].MinData = minData
			edbInfoMappingList[k].MaxData = maxData
		}
	}
	dataResp = data_manage.ChartRangeAnalysisDataResp{ChartRangeAnalysisExtraConf: req, SeriesId: seriesMappingItem.FactorEdbSeriesId}
	// 查询配置关联关系
	if req.MultipleGraphConfigId > 0 {
		multipleGraphConfigEdbMappingList, e := data_manage.GetMultipleGraphConfigEdbMappingListByIdAndSource(req.MultipleGraphConfigId, utils.CHART_SOURCE_RANGE_ANALYSIS)
		if e != nil && e.Error() != utils.ErrNoRow() {
			err = fmt.Errorf("获取区间计算图表, 指标信息失败, Err:" + e.Error())
			return
		}
		// 查询是否已经生成指标
		dataResp.ConfigEdbNum = len(multipleGraphConfigEdbMappingList)
	}

	edbList, err = GetChartEdbInfoFormat(chartInfoId, edbInfoMappingList)
	if err != nil {
		err = fmt.Errorf("获取区间计算图表, 完善指标信息失败, Err:" + err.Error())
		return
	}
	return
}

// getChartDataByEdbInfo 区间计算图表-根据指标信息获取x轴和y轴
func getChartDataByEdbInfo(edbInfoMapping *data_manage.ChartEdbInfoMapping, req *data_manage.ChartRangeAnalysisExtraConf) (newEdbInfoMapping *data_manage.ChartEdbInfoMapping, err error) {
	newEdbInfoMapping = edbInfoMapping
	// 指标的开始日期和结束日期
	edbStartDateTime, _ := time.ParseInLocation(utils.FormatDate, edbInfoMapping.StartDate, time.Local)
	//edbStartDate := edbStartDateTime.AddDate(0, 0, 1).Format(utils.FormatDate)
	edbEndDateTime, _ := time.ParseInLocation(utils.FormatDate, edbInfoMapping.EndDate, time.Local)
	edbEndDate := edbEndDateTime.Format(utils.FormatDate)

	// 获取时间基准指标在时间区间内的值
	dataList := make([]*data_manage.EdbDataList, 0)
	switch edbInfoMapping.EdbInfoCategoryType {
	case 0:
		dataList, err = data_manage.GetEdbDataList(edbInfoMapping.Source, edbInfoMapping.SubSource, edbInfoMapping.EdbInfoId, "", "")
	case 1:
		_, dataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfoMapping.EdbInfoId, "", "", false)
	default:
		err = errors.New("指标base类型异常")
		return
	}
	/*var dataList data_manage.SortEdbDataList
	dataList = dataListTmp
	ascDataList := dataListTmp
	sort.Sort(dataList)*/
	dateList := make([]*data_manage.ChartRangeAnalysisDateDataItem, 0)
	switch req.DateRangeType {
	case 0:
		// 智能划分得到一个开始日期，和结束日期
		var startDateTime, endDateTime time.Time
		startDateTime = edbStartDateTime
		if req.AutoDateConf.IsAutoStartDate == 0 { //固定设置
			startDate := req.AutoDateConf.StartDate
			if startDate == "" {
				startDate = "2020-01-01"
			}
			startDateTime, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
		} /*else {
			startConf := req.AutoDateConf.StartDateConf
			startDate := ""
			if startConf.BaseDateType == 0 { //
				startDate = edbEndDate
			} else if startConf.BaseDateType == 1 {
				startDate = time.Now().Format(utils.FormatDate)
			}
			if startConf.MoveForward > 0 {
				startDate = GetEdbDateByMoveForward(startConf.MoveForward, dataList)
			}
			if len(startConf.DateChange) > 0 {
				startDate, err = HandleEdbDateChange(startDate, startConf.DateChange)
				if err != nil {
					err = fmt.Errorf("智能划分开始日期处理失败：%s", err.Error())
					return
				}
			}
			startDateTime, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
		}*/

		if req.AutoDateConf.IsAutoEndDate == 0 { //固定设置
			endDate := req.AutoDateConf.EndDate
			if endDate == "" {
				err = fmt.Errorf("智能划分截止日期处理失败：请输入截止日期")
				return
			}
			// todo 如果截止日期比指标日期还要大，则用指标的最新日期
			endDateTime, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
		} else {
			endConf := req.AutoDateConf.EndDateConf
			endDate := edbEndDate
			if endConf.MoveForward > 0 {
				endDate = GetEdbDateByMoveForward(endDate, endConf.MoveForward, dataList)
			}
			if len(endConf.DateChange) > 0 {
				endDate, err = HandleEdbDateChange(endDate, endConf.DateChange)
				if err != nil {
					err = fmt.Errorf("智能划分结束日期处理失败：%s", err.Error())
					return
				}
			}
			endDateTime, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
		}

		dateList = append(dateList, &data_manage.ChartRangeAnalysisDateDataItem{
			StartDate: startDateTime,
			EndDate:   endDateTime})
	case 1:
		// 手工划分得到多个开始日期和结束日期（已排序）
		for _, v := range req.ManualDateConf {
			startDateT, _ := time.ParseInLocation(utils.FormatDate, v.StartDate, time.Local)
			endDateT, _ := time.ParseInLocation(utils.FormatDate, v.EndDate, time.Local)
			tmp := &data_manage.ChartRangeAnalysisDateDataItem{
				StartDate: startDateT,
				EndDate:   endDateT,
			}
			dateList = append(dateList, tmp)
		}
	case 2:
		// 跨年划分得到多个开始日期和结束日期
		startYear := edbStartDateTime.Year()
		endYear := edbEndDateTime.Year()
		startDay := req.YearDateConf.StartDay
		endDay := req.YearDateConf.EndDay
		for year := startYear; year <= endYear; year++ {
			startDate := fmt.Sprintf("%d-%s", year, startDay)
			endDate := fmt.Sprintf("%d-%s", year+1, endDay)
			startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
			endDateTime, _ := time.ParseInLocation(utils.FormatDate, endDate, time.Local)
			if startDateTime.Before(edbStartDateTime) {
				break
			}

			tmp := &data_manage.ChartRangeAnalysisDateDataItem{
				StartDate: startDateTime,
				EndDate:   endDateTime,
			}
			dateList = append(dateList, tmp)
		}
	}
	// 根据日期，获取数据
	for _, v := range dateList {
		for _, vv := range dataList {
			dataTimeT, _ := time.ParseInLocation(utils.FormatDate, vv.DataTime, time.Local)
			if dataTimeT.After(v.StartDate) && dataTimeT.Before(v.EndDate) ||
				dataTimeT.Equal(v.StartDate) ||
				dataTimeT.Equal(v.EndDate) {
				v.DataList = append(v.DataList, vv)
			}
		}
	}
	// 根据时间区间类型来获取数据的计算窗口，然后再拼接成整段数据
	newDataList, err := HandleDataByCalculateType(dateList, dataList, req)
	if err != nil {
		return
	}
	if req.UnNormalDataDealType > 0 {
		switch req.UnNormalDataDealType { //0：不处理，1:剔除，2替换
		case 1:
			dealDataList := make([]*data_manage.EdbDataList, 0)
			for _, v := range newDataList {
				if !utils.CompareFloatByOpStrings(req.UnNormalDataConf.Formula, v.Value, req.UnNormalDataConf.Value) {
					dealDataList = append(dealDataList, v)
				}
			}
			newDataList = dealDataList
		case 2:
			for i, v := range newDataList {
				if utils.CompareFloatByOpStrings(req.UnNormalDataConf.Formula, v.Value, req.UnNormalDataConf.Value) {
					newDataList[i].Value = req.UnNormalDataConf.ReplaceValue
				}
			}
		}
	}

	if req.DataConvertType > 0 {
		// 数据转换类型 0不转, 1乘 2除 3对数
		switch req.DataConvertType {
		case 1:
			for i, v := range newDataList {
				val := v.Value * req.DataConvertConf.Value
				val, _ = decimal.NewFromFloat(val).Round(4).Float64()
				newDataList[i].Value = val
			}
			//item.MaxData = item.MaxData * v.ConvertValue
			//item.MinData = item.MinData * v.ConvertValue
		case 2:
			for i, v := range newDataList {
				val := v.Value / req.DataConvertConf.Value
				val, _ = decimal.NewFromFloat(val).Round(4).Float64()
				newDataList[i].Value = val
			}
			//item.MaxData = item.MaxData / v.ConvertValue
			//item.MinData = item.MinData / v.ConvertValue
		case 3:
			for i, v := range newDataList {
				if v.Value <= 0 {
					err = errors.New("数据中含有负数或0，无法对数运算")
					return
				}
				val := math.Log(v.Value) / math.Log(req.DataConvertConf.Value)
				val, _ = decimal.NewFromFloat(val).Round(4).Float64()
				newDataList[i].Value = val
			}
			//item.MaxData = math.Log(item.MaxData) / math.Log(v.ConvertValue)
			//item.MinData = math.Log(item.MinData) / math.Log(v.ConvertValue)
		}
	}
	newEdbInfoMapping.DataList = newDataList
	//时间处理

	return
}

// RollingCorrelationChartDataResp 滚动区间计算图表数据
type RollingCorrelationChartDataResp struct {
	MaxData             float64
	MinData             float64
	LatestDate          string `description:"真实数据的最后日期"`
	EdbInfoCategoryType int
	ChartColor          string
	ChartStyle          string
	PredictChartColor   string
	ChartType           int
	ChartWidth          int
	EdbName             string
	EdbNameEn           string
	Unit                string
	UnitEn              string
	IsAxis              int
	DataList            []data_manage.EdbDataList
}

// ChartInfoRefresh 图表刷新
func ChartInfoRefresh(chartInfoId int, uniqueCode string) (isAsync bool, err error) {
	var errMsg string
	defer func() {
		if err != nil {
			tips := fmt.Sprintf("CorrelationChartInfoRefresh: %s", errMsg)
			utils.FileLog.Info(tips)
			go alarm_msg.SendAlarmMsg(tips, 3)
		}
	}()
	var chartInfo *data_manage.ChartInfo
	if chartInfoId > 0 {
		chartInfo, err = data_manage.GetChartInfoById(chartInfoId)
		if err != nil {
			if err.Error() == utils.ErrNoRow() {
				errMsg = "图表已被删除，请刷新页面"
				err = errors.New(errMsg)
				return
			}
			errMsg = "获取图表信息失败"
			err = errors.New("获取图表信息失败,Err:" + err.Error())
			return
		}
	} else {
		chartInfo, err = data_manage.GetChartInfoByUniqueCode(uniqueCode)
		if err != nil {
			if err.Error() == utils.ErrNoRow() {
				errMsg = "图表已被删除，请刷新页面"
				err = errors.New(errMsg)
				return
			}
			errMsg = "获取图表信息失败"
			err = errors.New("获取图表信息失败,Err:" + err.Error())
			return
		}
	}

	// 1.刷新图表关联的指标
	mappings, e := data_manage.GetChartEdbMappingList(chartInfoId)
	if e != nil {
		utils.FileLog.Info(fmt.Sprintf("获取图表关联指标失败, err: %v", e))
		return
	}
	if len(mappings) == 0 {
		utils.FileLog.Info("图表无关联指标")
		return
	}
	var edbIds []int
	for _, v := range mappings {
		edbIds = append(edbIds, v.EdbInfoId)
	}
	if e, _ = data.EdbInfoRefreshAllFromBaseV3(edbIds, false, true, false); e != nil {
		utils.FileLog.Info(fmt.Sprintf("批量刷新指标失败, err: %v", e))
		return
	}

	// todo 重新计算
	// 区间计算图表配置校验
	var extraConfig data_manage.ChartRangeAnalysisExtraConf
	err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &extraConfig)
	if err != nil {
		errMsg = "配置信息错误"
		err = errors.New(errMsg + ", Err: " + err.Error())
		return
	}
	chartSeriesOb := new(data_manage.FactorEdbSeriesChartMapping)
	seriesMappingItem, err := chartSeriesOb.GetItemByChartInfoId(chartInfo.ChartInfoId)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = nil
		} else {
			err = fmt.Errorf("获取图表关联失败, Err: " + err.Error())
			return
		}
	} else {
		_, e = FactorEdbStepCalculateRange(seriesMappingItem.FactorEdbSeriesId, edbIds, extraConfig, true)
		if e != nil {
			err = fmt.Errorf("计算因子指标失败, Err: " + e.Error())
			return
		}
	}
	// 4.清除图表缓存
	key := utils.HZ_CHART_LIB_DETAIL + uniqueCode
	_ = utils.Rc.Delete(key)

	return
}

// CopyChartInfo 复制图表
func CopyChartInfo(classifyId int, chartName string, oldChartInfo *data_manage.ChartInfo, sysUser *system.Admin, lang string) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {
	isSendEmail = true
	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
	chartInfo = &data_manage.ChartInfo{
		ChartInfoId:     0,
		ChartName:       chartName,
		ChartClassifyId: classifyId,
		SysUserId:       sysUser.AdminId,
		SysUserRealName: sysUser.RealName,
		UniqueCode:      utils.MD5(utils.CHART_PREFIX + "_" + timestamp),
		CreateTime:      time.Now(),
		ModifyTime:      time.Now(),
		DateType:        oldChartInfo.DateType,
		StartDate:       oldChartInfo.StartDate,
		EndDate:         oldChartInfo.EndDate,
		IsSetName:       oldChartInfo.IsSetName,
		EdbInfoIds:      oldChartInfo.EdbInfoIds,
		ChartType:       oldChartInfo.ChartType,
		Calendar:        oldChartInfo.Calendar,
		SeasonStartDate: oldChartInfo.SeasonStartDate,
		SeasonEndDate:   oldChartInfo.SeasonEndDate,
		ChartImage:      oldChartInfo.ChartImage,
		BarConfig:       oldChartInfo.BarConfig,
		//Sort:     sort,
		LeftMin:           oldChartInfo.LeftMin,
		LeftMax:           oldChartInfo.LeftMax,
		RightMin:          oldChartInfo.RightMin,
		RightMax:          oldChartInfo.RightMax,
		Right2Min:         oldChartInfo.Right2Min,
		Right2Max:         oldChartInfo.Right2Max,
		Disabled:          oldChartInfo.Disabled,
		Source:            oldChartInfo.Source,
		ExtraConfig:       oldChartInfo.ExtraConfig,
		SeasonExtraConfig: oldChartInfo.SeasonExtraConfig,
		StartYear:         oldChartInfo.StartYear,
		Unit:              oldChartInfo.Unit,
		UnitEn:            oldChartInfo.UnitEn,
		ChartThemeId:      oldChartInfo.ChartThemeId,
		SourcesFrom:       oldChartInfo.SourcesFrom,
		Instructions:      oldChartInfo.Instructions,
		MarkersLines:      oldChartInfo.MarkersLines,
		MarkersAreas:      oldChartInfo.MarkersAreas,
	}
	newId, err := data_manage.AddChartInfo(chartInfo)
	if err != nil {
		err = fmt.Errorf("保存失败，Err:%s", err.Error())
		return
	}
	chartInfo.ChartInfoId = int(newId)
	edbInfoMappingList, err := data_manage.GetChartEdbMappingList(oldChartInfo.ChartInfoId)
	if err != nil {
		err = fmt.Errorf("获取图表，指标信息失败，Err:" + err.Error())
		return
	}
	// 添加图表与指标的关联关系
	edbInfoIdArr := make([]int, 0)
	{
		mapList := make([]*data_manage.ChartEdbMapping, 0)
		for _, v := range edbInfoMappingList {
			edbInfoIdArr = append(edbInfoIdArr, v.EdbInfoId)
			timestamp = strconv.FormatInt(time.Now().UnixNano(), 10)
			mapItem := &data_manage.ChartEdbMapping{
				//ChartEdbMappingId: 0,
				ChartInfoId:   chartInfo.ChartInfoId,
				EdbInfoId:     v.EdbInfoId,
				CreateTime:    time.Now(),
				ModifyTime:    time.Now(),
				UniqueCode:    utils.MD5(utils.CHART_PREFIX + "_" + timestamp),
				MaxData:       v.MaxData,
				MinData:       v.MinData,
				IsOrder:       v.IsOrder,
				IsAxis:        v.IsAxis,
				EdbInfoType:   v.EdbInfoType,
				LeadValue:     v.LeadValue,
				LeadUnit:      v.LeadUnit,
				ChartStyle:    v.ChartStyle,
				ChartColor:    v.ChartColor,
				ChartWidth:    v.ChartWidth,
				Source:        v.Source,
				EdbAliasName:  v.EdbAliasName,
				IsConvert:     v.IsConvert,
				ConvertType:   v.ConvertType,
				ConvertValue:  v.ConvertValue,
				ConvertUnit:   v.ConvertEnUnit,
				ConvertEnUnit: v.ConvertEnUnit,
			}
			mapList = append(mapList, mapItem)
		}
		err = data_manage.AddChartEdbMapping(mapList)
		if err != nil {
			err = fmt.Errorf("保存失败，Err:%s", err.Error())
			return
		}
	}
	// 添加系列和图表映射
	chartSeriesOb := new(data_manage.FactorEdbSeriesChartMapping)
	_, err = chartSeriesOb.GetItemByChartInfoId(oldChartInfo.ChartInfoId)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = nil
		} else {
			err = fmt.Errorf("获取图表关联失败, Err: " + err.Error())
			return
		}
	} else {
		// 新增指标系列
		// 区间计算图表配置校验
		var extraConfig data_manage.ChartRangeAnalysisExtraConf
		err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &extraConfig)
		if err != nil {
			errMsg = "配置信息错误"
			err = errors.New(errMsg + ", Err: " + err.Error())
			return
		}
		err = AddSeries(edbInfoIdArr, chartInfo.ChartInfoId, utils.CHART_SOURCE_RANGE_ANALYSIS, extraConfig, chartInfo.ExtraConfig)
		if err != nil {
			errMsg = "操作失败"
			err = errors.New("新增区间计算图表失败, Err: " + err.Error())
			return
		}
	}

	//添加es数据
	go data.EsAddOrEditChartInfo(chartInfo.ChartInfoId)

	return
}

/*
// CalculateCorrelation 计算区间计算-获取x轴和y轴
func CalculateCorrelation(leadValue int, leadUnit, frequencyA, frequencyB string, dataListA, dataListB []*data_manage.EdbDataList) (xEdbIdValue []int, yDataList []data_manage.YData, err error) {
	xData := make([]int, 0)
	yData := make([]float64, 0)
	if leadValue == 0 {
		xData = append(xData, 0)
	}
	if leadValue > 0 {
		leadMin := 0 - leadValue
		xLen := 2*leadValue + 1
		for i := 0; i < xLen; i++ {
			n := leadMin + i
			xData = append(xData, n)
		}
	}

	// 计算窗口，不包含第一天
	//startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
	//startDate = startDateTime.AddDate(0, 0, 1).Format(utils.FormatDate)

	//// 2023-03-02 时间序列始终以指标B为基准, 始终是A进行平移
	//baseEdbInfo := edbInfoMappingB
	//changeEdbInfo := edbInfoMappingA
	// 2023-03-17 时间序列始终以指标A为基准, 始终是B进行平移
	//baseEdbInfo := edbInfoMappingA
	//changeEdbInfo := edbInfoMappingB

	// 获取时间基准指标在时间区间内的值
	//aDataList := make([]*data_manage.EdbDataList, 0)
	//switch baseEdbInfo.EdbInfoCategoryType {
	//case 0:
	//	aDataList, err = data_manage.GetEdbDataList(baseEdbInfo.Source, baseEdbInfo.SubSource, baseEdbInfo.EdbInfoId, startDate, endDate)
	//case 1:
	//	_, aDataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(baseEdbInfo.EdbInfoId, startDate, endDate, false)
	//default:
	//	err = errors.New("指标base类型异常")
	//	return
	//}
	//
	//// 获取变频指标所有日期的值, 插值法完善数据
	//bDataList := make([]*data_manage.EdbDataList, 0)
	//switch changeEdbInfo.EdbInfoCategoryType {
	//case 0:
	//	bDataList, err = data_manage.GetEdbDataList(changeEdbInfo.Source, changeEdbInfo.SubSource, changeEdbInfo.EdbInfoId, "", "")
	//case 1:
	//	_, bDataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(changeEdbInfo.EdbInfoId, "", "", false)
	//default:
	//	err = errors.New("指标change类型异常")
	//	return
	//}
	//changeDataMap := make(map[string]float64)
	//newChangeDataList, e := HandleDataByLinearRegression(bDataList, changeDataMap)
	//if e != nil {
	//	err = fmt.Errorf("获取变频指标插值法Map失败, Err: %s", e.Error())
	//	return
	//}

	// 2023-03-17 时间序列始终以指标A为基准, 始终是B进行平移
	baseDataList := make([]*data_manage.EdbDataList, 0)
	baseDataMap := make(map[string]float64)
	changeDataList := make([]*data_manage.EdbDataList, 0)
	changeDataMap := make(map[string]float64)

	// 先把低频指标升频为高频
	{
		frequencyIntMap := map[string]int{
			"日度": 1,
			"周度": 2,
			"旬度": 3,
			"月度": 4,
			"季度": 5,
			"年度": 6,
		}

		// 如果A指标是高频，那么就需要对B指标进行升频
		if frequencyIntMap[frequencyA] < frequencyIntMap[frequencyB] {
			tmpNewChangeDataList, e := HandleDataByLinearRegression(dataListB, changeDataMap)
			if e != nil {
				err = fmt.Errorf("获取变频指标插值法Map失败, Err: %s", e.Error())
				return
			}
			changeDataList = tmpNewChangeDataList
			baseDataList = dataListA
			for _, v := range baseDataList {
				baseDataMap[v.DataTime] = v.Value
			}

		} else if frequencyIntMap[frequencyA] > frequencyIntMap[frequencyB] {
			// 如果B指标是高频，那么就需要对A指标进行升频
			tmpNewChangeDataList, e := HandleDataByLinearRegression(dataListA, baseDataMap)
			if e != nil {
				err = fmt.Errorf("获取变频指标插值法Map失败, Err: %s", e.Error())
				return
			}
			baseDataList = tmpNewChangeDataList

			changeDataList = dataListB
			for _, v := range changeDataList {
				changeDataMap[v.DataTime] = v.Value
			}
		} else {
			baseDataList = dataListA
			for _, v := range baseDataList {
				baseDataMap[v.DataTime] = v.Value
			}
			changeDataList = dataListB
			for _, v := range changeDataList {
				changeDataMap[v.DataTime] = v.Value
			}
		}

	}

	// 计算不领先也不滞后时的相关系数
	baseCalculateData := make([]float64, 0)
	baseDataTimeArr := make([]string, 0)
	for i := range baseDataList {
		baseDataTimeArr = append(baseDataTimeArr, baseDataList[i].DataTime)
		baseCalculateData = append(baseCalculateData, baseDataList[i].Value)
	}

	//zeroBaseData := make([]float64, 0)
	//zeroCalculateData := make([]float64, 0)
	//for i := range baseDataTimeArr {
	//	tmpBaseVal, ok1 := baseDataMap[baseDataTimeArr[i]]
	//	tmpCalculateVal, ok2 := changeDataMap[baseDataTimeArr[i]]
	//	if ok1 && ok2 {
	//		zeroBaseData = append(zeroBaseData, tmpBaseVal)
	//		zeroCalculateData = append(zeroCalculateData, tmpCalculateVal)
	//	}
	//}
	//if len(zeroBaseData) != len(zeroCalculateData) {
	//	err = fmt.Errorf("相关系数两组序列元素数不一致, %d-%d", len(baseCalculateData), len(zeroCalculateData))
	//	return
	//}
	//zeroRatio := utils.CalculateCorrelationByIntArr(zeroBaseData, zeroCalculateData)
	//if leadValue == 0 {
	//	yData = append(yData, zeroRatio)
	//}

	// 计算领先/滞后N期
	if leadValue > 0 {
		// 平移变频指标领先/滞后的日期(单位天)
		moveUnitDays := utils.FrequencyDaysMap[leadUnit]

		for i := range xData {
			//if xData[i] == 0 {
			//	yData = append(yData, zeroRatio)
			//	continue
			//}
			xCalculateData := make([]float64, 0)
			yCalculateData := make([]float64, 0)

			// 平移指定天数
			mDays := int(moveUnitDays) * xData[i]
			_, dMap := MoveDataDaysToNewDataList(changeDataList, mDays)

			// 取出对应的基准日期的值
			for i2 := range baseDataTimeArr {
				tmpDate := baseDataTimeArr[i2]
				if yVal, ok := dMap[tmpDate]; ok {
					xCalculateData = append(xCalculateData, baseCalculateData[i2])
					yCalculateData = append(yCalculateData, yVal)
				}
			}
			if len(yCalculateData) <= 0 {
				//err = fmt.Errorf("领先滞后相关系数两组序列元素数不一致, %d-%d", len(baseCalculateData), len(yCalculateData))
				//return
				// 领先滞后后，没有可以计算的数据了
				continue
			}

			// 公式计算出领先/滞后频度对应点的区间计算系数
			ratio := utils.CalculateCorrelationByIntArr(xCalculateData, yCalculateData)
			yData = append(yData, ratio)
		}
	}

	xEdbIdValue = xData
	yDataList = make([]data_manage.YData, 0)
	yDate := "0000-00-00"
	yDataList = append(yDataList, data_manage.YData{
		Date:  yDate,
		Value: yData,
	})
	return
}

// GetFactorChartDataByChartId 获取多因子区间计算图表数据
func GetFactorChartDataByChartId(chartInfoId int, extraConfig string) (xEdbIdValue []int, yDataList []data_manage.YData, err error) {
	if chartInfoId <= 0 {
		return
	}
	// 指标对应的图例
	extra := new(data_manage.CorrelationChartInfoExtraConfig)
	if extraConfig != "" {
		if e := json.Unmarshal([]byte(extraConfig), extra); e != nil {
			err = fmt.Errorf("解析图表额外配置失败, err: %v", e)
			return
		}
	}
	legends := make(map[string]*data_manage.CorrelationChartLegend)
	if extra != nil {
		for _, v := range extra.LegendConfig {
			s := fmt.Sprintf("%d-%d", v.SeriesId, v.EdbInfoId)
			legends[s] = v
		}
	}

	// 获取图表引用到的系列指标
	chartMappingOb := new(data_manage.FactorEdbSeriesChartMapping)
	cond := fmt.Sprintf(" AND %s = ? AND %s = 1", chartMappingOb.Cols().ChartInfoId, chartMappingOb.Cols().EdbUsed)
	pars := make([]interface{}, 0)
	pars = append(pars, chartInfoId)
	chartMappings, e := chartMappingOb.GetItemsByCondition(cond, pars, []string{}, "")
	if e != nil {
		err = fmt.Errorf("获取图表引用系列指标失败")
		return
	}

	// 取出计算结果
	yDataList = make([]data_manage.YData, 0)
	yDate := "0000-00-00"
	for k, m := range chartMappings {
		var values []data_manage.FactorEdbSeriesCorrelationMatrixValues
		if m.CalculateData != "" {
			e = json.Unmarshal([]byte(m.CalculateData), &values)
			if e != nil {
				err = fmt.Errorf("系列指标计算数据有误, err: %v", e)
				return
			}
		}
		var y []float64
		for _, v := range values {
			if k == 0 {
				xEdbIdValue = append(xEdbIdValue, v.XData)
			}
			y = append(y, v.YData)
		}
		var yData data_manage.YData
		yData.Date = yDate
		yData.Value = y
		yData.SeriesEdb.SeriesId = m.FactorEdbSeriesId
		yData.SeriesEdb.EdbInfoId = m.EdbInfoId

		// 图例
		s := fmt.Sprintf("%d-%d", m.FactorEdbSeriesId, m.EdbInfoId)
		legend := legends[s]
		if legend != nil {
			yData.Name = legend.LegendName
			yData.Color = legend.Color
		}
		yDataList = append(yDataList, yData)
	}
	return
}

// FormatChartEdbInfoMappings 补充指标信息
func FormatChartEdbInfoMappings(chartInfoId int, mappings []*data_manage.ChartEdbInfoMapping) (edbList []*data_manage.ChartEdbInfoMapping, err error) {
	edbList = make([]*data_manage.ChartEdbInfoMapping, 0)
	if len(mappings) == 0 {
		return
	}

	for _, v := range mappings {
		if chartInfoId <= 0 {
			v.IsAxis = 1
			v.LeadValue = 0
			v.LeadUnit = ""
			v.ChartEdbMappingId = 0
			v.ChartInfoId = 0
			v.IsOrder = false
			v.EdbInfoType = 1
			v.ChartStyle = ""
			v.ChartColor = ""
			v.ChartWidth = 0
		} else {
			v.LeadUnitEn = data.GetLeadUnitEn(v.LeadUnit)
			v.LeadUnitEn = data.GetLeadUnitEn(v.LeadUnit)
		}
		v.FrequencyEn = data.GetFrequencyEn(v.Frequency)
		if v.Unit == `无` {
			v.Unit = ``
		}
		edbList = append(edbList, v)
	}
	return
}*/

func GetEdbDateByMoveForward(startDate string, moveForward int, edbDataList []*data_manage.EdbDataList) (date string) {
	// 根据日期进行排序
	index := 0
	length := len(edbDataList)
	for i := length - 1; i >= 0; i-- {
		item := edbDataList[i]
		if item.DataTime == startDate {
			index += 1
			continue
		}
		if index >= moveForward {
			date = item.DataTime
			break
		}
		if index > 0 {
			index += 1
			date = item.DataTime
		}
	}
	return
}

// HandleEdbDateChange 处理日期变换
func HandleEdbDateChange(date string, dateChange []*data_manage.EdbDataDateChangeConf) (newDate string, err error) {
	newDate = date
	if newDate != "" {
		if len(dateChange) > 0 {
			var dateTime time.Time
			dateTime, err = time.ParseInLocation(utils.FormatDate, newDate, time.Local)
			if err != nil {
				err = fmt.Errorf("日期解析失败: %s", err.Error())
				return
			}
			for _, v := range dateChange {
				if v.ChangeType == 1 {
					dateTime = dateTime.AddDate(v.Year, v.Month, v.Day)
					newDate = dateTime.Format(utils.FormatDate)
				} else if v.ChangeType == 2 {
					newDate, err, _ = utils.HandleSystemAppointDateT(dateTime, v.FrequencyDay, v.Frequency)
					if err != nil {
						return
					}
					dateTime, err = time.ParseInLocation(utils.FormatDate, newDate, time.Local)
					if err != nil {
						err = fmt.Errorf("日期解析失败: %s", err.Error())
						return
					}
				}
			}
		}
	}

	return
}

// 添加指标系列和数据
func AddSeries(edbInfoIds []int, chartInfoId, chartInfoSource int, extraConf data_manage.ChartRangeAnalysisExtraConf, calculatesJson string) (err error) {
	edbArr, e := data_manage.GetEdbInfoByIdList(edbInfoIds)
	if e != nil {
		err = fmt.Errorf("获取指标列表失败, Err: " + e.Error())
		return
	}
	if len(edbArr) == 0 {
		err = fmt.Errorf("获取指标列表失败, 指标不存在")
		return
	}
	edbInfoType := edbArr[0].EdbInfoType
	// 新增指标系列
	seriesItem := new(data_manage.FactorEdbSeries)
	seriesItem.SeriesName = extraConf.SeriesName
	seriesItem.EdbInfoType = edbInfoType
	seriesItem.CreateTime = time.Now().Local()
	seriesItem.ModifyTime = time.Now().Local()
	seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculating
	seriesItem.CalculateStep = calculatesJson
	mappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
	for _, v := range edbArr {
		mappings = append(mappings, &data_manage.FactorEdbSeriesMapping{
			EdbInfoId:  v.EdbInfoId,
			EdbCode:    v.EdbCode,
			CreateTime: time.Now().Local(),
			ModifyTime: time.Now().Local(),
		})
	}

	seriesId, e := seriesItem.CreateSeriesAndMapping(seriesItem, mappings)
	if e != nil {
		err = fmt.Errorf("新增因子指标系列失败, Err: " + e.Error())
		return
	}

	// 图表关联-此处添加的chart_info_id=0
	seriesChartMapping := new(data_manage.FactorEdbSeriesChartMapping)
	seriesChartMapping.CalculateType = data_manage.FactorEdbSeriesChartCalculateTypeRange
	//新增图表和指标的映射关系
	seriesChartMapping.CalculateData = ""
	seriesChartMapping.FactorEdbSeriesId = seriesId
	seriesChartMapping.ChartInfoId = chartInfoId
	seriesChartMapping.Source = chartInfoSource
	seriesChartMapping.CreateTime = time.Now().Local()
	seriesChartMapping.ModifyTime = time.Now().Local()

	if e = seriesChartMapping.Create(); e != nil {
		err = fmt.Errorf("新增图表关联失败, Err: " + e.Error())
		return
	}

	// todo 计算指标数据并存储
	_, e = FactorEdbStepCalculateRange(seriesId, edbInfoIds, extraConf, false)
	if e != nil {
		err = fmt.Errorf("计算因子指标失败, Err: " + e.Error())
		return
	}

	// 更新系列计算状态
	cols := []string{seriesItem.Cols().CalculateState, seriesItem.Cols().ModifyTime}
	seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculated
	seriesItem.ModifyTime = time.Now().Local()
	if e = seriesItem.Update(cols); e != nil {
		err = fmt.Errorf("更新因子指标系列计算状态失败, Err: " + e.Error())
		return
	}
	return
}

func EditSeries(seriesMapping *data_manage.FactorEdbSeriesChartMapping, edbInfoIds []int, extraConf data_manage.ChartRangeAnalysisExtraConf, calculatesJson string, recalculate bool) (err error) {
	seriesOb := new(data_manage.FactorEdbSeries)
	seriesItem, e := seriesOb.GetItemById(seriesMapping.FactorEdbSeriesId)
	if e != nil {
		if e.Error() == utils.ErrNoRow() {
			err = fmt.Errorf("因子指标系列不存在, Err: " + e.Error())
			return
		}
		err = fmt.Errorf("获取因子指标系列失败, Err: " + e.Error())
		return
	}

	edbArr, e := data_manage.GetEdbInfoByIdList(edbInfoIds)
	if e != nil {
		err = fmt.Errorf("获取指标列表失败, Err: " + e.Error())
		return
	}
	if len(edbArr) == 0 {
		err = fmt.Errorf("指标列表为空")
		return
	}
	var calculateResp data_manage.FactorEdbSeriesStepCalculateResp
	calculateResp.SeriesId = seriesItem.FactorEdbSeriesId

	// 如果不需要进行重新计算(比如只改了系列名称)那么只更新指标系列
	seriesItem.SeriesName = extraConf.SeriesName
	seriesItem.EdbInfoType = edbArr[0].EdbInfoType
	seriesItem.ModifyTime = time.Now().Local()
	updateCols := []string{seriesOb.Cols().SeriesName, seriesOb.Cols().EdbInfoType, seriesOb.Cols().ModifyTime}
	if !recalculate {
		if e = seriesItem.Update(updateCols); e != nil {
			err = fmt.Errorf("更新因子指标系列失败, Err: " + e.Error())
			return
		}
		return
	}

	// 更新系列信息和指标关联
	seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculating
	seriesItem.CalculateStep = calculatesJson
	updateCols = append(updateCols, seriesOb.Cols().CalculateState, seriesOb.Cols().CalculateStep)

	mappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
	for _, v := range edbArr {
		mappings = append(mappings, &data_manage.FactorEdbSeriesMapping{
			EdbInfoId:  v.EdbInfoId,
			EdbCode:    v.EdbCode,
			CreateTime: time.Now().Local(),
			ModifyTime: time.Now().Local(),
		})
	}
	if e = seriesItem.EditSeriesAndMapping(seriesItem, mappings, updateCols); e != nil {
		err = fmt.Errorf("更新因子指标系列信息失败, Err: %s", e.Error())
		return
	}

	// todo 重新计算
	_, e = FactorEdbStepCalculateRange(seriesItem.FactorEdbSeriesId, edbInfoIds, extraConf, false)
	if e != nil {
		err = fmt.Errorf("计算因子指标失败, Err: " + e.Error())
		return
	}

	// 更新系列计算状态
	cols := []string{seriesItem.Cols().CalculateState, seriesItem.Cols().ModifyTime}
	seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculated
	seriesItem.ModifyTime = time.Now().Local()
	if e = seriesItem.Update(cols); e != nil {
		err = fmt.Errorf("更新因子指标系列计算状态失败, Err: %s", e.Error())
		return
	}
	return
}

// FactorEdbStepCalculateRange 因子指标-区间计算
func FactorEdbStepCalculateRange(seriesId int, edbArr []int, extraConf data_manage.ChartRangeAnalysisExtraConf, recalculate bool) (calculateResp data_manage.FactorEdbSeriesStepCalculateResp, err error) {
	// todo 如果指标已保存，则用指标数据还是图表指标数据？
	// 获取图表x轴y轴
	defer func() {
		if err != nil {
			tips := fmt.Sprintf("StepCalculate计算失败, ErrMsg: %v", err)
			fmt.Println(tips)
			utils.FileLog.Info(tips)
			go alarm_msg.SendAlarmMsg(tips, 3)
		}
		/*if len(calculateResp.Fail) > 0 {
			tips := "StepCalculate计算失败, ErrMsg: "
			for _, f := range calculateResp.Fail {
				tips += fmt.Sprintf("code: %s, err: %s\n", f.EdbCode, f.ErrMsg)
			}
			fmt.Println(tips)
			utils.FileLog.Info(tips)
			go alarm_msg.SendAlarmMsg(tips, 2)
		}*/
	}()

	edbInfoMappingList, e := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbArr)
	if e != nil {
		err = fmt.Errorf("获取区间计算图表, A指标mapping信息失败, Err:%v", e)
		return
	}

	_, _, _, err = GetChartDataByEdbInfoList(0, 0, 0, "", "", edbInfoMappingList, &extraConf)
	if err != nil {
		err = fmt.Errorf("获取图表数据失败, ErrMsg: %v", err)
		return
	}

	// 重新计算-先清除原数据
	calculateDataOb := new(data_manage.FactorEdbSeriesCalculateDataQjjs)

	cond := fmt.Sprintf("%s = ?", calculateDataOb.Cols().FactorEdbSeriesId)
	pars := make([]interface{}, 0)
	pars = append(pars, seriesId)
	if e := calculateDataOb.RemoveByCondition(cond, pars); e != nil {
		err = fmt.Errorf("清除原数据失败, err: %v", e)
		return
	}

	// 计算成功的保存结果
	dataArr := make([]*data_manage.FactorEdbSeriesCalculateDataQjjs, 0)
	for _, v := range edbInfoMappingList {
		dataList := v.DataList.([]*data_manage.EdbDataList)
		for _, dataItem := range dataList {
			dataTime, _ := time.ParseInLocation(utils.FormatDate, dataItem.DataTime, time.Local)
			dataArr = append(dataArr, &data_manage.FactorEdbSeriesCalculateDataQjjs{
				FactorEdbSeriesId: seriesId,
				EdbInfoId:         v.EdbInfoId,
				EdbCode:           v.EdbCode,
				DataTime:          dataTime,
				Value:             dataItem.Value,
				CreateTime:        time.Now().Local(),
				ModifyTime:        time.Now().Local(),
				DataTimestamp:     dataItem.DataTimestamp,
			})
		}
	}
	if len(dataArr) == 0 {
		err = fmt.Errorf("计算结果无数据, seriesId: %d", seriesId)
		return
	}
	if e = calculateDataOb.CreateMulti(dataArr); e != nil {
		err = fmt.Errorf("保存计算结果失败, seriesId: %d, err: %v, ", seriesId, e)
		return
	}
	return
}

func CheckChartRangeExtraConfig(extraConfig data_manage.ChartRangeAnalysisExtraConf) (err error, errMsg string, isSendEmail bool) {
	extraConfig.SeriesName = strings.TrimSpace(extraConfig.SeriesName)
	if extraConfig.SeriesName == "" && extraConfig.EdbInfoMode == 1 {
		errMsg = "请输入指标系列名称"
		err = errors.New(errMsg)
		isSendEmail = false
		return
	}

	if extraConfig.CalculateType > 5 || extraConfig.CalculateType < 0 {
		errMsg = "计算方式参数错误"
		err = errors.New(errMsg)
		isSendEmail = false
		return
	}
	switch extraConfig.DateRangeType {
	case 0:
	case 1:
		if len(extraConfig.ManualDateConf) == 0 {
			errMsg = "请选择时间区间"
			err = errors.New(errMsg)
			return
		}
		// 先按开始时间排序
		sort.Sort(data_manage.ChartRangeAnalysisManualDateConfList(extraConfig.ManualDateConf))
		// 校验日期
		// 1.如果截止时间小于指标的截止日期，需要重置为指标的截止日期
		// 2.时间区间不能重叠
		for i := 1; i < len(extraConfig.ManualDateConf); i++ {
			start1, e := time.Parse(utils.FormatDate, extraConfig.ManualDateConf[i-1].EndDate)
			if e != nil {
				err = e
				errMsg = "截止日期格式有误"
				return
			}
			start2, e := time.Parse(utils.FormatDate, extraConfig.ManualDateConf[i].EndDate)
			if e != nil {
				err = e
				errMsg = "截止日期格式有误"
				return
			}

			start3, e := time.Parse(utils.FormatDate, extraConfig.ManualDateConf[i].StartDate)
			if e != nil {
				err = e
				errMsg = "截止日期格式有误"
				return
			}
			// 如果当前区间的开始时间小于等于前一个区间的结束时间，则存在重叠
			if !start2.After(start1) || start3.Before(start1) {
				errMsg = "日期区间存在重叠"
				return
			}
		}
		//如果截止时间大于指标的截止日期，需要重置为指标的截止日期
	case 2:
		if extraConfig.YearDateConf.StartDay == "" || extraConfig.YearDateConf.EndDay == "" {
			errMsg = "请选择时间区间"
			return
		}
		if _, e := time.Parse(utils.FormatMonthDay, extraConfig.YearDateConf.StartDay); e != nil {
			errMsg = "开始日期格式有误"
			return
		}
		if _, e := time.Parse(utils.FormatMonthDay, extraConfig.YearDateConf.EndDay); e != nil {
			errMsg = "结束日期格式有误"
			return
		}
	}
	return
}
