package line_feature

import (
	"errors"
	"github.com/shopspring/decimal"
	"hongze/hongze_chart_lib/models"
	"hongze/hongze_chart_lib/models/data_manage/line_feature/response"
	"hongze/hongze_chart_lib/services/data"
	"hongze/hongze_chart_lib/utils"
	"time"
)

// GetStandardDeviationData 获取标准差图表的指标数据
func GetStandardDeviationData(chartInfoId int, startDate, endDate string, mappingInfo *models.ChartEdbInfoMapping, calculateValue int) (edbList []*models.ChartEdbInfoMapping, dataResp response.LineFeatureDataResp, err error, errMsg string) {
	edbList = make([]*models.ChartEdbInfoMapping, 0)

	// 指标对应的所有数据
	_, edbList, err = data.GetEdbDataMapList(chartInfoId, 1, `公历`, startDate, endDate, []*models.ChartEdbInfoMapping{mappingInfo})
	if err != nil {
		return
	}

	if len(edbList) != 1 {
		errMsg = `指标异常`
		err = errors.New(errMsg)
		return
	}

	edb := edbList[0]
	dataList := edb.DataList.([]*models.EdbDataList)
	newDataList := make([]models.EdbDataList, 0)
	lenData := len(dataList)

	var minVal, maxVal float64
	if lenData >= calculateValue {
		tmpDataList := make([]float64, 0)
		for _, tmpData := range dataList {
			tmpDataList = append(tmpDataList, tmpData.Value)
		}
		for i := calculateValue; i <= lenData; i++ {
			tmpV := utils.CalculateStandardDeviation(tmpDataList[i-calculateValue : i])
			tmpV, _ = decimal.NewFromFloat(tmpV).Round(4).Float64()
			newDataList = append(newDataList, models.EdbDataList{
				EdbDataId:     i,
				EdbInfoId:     edb.EdbInfoId,
				DataTime:      dataList[i-1].DataTime,
				DataTimestamp: dataList[i-1].DataTimestamp,
				Value:         tmpV,
			})
			if tmpV > maxVal {
				maxVal = tmpV
			}
			if tmpV < minVal {
				minVal = tmpV
			}
		}
	}

	dataResp = response.LineFeatureDataResp{
		MaxData:             maxVal,
		MinData:             minVal,
		LatestDate:          edb.LatestDate,
		EdbInfoCategoryType: edb.EdbInfoCategoryType,
		ChartColor:          `#00F`,
		ChartStyle:          `spline`,
		PredictChartColor:   `#00F`,
		ChartType:           0,
		ChartWidth:          3,
		EdbName:             "标准差",
		EdbNameEn:           "standard deviation",
		Unit:                edb.Unit,
		UnitEn:              edb.UnitEn,
		IsAxis:              1,
		DataList:            newDataList,
	}

	return
}

