package line_feature

import (
	"errors"
	"github.com/shopspring/decimal"
	chartEdbMappingModel "hongze/hongze_yb/models/tables/chart_edb_mapping"
	edbDataModel "hongze/hongze_yb/models/tables/edb_data"
	"hongze/hongze_yb/services/chart"
	"hongze/hongze_yb/utils"
	"time"
)

// LineFeatureDataResp 曲线图的一些数据返回
type LineFeatureDataResp struct {
	MaxData             float64
	MinData             float64
	LatestDate          time.Time `description:"真实数据的最后日期"`
	EdbInfoCategoryType int
	ChartColor          string
	ChartStyle          string
	PredictChartColor   string
	ChartType           int
	ChartWidth          float64
	EdbName             string
	EdbNameEn           string
	Unit                string
	UnitEn              string
	IsAxis              int
	DataList            []edbDataModel.EdbDataList
}

// FrequencyDistributionResp 频率分布图数据
type FrequencyDistributionResp struct {
	LeftMinValue  float64
	LeftMaxValue  float64
	RightMinValue float64
	RightMaxValue float64
	DataList      []FrequencyDistributionData
}

// FrequencyDistributionData 频率分布的值
type FrequencyDistributionData struct {
	Name   string      `description:"别名"`
	NameEn string      `description:"英文别名"`
	Unit   string      `description:"单位"`
	UnitEn string      `description:"单位别名"`
	Value  interface{} `description:"每个指标的值"`
	Color  string      `description:"数据颜色"`
	IsAxis int         `description:"1:左轴,0:右轴"`
}

// FrequencyDistributionYData 频率分布的实际数据
type FrequencyDistributionYData struct {
	X float64
	Y float64
}

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

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

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

	edb := edbList[0]
	dataList := edb.DataList.([]*edbDataModel.EdbDataList)
	newDataList := make([]edbDataModel.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, edbDataModel.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 = 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 *chartEdbMappingModel.ChartEdbInfoMapping, calculateValue int, calculateUnit string) (edbList []*chartEdbMappingModel.ChartEdbInfoMappingList, dataResp LineFeatureDataResp, sourceArr []string, err error, errMsg string) {
	edbList = make([]*chartEdbMappingModel.ChartEdbInfoMappingList, 0)
	moveUnitDays, ok := utils.FrequencyDaysMap[calculateUnit]
	if !ok {
		errMsg = `错误的周期`
		err = errors.New(errMsg)
		return
	}
	calculateDay := calculateValue * moveUnitDays
	// 指标对应的所有数据
	_, edbList, sourceArr, err = chart.GetEdbDataMapList(chartInfoId, 1, `公历`, startDate, endDate, []*chartEdbMappingModel.ChartEdbInfoMapping{mappingInfo}, "")
	if err != nil {
		return
	}

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

	edb := edbList[0]
	dataList := edb.DataList.([]*edbDataModel.EdbDataList)
	newDataList := make([]edbDataModel.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, edbDataModel.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 = 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 *chartEdbMappingModel.ChartEdbInfoMapping, dateType, stepVal int, startDate, endDate string) (edbList []*chartEdbMappingModel.ChartEdbInfoMappingList, dataResp FrequencyDistributionResp, sourceArr []string, err error, errMsg string) {
	XDataList := make([]float64, 0)
	// 频度
	Y1DataList := make([]FrequencyDistributionYData, 0)
	// 累计频率
	Y2DataList := make([]FrequencyDistributionYData, 0)
	edbList = make([]*chartEdbMappingModel.ChartEdbInfoMappingList, 0)

	// 指标对应的所有数据
	_, edbList, sourceArr, err = chart.GetEdbDataMapList(chartInfoId, 1, `公历`, startDate, endDate, []*chartEdbMappingModel.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.([]*edbDataModel.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([]*edbDataModel.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, 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, FrequencyDistributionYData{
			X: tmpMinVal,
			Y: tmpTotalFrequency,
		})
	}

	newDataList := []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 = FrequencyDistributionResp{
		LeftMinValue:  minFrequency,
		LeftMaxValue:  maxFrequency,
		RightMinValue: 0,
		RightMaxValue: 100,
		DataList:      newDataList,
	}
	return
}
