package future_good

import (
	"errors"
	"fmt"
	"github.com/shopspring/decimal"
	"hongze/hongze_yb/models/request"
	"hongze/hongze_yb/models/response/chart_info"
	chartEdbMappingModel "hongze/hongze_yb/models/tables/chart_edb_mapping"
	edbDataModel "hongze/hongze_yb/models/tables/edb_data"
	"hongze/hongze_yb/models/tables/future_good_edb_data"
	"hongze/hongze_yb/models/tables/future_good_edb_info"
	"hongze/hongze_yb/services/alarm_msg"
	"hongze/hongze_yb/services/chart"
	"hongze/hongze_yb/utils"
	"strconv"
	"time"
)

// GetChartEdbData 获取图表的指标数据
func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping, futureGoodEdbInfoMapping *chartEdbMappingModel.ChartEdbInfoMappingList, barChartInfoDateList []request.BarChartInfoDateReq, barChartInfoSort request.BarChartInfoSortReq) (barConfigEdbInfoIdList []request.BarChartInfoEdbItemReq, edbList []*chartEdbMappingModel.ChartEdbInfoMappingList, xEdbIdValue []int, xDataList []chart_info.XData, yDataList []chart_info.YData, sourceArr []string, err error) {
	edbList = make([]*chartEdbMappingModel.ChartEdbInfoMappingList, 0)

	sourceArr = make([]string, 0)
	if futureGoodEdbInfoMapping == nil {
		err = errors.New("商品指标未选取")
		return
	}
	if edbInfoMapping == nil {
		err = errors.New("ETA指标未选取")
		return
	}
	// 指标对应的所有数据
	edbDataListMap := make(map[int][]*edbDataModel.EdbDataList)

	item := new(chartEdbMappingModel.ChartEdbInfoMappingList)
	edbInfoMapping.FrequencyEn = chart.GetFrequencyEn(edbInfoMapping.Frequency)

	if edbInfoMapping.Unit == `无` {
		edbInfoMapping.Unit = ``
	}
	if futureGoodEdbInfoMapping.Unit == `无` {
		futureGoodEdbInfoMapping.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

		futureGoodEdbInfoMapping.IsAxis = 1
		futureGoodEdbInfoMapping.LeadValue = 0
		futureGoodEdbInfoMapping.LeadUnit = ""
		futureGoodEdbInfoMapping.ChartEdbMappingId = 0
		futureGoodEdbInfoMapping.ChartInfoId = 0
		futureGoodEdbInfoMapping.IsOrder = false
		futureGoodEdbInfoMapping.EdbInfoType = 1
		futureGoodEdbInfoMapping.ChartStyle = ""
		futureGoodEdbInfoMapping.ChartColor = ""
		futureGoodEdbInfoMapping.ChartWidth = 0
	} else {
		edbInfoMapping.LeadUnitEn = chart.GetLeadUnitEn(edbInfoMapping.LeadUnit)
		futureGoodEdbInfoMapping.LeadUnitEn = chart.GetLeadUnitEn(futureGoodEdbInfoMapping.LeadUnit)
	}

	// 普通的指标数据
	{
		dataList := make([]*edbDataModel.EdbDataList, 0)

		dataList, err = edbDataModel.GetEdbDataList(edbInfoMapping.Source, edbInfoMapping.EdbInfoId, startDate, endDate)
		edbDataListMap[edbInfoMapping.EdbInfoId] = dataList
		item.DataList = dataList

		edbList = append(edbList, edbInfoMapping)

		barConfigEdbInfoIdList = append(barConfigEdbInfoIdList, request.BarChartInfoEdbItemReq{
			EdbInfoId: edbInfoMapping.EdbInfoId,
			//Name:      edbInfoMapping.EdbName,
			Name:   "现货价",
			NameEn: "Spot Price",
			Source: edbInfoMapping.Source,
		})

		if !utils.InArray(edbInfoMapping.Source, utils.SystemSourceList) { //来源于系统的指标，都展示为弘则研究
			if !utils.InArray(edbInfoMapping.SourceName, sourceArr) {
				sourceArr = append(sourceArr, edbInfoMapping.SourceName)
			}
		}
	}

	// 获取期货指标以及期货数据
	futureGoodEdbInfoList, err := future_good_edb_info.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfoMapping.EdbInfoId)
	if err != nil {
		return
	}

	futureGoodMappingList := make([]*chartEdbMappingModel.ChartEdbInfoMappingList, 0)
	for k, v := range futureGoodEdbInfoList {
		newMappingInfo := &chartEdbMappingModel.ChartEdbInfoMappingList{
			ChartEdbInfoMapping: chartEdbMappingModel.ChartEdbInfoMapping{
				EdbInfoId:           int(v.FutureGoodEdbInfoID),
				SourceName:          v.Exchange,
				Source:              utils.CHART_SOURCE_FUTURE_GOOD,
				EdbCode:             v.FutureGoodEdbCode,
				EdbName:             v.FutureGoodEdbName,
				EdbAliasName:        v.FutureGoodEdbName,
				EdbNameEn:           v.FutureGoodEdbNameEn,
				EdbType:             edbInfoMapping.EdbType,
				Frequency:           edbInfoMapping.Frequency,
				FrequencyEn:         edbInfoMapping.FrequencyEn,
				Unit:                edbInfoMapping.Unit,
				UnitEn:              edbInfoMapping.UnitEn,
				StartDate:           v.StartDate.Format(utils.FormatDateTime),
				EndDate:             v.EndDate.Format(utils.FormatDateTime),
				ModifyTime:          v.ModifyTime.Format(utils.FormatDateTime),
				ChartEdbMappingId:   int(v.FutureGoodEdbInfoID),
				ChartInfoId:         edbInfoMapping.ChartInfoId,
				MaxData:             v.MaxValue,
				MinData:             v.MinValue,
				IsOrder:             edbInfoMapping.IsOrder,
				IsAxis:              edbInfoMapping.IsAxis,
				EdbInfoType:         edbInfoMapping.EdbInfoType,
				EdbInfoCategoryType: edbInfoMapping.EdbInfoCategoryType,
				LeadValue:           edbInfoMapping.LeadValue,
				LeadUnit:            edbInfoMapping.LeadUnit,
				LeadUnitEn:          edbInfoMapping.LeadUnitEn,
				ChartStyle:          edbInfoMapping.ChartStyle,
				ChartColor:          edbInfoMapping.ChartColor,
				PredictChartColor:   edbInfoMapping.PredictChartColor,
				ChartWidth:          edbInfoMapping.ChartWidth,
				ChartType:           edbInfoMapping.ChartType,
				LatestDate:          v.LatestDate,
				LatestValue:         v.LatestValue,
				UniqueCode:          futureGoodEdbInfoMapping.UniqueCode + "1" + strconv.Itoa(k),
				MinValue:            v.MinValue,
				MaxValue:            v.MaxValue,
			},
			DataList:   nil,
			IsNullData: false,
		}
		futureGoodMappingList = append(futureGoodMappingList, newMappingInfo)

		barConfigEdbInfoIdList = append(barConfigEdbInfoIdList, request.BarChartInfoEdbItemReq{
			EdbInfoId: newMappingInfo.EdbInfoId,
			Name:      fmt.Sprint("M+", v.Month),
			NameEn:    fmt.Sprint("M+", v.Month),
			Source:    newMappingInfo.Source,
		})
	}

	// 获取数据
	for _, v := range futureGoodMappingList {
		dataList := make([]*edbDataModel.EdbDataList, 0)

		tmpDataList, tmpErr := future_good_edb_data.GetFutureGoodEdbDataListByDate(v.EdbInfoId, startDate, endDate)
		if tmpErr != nil {
			return
		}
		for _, tmpData := range tmpDataList {
			dataList = append(dataList, &edbDataModel.EdbDataList{
				EdbDataId:     int(tmpData.FutureGoodEdbDataID),
				EdbInfoId:     int(tmpData.FutureGoodEdbInfoID),
				DataTime:      tmpData.DataTime.Format(utils.FormatDate),
				DataTimestamp: tmpData.DataTimestamp,
				Value:         tmpData.Close,
			})
		}
		edbDataListMap[v.EdbInfoId] = dataList
		v.DataList = dataList
	}

	edbList = append(edbList, futureGoodMappingList...)
	xEdbIdValue, yDataList, err = BarChartData(edbList[0], futureGoodMappingList, edbDataListMap, barChartInfoDateList, barChartInfoSort)

	xDataList = []chart_info.XData{
		{
			Name:   "现货价",
			NameEn: "Spot Price",
		},
	}

	for i := 1; i <= 11; i++ {
		xDataList = append(xDataList, chart_info.XData{
			Name:   fmt.Sprint("M+", i),
			NameEn: fmt.Sprint("M+", i),
		})
	}

	return
}