// GetPercentileData 获取百分位图表的指标数据
func GetPercentileData(chartInfoId int, startDate, endDate string, mappingInfo *models.ChartEdbInfoMapping, calculateValue int, calculateUnit string) (edbList []*models.ChartEdbInfoMapping, dataResp response.LineFeatureDataResp, err error, errMsg string) {
	edbList = make([]*models.ChartEdbInfoMapping, 0)
	moveUnitDays, ok := utils.FrequencyDaysMap[calculateUnit]
	if !ok {
		errMsg = `错误的周期`
		err = errors.New(errMsg)
		return
	}
	calculateDay := calculateValue * moveUnitDays
	// 指标对应的所有数据
	_, edbList, err = data.GetEdbDataMapList(chartInfoId, 1, `公历`, startDate, endDate, []*models.ChartEdbInfoMapping{mappingInfo})
	if err != nil {
		return
	}

	if len(edbList) != 1 {
		errMsg = `指标异常`
		err = errors.New(errMsg)
		return
	}

	edb := edbList[0]
	dataList := edb.DataList.([]*models.EdbDataList)
	newDataList := make([]models.EdbDataList, 0)

	var edbMinVal, edbMaxVal float64
	dataMap := make(map[time.Time]float64, 0)
	for _, tmpData := range dataList {
		currDateTime, _ := time.ParseInLocation(utils.FormatDate, tmpData.DataTime, time.Local)
		dataMap[currDateTime] = tmpData.Value
	}

	//百分位:对所选指标滚动地取对应时间长度的数据值,取最大值Max,最小值Min,计算Max-Min,百分位=(现值-Min)/(Max-Min),Max=Min时不予计算。
	for i, tmpData := range dataList {
		currDateTime, _ := time.ParseInLocation(utils.FormatDate, tmpData.DataTime, time.Local)
		maxVal := tmpData.Value
		minVal := tmpData.Value
		for k := 0; k < calculateDay; k++ {
			preVal, ok2 := dataMap[currDateTime.AddDate(0, 0, -k)]
			if ok2 {
				if preVal > maxVal {
					maxVal = preVal
				}
				if preVal < minVal {
					minVal = preVal
				}
			}
		}

		if maxVal == minVal {
			continue
		}
		//百分位=(现值-Min)/(Max-Min)
		tmpV := (tmpData.Value - minVal) / (maxVal - minVal) * 100
		tmpV, _ = decimal.NewFromFloat(tmpV).Round(4).Float64()
		newDataList = append(newDataList, models.EdbDataList{
			EdbDataId:     i,
			EdbInfoId:     edb.EdbInfoId,
			DataTime:      dataList[i].DataTime,
			DataTimestamp: dataList[i].DataTimestamp,
			Value:         tmpV,
		})

		if tmpV < edbMinVal {
			edbMinVal = tmpV
		}
		if tmpV > edbMaxVal {
			edbMaxVal = tmpV
		}
	}

	dataResp = response.LineFeatureDataResp{
		MaxData:             edbMaxVal,
		MinData:             edbMinVal,
		LatestDate:          edb.LatestDate,
		EdbInfoCategoryType: edb.EdbInfoCategoryType,
		ChartColor:          `#00F`,
		ChartStyle:          `spline`,
		PredictChartColor:   `#00F`,
		ChartType:           0,
		ChartWidth:          3,
		EdbName:             "百分位",
		EdbNameEn:           "percentile",
		Unit:                "%",
		UnitEn:              "%",
		IsAxis:              1,
		DataList:            newDataList,
	}

	return
}

// GetFrequencyDistributionData 获取频率分布的图表数据
func GetFrequencyDistributionData(chartInfoId int, mappingInfo *models.ChartEdbInfoMapping, dateType, stepVal int, startDate, endDate string) (edbList []*models.ChartEdbInfoMapping, dataResp response.FrequencyDistributionResp, err error, errMsg string) {
	XDataList := make([]float64, 0)
	// 频度
	Y1DataList := make([]response.FrequencyDistributionYData, 0)
	// 累计频率
	Y2DataList := make([]response.FrequencyDistributionYData, 0)
	edbList = make([]*models.ChartEdbInfoMapping, 0)

	// 指标对应的所有数据
	_, edbList, err = data.GetEdbDataMapList(chartInfoId, 1, `公历`, startDate, endDate, []*models.ChartEdbInfoMapping{mappingInfo})
	if err != nil {
		return
	}
	if len(edbList) != 1 {
		err = errors.New("指标异常")
		return
	}
	startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
	var endDateTime time.Time
	if endDate != `` {
		endDateTime, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
	}

	edb := edbList[0]
	dataList := edb.DataList.([]*models.EdbDataList)
	if len(dataList) <= 0 {
		return
	}

	// 非自定义
	if dateType != 8 {
		endDate = dataList[len(dataList)-1].DataTime
		endDateTime, err = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
		if err != nil {
			return
		}
		//日期类型:1:最近3月;2:最近6月;3:最近1年;4:最近2年;5:最近3年;6:最近5年;7:最近10年,8:自定义时间
		startDateTime = utils.GetDateByDateType2(dateType, endDateTime)
		startDate = startDateTime.Format(utils.FormatDate)

		newDataList := make([]*models.EdbDataList, 0)
		for _, v := range dataList {
			tmpDataTime, tmpErr := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			if tmpDataTime.Equal(startDateTime) || tmpDataTime.After(startDateTime) {
				newDataList = append(newDataList, v)
			}

		}
		dataList = newDataList
	}

	maxVal := dataList[0].Value
	minVal := dataList[0].Value
	dataValMap := make(map[float64]int)
	total := 0 // 数据总量
	for _, tmpData := range dataList {
		currDateTime, _ := time.ParseInLocation(utils.FormatDate, tmpData.DataTime, time.Local)
		if (currDateTime.Equal(startDateTime) || currDateTime.After(startDateTime)) && (endDateTime.IsZero() || currDateTime.Before(endDateTime)) {
			if maxVal < tmpData.Value {
				maxVal = tmpData.Value
			}
			if minVal > tmpData.Value {
				minVal = tmpData.Value
			}

			num, ok := dataValMap[tmpData.Value]
			if ok {
				dataValMap[tmpData.Value] = num + 1
			} else {
				dataValMap[tmpData.Value] = 1
			}
			total++
		}
	}

	if total <= 0 {
		errMsg = `没有数据`
		err = errors.New(errMsg)
		return
	}

	// 最大最小值 向上/下取整
	minVal = utils.GetFloorNewNum(minVal, 2)
	maxVal = utils.GetCeilNewNum(maxVal, 2)
	//间距
	spacing, _ := (decimal.NewFromFloat(maxVal).Sub(decimal.NewFromFloat(minVal))).Div(decimal.NewFromInt(int64(stepVal))).Float64()

	distributionDataNumMap := make(map[float64]int)
	for i := 1; i <= stepVal; i++ {
		tmpMinVal, _ := decimal.NewFromFloat(minVal).Add((decimal.NewFromFloat(spacing)).Mul(decimal.NewFromInt(int64(i - 1)))).Float64()
		tmpMaxVal, _ := decimal.NewFromFloat(minVal).Add((decimal.NewFromFloat(spacing)).Mul(decimal.NewFromInt(int64(i)))).Float64()
		XDataList = append(XDataList, tmpMinVal)
		distributionDataNumMap[tmpMinVal] = 0
		for tmpVal, num := range dataValMap {
			if tmpMinVal <= tmpVal {
				// 最后一期数据是要小于等于
				if i == stepVal {
					if tmpVal <= tmpMaxVal {
						distributionDataNumMap[tmpMinVal] += num
					}
				} else {
					if tmpVal < tmpMaxVal {
						distributionDataNumMap[tmpMinVal] += num
					}
				}
			}
		}
	}

	var minFrequency, maxFrequency float64
	tmpNum := 0
	for k, tmpMinVal := range XDataList {
		// 数量
		frequencyYNum := distributionDataNumMap[tmpMinVal]

		// 频率
		tmpFrequency, _ := decimal.NewFromInt(int64(frequencyYNum)).Div(decimal.NewFromInt(int64(total))).Mul(decimal.NewFromInt(100)).Round(4).Float64()
		Y1DataList = append(Y1DataList, response.FrequencyDistributionYData{
			X: tmpMinVal,
			Y: tmpFrequency,
		})
		if k == 0 {
			minFrequency = tmpFrequency
			maxFrequency = tmpFrequency
		} else {
			if tmpFrequency < minFrequency {
				minFrequency = tmpFrequency
			}
			if tmpFrequency > maxFrequency {
				maxFrequency = tmpFrequency
			}
		}

		// 累计数
		tmpNum += frequencyYNum
		// 累计频率
		tmpTotalFrequency, _ := decimal.NewFromInt(int64(tmpNum)).Div(decimal.NewFromInt(int64(total))).Mul(decimal.NewFromInt(100)).Round(4).Float64()
		Y2DataList = append(Y2DataList, response.FrequencyDistributionYData{
			X: tmpMinVal,
			Y: tmpTotalFrequency,
		})
	}

	newDataList := []response.FrequencyDistributionData{
		{
			Name:   "频率",
			NameEn: "Frequency",
			Unit:   "%",
			UnitEn: "%",
			Value:  Y1DataList,
			Color:  "#00F",
			IsAxis: 1,
		}, {
			Name:   "累计频率",
			NameEn: "Total Frequency",
			Unit:   "%",
			UnitEn: "%",
			Value:  Y2DataList,
			Color:  "#F00",
			IsAxis: 0,
		},
	}
	edbList[0].DataList = nil
	dataResp = response.FrequencyDistributionResp{
		LeftMinValue:  minFrequency,
		LeftMaxValue:  maxFrequency,
		RightMinValue: 0,
		RightMaxValue: 100,
		DataList:      newDataList,
	}
	return
}