// BarChartData 柱方图的数据处理
func BarChartData(edbInfoMapping *chartEdbMappingModel.ChartEdbInfoMappingList, futureGoodMappingList []*chartEdbMappingModel.ChartEdbInfoMappingList, edbDataListMap map[int][]*edbDataModel.EdbDataList, barChartInfoDateList []request.BarChartInfoDateReq, barChartInfoSort request.BarChartInfoSortReq) (edbIdList []int, yDataList []chart_info.YData, err error) {
	// 指标数据数组（10086:{"2022-12-02":100.01,"2022-12-01":102.3}）
	edbDataMap := make(map[int]map[string]float64)
	for edbInfoId, edbDataList := range edbDataListMap {
		edbDateData := make(map[string]float64)
		for _, edbData := range edbDataList {
			edbDateData[edbData.DataTime] = edbData.Value
		}
		edbDataMap[edbInfoId] = edbDateData
	}

	// edbIdList 指标展示顺序；x轴的指标顺序
	edbIdList = make([]int, 0)
	edbIdList = append(edbIdList, edbInfoMapping.EdbInfoId)
	if barChartInfoSort.Sort == 0 {
		for _, v := range futureGoodMappingList {
			edbIdList = append(edbIdList, v.EdbInfoId)
		}
	}

	//固定取螺纹期货主力合约的时间序列，最新值为该合约最新日期、N天前为该合约最新日期N天前
	rbzlInfo, err := future_good_edb_info.GetFutureGoodEdbInfoByCode("RBZL.SHF")
	if err != nil {
		return
	}
	// 最新日期是这个
	if rbzlInfo.EndDate.IsZero() {
		err = errors.New("日期异常")
		return
	}
	latestDateTime := rbzlInfo.EndDate

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

	for _, barChartInfoDate := range barChartInfoDateList {
		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列表

		// 现货指标
		realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, edbDataListMap[edbInfoMapping.EdbInfoId], edbDataMap[edbInfoMapping.EdbInfoId])
		if tmpErr != nil {
			err = tmpErr
			return
		}
		findDataList = append(findDataList, findDataValue)
		if isFind {
			maxDate = realDateTime
		} else {
			noDataIdList = append(noDataIdList, edbInfoMapping.EdbInfoId)
			noDataIdMap[edbInfoMapping.EdbInfoId] = edbInfoMapping.EdbInfoId
		}
		currMonth := findDateTime.Month() // 当前月份
		xEdbInfoIdList = append(xEdbInfoIdList, edbInfoMapping.EdbInfoId)

		// 当前月的后面月份合约的数据
		for i := currMonth; i < 12; i++ {
			futureGoodMapping := futureGoodMappingList[i] // 当前的期货指标
			tmpRealDateTime, tmpFindDataValue, tmpIsFind, tmpErr := GetNeedDateData(findDateTime, edbDataListMap[futureGoodMapping.EdbInfoId], edbDataMap[futureGoodMapping.EdbInfoId])
			if tmpErr != nil {
				err = tmpErr
				return
			}
			findDataList = append(findDataList, tmpFindDataValue)
			if tmpIsFind {
				if maxDate.IsZero() || maxDate.Before(tmpRealDateTime) {
					maxDate = tmpRealDateTime
				}
			} else {
				noDataIdList = append(noDataIdList, futureGoodMapping.EdbInfoId)
				noDataIdMap[futureGoodMapping.EdbInfoId] = futureGoodMapping.EdbInfoId
			}
			// 当前期货合约的指标
			xEdbInfoIdList = append(xEdbInfoIdList, futureGoodMapping.EdbInfoId)
		}

		// 当前月的前面月份合约的数据
		for i := 1; i < int(currMonth); i++ {
			futureGoodMapping := futureGoodMappingList[i-1] // 当前的期货指标
			tmpRealDateTime, tmpFindDataValue, tmpIsFind, tmpErr := GetNeedDateData(findDateTime, edbDataListMap[futureGoodMapping.EdbInfoId], edbDataMap[futureGoodMapping.EdbInfoId])
			if tmpErr != nil {
				err = tmpErr
				return
			}
			findDataList = append(findDataList, tmpFindDataValue)
			if tmpIsFind {
				if maxDate.IsZero() || maxDate.Before(tmpRealDateTime) {
					maxDate = tmpRealDateTime
				}
			} else {
				noDataIdList = append(noDataIdList, futureGoodMapping.EdbInfoId)
				noDataIdMap[futureGoodMapping.EdbInfoId] = futureGoodMapping.EdbInfoId
			}
			// 当前期货合约的指标
			xEdbInfoIdList = append(xEdbInfoIdList, futureGoodMapping.EdbInfoId)
		}

		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, chart_info.YData{
			Date:           yDate,
			Value:          findDataList,
			NoDataEdbList:  noDataIdList,
			XEdbInfoIdList: xEdbInfoIdList,
			Color:          barChartInfoDate.Color,
			Name:           yName,
			NameEn:         yNameEn,
		})
	}

	return
}

// GetNeedDateData 获取合约内需要的日期数据
func GetNeedDateData(needDateTime time.Time, dataList []*edbDataModel.EdbDataList, edbDataMap map[string]float64) (findDateTime time.Time, findDataValue float64, isFind bool, err error) {
	//dataList := edbDataListMap[edbInfoId] //指标的所有数据值
	if len(dataList) <= 0 {
		// 没有数据的指标id
		return
	}

	//最早的日期
	minDateTime, err := time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
	if err != nil {
		return
	}

	for tmpDateTime := needDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
		tmpDate := tmpDateTime.Format(utils.FormatDate)
		if tmpValue, ok := edbDataMap[tmpDate]; ok { //如果能找到数据，那么就返回
			// 数据为0,也直接返回,做无值处理
			if tmpValue == 0 {
				return
			}
			findDateTime, _ = time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
			findDataValue = tmpValue
			isFind = true
			return
		}
	}

	return
}

// FutureGoodChartInfoRefresh
// @author Roc
// @datetime 2023-2-2 18:44:46
// @description 商品价格曲线图表刷新
func FutureGoodChartInfoRefresh(chartInfoId int) (err error) {
	var errMsg string
	defer func() {
		if err != nil {
			go alarm_msg.SendAlarmMsg("ChartInfoRefresh:"+errMsg, 3)
			fmt.Println("ChartInfoRefresh Err:" + errMsg)
		}
	}()

	edbInfoMapping, err := chartEdbMappingModel.GetEtaEdbChartEdbMapping(chartInfoId)
	if err != nil {
		errMsg = "获取需要刷新的ETA指标失败:Err:" + err.Error()
		return
	}
	// 获取期货指标
	futureGoodEdbInfoMapping, err := chartEdbMappingModel.GetFutureGoodEdbChartEdbMapping(chartInfoId)
	if err != nil {
		errMsg = "获取需要刷新的商品期货指标失败:Err:" + err.Error()
		return
	}

	// 获取期货指标以及期货数据
	futureGoodEdbInfoList, err := future_good_edb_info.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfoMapping.EdbInfoId)
	if err != nil {
		return
	}

	// 批量刷新ETA指标
	err, _ = chart.EdbInfoRefreshAllFromBase([]int{edbInfoMapping.EdbInfoId}, false)
	if err != nil {
		return
	}

	// 批量刷新期货指标
	err = FutureGoodEdbInfoRefreshAllFromBase(futureGoodEdbInfoList, false)
	if err != nil {
		return
	}

	return
}
