package chart

import (
	"errors"
	"fmt"
	chart_info2 "hongze/hongze_yb/models/response/chart_info"
	chartEdbMappingModel "hongze/hongze_yb/models/tables/chart_edb_mapping"
	"hongze/hongze_yb/models/tables/chart_info"
	edbDataModel "hongze/hongze_yb/models/tables/edb_data"
	"hongze/hongze_yb/utils"
	"sort"
	"strconv"
	"time"
)

// GetChartSectionCombineData 截面组合图的数据处理
func GetChartSectionCombineData(chartInfo *chart_info.ChartInfo, mappingList []*chartEdbMappingModel.ChartEdbInfoMapping, edbDataListMap map[int][]*edbDataModel.EdbDataList, extraConfig chart_info2.ChartSectionAllExtraConf) (edbIdList []int, dataListResp chart_info2.ChartSectionCombineDataResp, 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)
	edbMappingMap := make(map[int]*chartEdbMappingModel.ChartEdbInfoMapping)
	for _, v := range mappingList {
		edbIdList = append(edbIdList, v.EdbInfoId)
		edbMappingMap[v.EdbInfoId] = v
	}
	// 确定好截面散点图返回的数据格式
	// 获取所有的引用日期设置
	dateConfListMap := make(map[string]*chart_info2.ChartSectionDateConfItem)
	dateConfEdbIds := make([]int, 0)
	for _, v := range extraConfig.DateConfList {
		if v.EdbInfoId > 0 {
			dateConfEdbIds = append(dateConfEdbIds, v.EdbInfoId)
		}
		dateConfListMap[v.DateConfName] = v
	}
	// 遍历每个系列
	// 遍历每个指标,根据选中的日期,进行日期变换得到最终的日期,根据最终的日期获取对应的值
	// 组装数据
	baseSeries := new(chart_info2.ChartSectionSeriesItem) //y轴的系列
	var firstUnit, leftUnit, rightUnit, right2Unit *chart_info2.XData
	var (
		LeftMin   float64
		LeftMax   float64
		RightMin  float64
		RightMax  float64
		Right2Min float64
		Right2Max float64
	)
	seriesDataListMap := make(map[string][]float64)
	seriesNoDataIndexMap := make(map[string][]int)
	for _, seriesItem := range extraConfig.SeriesList {
		var maxDate time.Time
		var minVal, maxVal float64
		noDataEdbIndex := make([]int, 0)
		dataList := make([]float64, len(seriesItem.EdbInfoList))
		for index, edbConf := range seriesItem.EdbInfoList {
			edbInfoId := edbConf.EdbInfoId //X轴的指标
			edbMappingInfo, ok := edbMappingMap[edbInfoId]
			if !ok {
				continue
			}
			seriesItem.EdbInfoList[index].EdbName = edbMappingInfo.EdbName
			seriesItem.EdbInfoList[index].EdbNameEn = edbMappingInfo.EdbNameEn
			seriesItem.EdbInfoList[index].EdbInfoType = edbMappingInfo.EdbInfoCategoryType
			seriesItem.EdbInfoList[index].Unit = edbMappingInfo.Unit
			seriesItem.EdbInfoList[index].UnitEn = edbMappingInfo.UnitEn
			if index == 0 {
				firstUnit = &chart_info2.XData{
					Name:   edbMappingInfo.Unit,
					NameEn: edbMappingInfo.UnitEn,
				}
			}
			edbDataList, ok3 := edbDataListMap[edbInfoId]
			if !ok3 {
				err = fmt.Errorf("指标%d的日期数据不存在", edbInfoId)
				return
			}
			//日期变换处理,判断用指标的最新日期还是,直接获取引用日期
			var findDate string
			if edbConf.DateConfType == 0 {
				if edbInfoId == 0 {
					err = fmt.Errorf("请选择指标")
					return
				}
				findDate, err = GetChartSectionSeriesDateByDateChange(edbInfoId, edbDataList, edbConf.DateConf.DateChange, edbConf.DateConf.MoveForward)
				if err != nil {
					err = fmt.Errorf("指标%d的日期变换处理失败", edbInfoId)
					return
				}
			} else {
				// 获取日期配置
				dateConfItem, ok1 := dateConfListMap[edbConf.DateConfName]
				if !ok1 {
					err = fmt.Errorf("引用日期配置不存在")
					return
				}
				// todo 根据日期变换得到最终日期
				edbDataListTmp := make([]*edbDataModel.EdbDataList, 0)
				if dateConfItem.EdbInfoId > 0 {
					edbDataListTmp, ok1 = edbDataListMap[dateConfItem.EdbInfoId]
					if !ok1 {
						err = fmt.Errorf("指标%d的日期数据不存在", dateConfItem.EdbInfoId)
						return
					}
				}

				findDate, err = GetChartSectionSeriesDateByDateChange(dateConfItem.EdbInfoId, edbDataListTmp, dateConfItem.DateChange, dateConfItem.MoveForward)
				if err != nil {
					err = fmt.Errorf("指标%d的日期变换处理失败", dateConfItem.EdbInfoId)
					return
				}
			}
			findDateTime, _ := time.ParseInLocation(utils.FormatDate, findDate, time.Local)
			if maxDate.IsZero() {
				maxDate = findDateTime
			} else {
				if findDateTime.After(maxDate) {
					maxDate = findDateTime
				}
			}
			if tmpValue, ok := edbDataMap[edbInfoId][findDate]; ok {
				dataList[index] = tmpValue
				if index == 0 {
					minVal = tmpValue
					maxVal = tmpValue
				} else {
					if tmpValue < minVal {
						minVal = tmpValue
					}
					if tmpValue > maxVal {
						maxVal = tmpValue
					}
				}
			} else {
				dataList[index] = 0
				noDataEdbIndex = append(noDataEdbIndex, index)
				continue
			}
		}
		seriesDataListMap[seriesItem.SeriesName] = dataList
		seriesNoDataIndexMap[seriesItem.SeriesName] = noDataEdbIndex
		seriesItem.DataList = dataList
		seriesItem.MinData = minVal
		seriesItem.MaxData = maxVal
		seriesItem.NoDataEdbIndex = noDataEdbIndex
		if extraConfig.BaseChartSeriesName == seriesItem.SeriesName {
			baseSeries = seriesItem
		}
		if seriesItem.IsAxis == 1 && leftUnit == nil { //左轴,右轴
			leftUnit = firstUnit
		} else if seriesItem.IsAxis == 0 && rightUnit == nil {
			rightUnit = firstUnit
		} else if seriesItem.IsAxis == 2 && right2Unit == nil {
			right2Unit = firstUnit
		}

		//处理上下限
		var minData, maxData float64
		for _, d := range seriesItem.DataList {
			if minData > d {
				minData = d
			}
			if maxData < d {
				maxData = d
			}
		}
		if seriesItem.IsAxis == 1 {
			if LeftMin > minData {
				LeftMin = minData
			}
			if LeftMax < maxData {
				LeftMax = maxData
			}
		} else if seriesItem.IsAxis == 0 {
			if RightMin > minData {
				RightMin = minData
			}
			if RightMax < maxData {
				RightMax = maxData
			}
		} else {
			if Right2Min > minData {
				Right2Min = minData
			}
			if Right2Max < maxData {
				Right2Max = maxData
			}
		}
	}
	// 处理横轴
	// 遍历基准系列,判断有几个横轴名称
	if baseSeries == nil {
		err = fmt.Errorf("基准系列不存在")
		return
	}
	// 处理系列排序
	if extraConfig.SortType > 0 {
		newSeriesDataListMap, newSeriesNoDataIndexMap := SortChartSeriesDataSet(baseSeries.SeriesName, baseSeries.DataList, baseSeries.NoDataEdbIndex, seriesDataListMap, seriesNoDataIndexMap, extraConfig.SortType)
		for k, item := range extraConfig.SeriesList {
			dataList, ok := newSeriesDataListMap[item.SeriesName]
			if ok {
				extraConfig.SeriesList[k].DataList = dataList
			}
			noIndex, ok := newSeriesNoDataIndexMap[item.SeriesName]
			if ok {
				extraConfig.SeriesList[k].NoDataEdbIndex = noIndex
			}
		}
	}

	xDataList := make([]chart_info2.XData, 0)
	for index, item := range baseSeries.EdbInfoList {
		if index == 0 {
			firstUnit = &chart_info2.XData{
				Name:   item.Unit,
				NameEn: item.UnitEn,
			}
		}
		tmp := chart_info2.XData{
			Name:   item.EdbName,
			NameEn: item.EdbNameEn,
		}
		// 如果已经设置了横轴名称,则用设置的名称替换
		if len(extraConfig.XDataList) > index {
			newItem := extraConfig.XDataList[index]
			if newItem.Name != "" {
				tmp = newItem
			}
		}
		xDataList = append(xDataList, tmp)
	}
	dataListResp.XDataList = xDataList

	unitList := new(chart_info2.ChartSectionCombineUnit)
	if baseSeries.IsAxis == 1 { //左轴,右轴
		leftUnit = firstUnit
	} else if baseSeries.IsAxis == 2 {
		rightUnit = firstUnit
	} else {
		right2Unit = firstUnit
	}
	if leftUnit != nil {
		unitList.LeftName = leftUnit.Name
		unitList.LeftNameEn = leftUnit.NameEn
	}
	if rightUnit != nil {
		unitList.RightName = rightUnit.Name
		unitList.RightNameEn = rightUnit.NameEn
	}
	if right2Unit != nil {
		unitList.RightTwoName = right2Unit.Name
		unitList.RightTwoNameEn = right2Unit.NameEn
	}
	if extraConfig.UnitList.LeftName != "" {
		unitList.LeftName = extraConfig.UnitList.LeftName
		unitList.LeftNameEn = extraConfig.UnitList.LeftNameEn
	}
	if extraConfig.UnitList.RightName != "" {
		unitList.RightName = extraConfig.UnitList.RightName
		unitList.RightNameEn = extraConfig.UnitList.RightNameEn
	}

	if extraConfig.UnitList.RightTwoName != "" {
		unitList.RightTwoName = extraConfig.UnitList.RightTwoName
		unitList.RightTwoNameEn = extraConfig.UnitList.RightTwoNameEn
	}

	if chartInfo != nil && chartInfo.MinMaxSave == 1 {
		dataListResp.LeftMin = chartInfo.LeftMin
		dataListResp.LeftMax = chartInfo.LeftMax
		dataListResp.RightMin = chartInfo.RightMin
		dataListResp.RightMax = chartInfo.RightMax
		dataListResp.Right2Min = chartInfo.Right2Min
		dataListResp.Right2Max = chartInfo.Right2Max
	} else {
		dataListResp.LeftMin = strconv.FormatFloat(LeftMin, 'f', -1, 64)
		dataListResp.LeftMax = strconv.FormatFloat(LeftMax, 'f', -1, 64)
		dataListResp.RightMin = strconv.FormatFloat(RightMin, 'f', -1, 64)
		dataListResp.RightMax = strconv.FormatFloat(RightMax, 'f', -1, 64)
		dataListResp.Right2Min = strconv.FormatFloat(Right2Min, 'f', -1, 64)
		dataListResp.Right2Max = strconv.FormatFloat(Right2Max, 'f', -1, 64)
	}

	// 查询引用日期里的指标信息
	/*if len(dateConfEdbIds) > 0 {
		dateConfEdbList, e := chart_info2.GetEdbInfoByIdList(dateConfEdbIds)
		if e != nil {
			err = fmt.Errorf("查询引用日期里的指标信息失败,错误信息:%s", e.Error())
			return
		}
		dateConfEdbMap := make(map[int]*data_manage.EdbInfo)
		for _, dateConfEdb := range dateConfEdbList {
			dateConfEdbMap[dateConfEdb.EdbInfoId] = dateConfEdb
		}
		for i, dateConf := range extraConfig.DateConfList {
			if dateConf.EdbInfoId > 0 {
				edbItem, ok := dateConfEdbMap[dateConf.EdbInfoId]
				if ok {
					extraConfig.DateConfList[i].EdbName = edbItem.EdbName
					extraConfig.DateConfList[i].EdbInfoId = edbItem.EdbInfoId
					extraConfig.DateConfList[i].EdbInfoType = edbItem.EdbInfoType
					extraConfig.DateConfList[i].Frequency = edbItem.Frequency
					extraConfig.DateConfList[i].EndDate = edbItem.EndDate
				}

			}
		}
	}*/

	dataListResp.SeriesList = extraConfig.SeriesList
	dataListResp.DateConfList = extraConfig.DateConfList
	dataListResp.BaseChartSeriesName = extraConfig.BaseChartSeriesName
	dataListResp.UnitList = unitList
	dataListResp.IsHeap = extraConfig.IsHeap
	dataListResp.SortType = extraConfig.SortType
	return
}

// GetChartSectionSeriesDateByDateChange 获取日期变换后的日期edbInfoId 1指标日期,2 系统日期
func GetChartSectionSeriesDateByDateChange(edbInfoId int, dataList []*edbDataModel.EdbDataList, dateChange []*chart_info2.ChartSectionDateChange, moveForward int) (newDate string, err error) {
	if edbInfoId > 0 { //指标日期
		newDate = GetEdbDateByMoveForward(moveForward, dataList)
	} else {
		//系统日期
		newDate = time.Now().Format(utils.FormatDate)
	}
	if newDate != "" && len(dateChange) > 0 {
		newDate, err = HandleChartSectionSeriesDateChange(newDate, dateChange)
	}
	return
}

func GetEdbDateByMoveForward(moveForward int, edbDataList []*edbDataModel.EdbDataList) (date string) {
	dateList := make([]string, 0)
	for _, v := range edbDataList {
		dateList = append(dateList, v.DataTime)
	}

	date = GetEdbDateByMoveForwardByDateList(moveForward, dateList)
	return
}

func GetEdbDateByMoveForwardByDateList(moveForward int, dateList []string) (date string) {
	// 根据日期进行排序
	index := len(dateList) - 1 - moveForward
	for k, v := range dateList {
		if k == index {
			date = v
			return
		}
	}
	return
}

// HandleChartSectionSeriesDateChange 处理日期变换
func HandleChartSectionSeriesDateChange(date string, dateChange []*chart_info2.ChartSectionDateChange) (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, _ = 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
}

// handleSystemAppointDateT
// @Description: 处理系统日期相关的指定频率(所在周/旬/月/季/半年/年的最后/最早一天)
// @author: Roc
// @datetime2023-10-27 09:31:35
// @param Frequency string
// @param Day string
// @return date string
// @return err error
// @return errMsg string
func handleSystemAppointDateT(currDate time.Time, appointDay, frequency string) (date string, err error, errMsg string) {
	//currDate := time.Now()
	switch frequency {
	case "本周":
		day := int(currDate.Weekday())
		if day == 0 { // 周日
			day = 7
		}
		num := 0
		switch appointDay {
		case "周一":
			num = 1
		case "周二":
			num = 2
		case "周三":
			num = 3
		case "周四":
			num = 4
		case "周五":
			num = 5
		case "周六":
			num = 6
		case "周日":
			num = 7
		}
		day = num - day
		date = currDate.AddDate(0, 0, day).Format(utils.FormatDate)
	case "本旬":
		day := currDate.Day()
		var tmpDate time.Time
		switch appointDay {
		case "第一天":
			if day <= 10 {
				tmpDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, currDate.Location())
			} else if day <= 20 {
				tmpDate = time.Date(currDate.Year(), currDate.Month(), 11, 0, 0, 0, 0, currDate.Location())
			} else {
				tmpDate = time.Date(currDate.Year(), currDate.Month(), 21, 0, 0, 0, 0, currDate.Location())
			}
		case "最后一天":
			if day <= 10 {
				tmpDate = time.Date(currDate.Year(), currDate.Month(), 10, 0, 0, 0, 0, currDate.Location())
			} else if day <= 20 {
				tmpDate = time.Date(currDate.Year(), currDate.Month(), 20, 0, 0, 0, 0, currDate.Location())
			} else {
				tmpDate = time.Date(currDate.Year(), currDate.Month()+1, 1, 0, 0, 0, 0, currDate.Location()).AddDate(0, 0, -1)
			}
		}
		date = tmpDate.Format(utils.FormatDate)
	case "本月":
		var tmpDate time.Time
		switch appointDay {
		case "第一天":
			tmpDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, currDate.Location())
		case "最后一天":
			tmpDate = time.Date(currDate.Year(), currDate.Month()+1, 1, 0, 0, 0, 0, currDate.Location()).AddDate(0, 0, -1)
		}
		date = tmpDate.Format(utils.FormatDate)
	case "本季":
		month := currDate.Month()
		var tmpDate time.Time
		switch appointDay {
		case "第一天":
			if month <= 3 {
				tmpDate = time.Date(currDate.Year(), 1, 1, 0, 0, 0, 0, currDate.Location())
			} else if month <= 6 {
				tmpDate = time.Date(currDate.Year(), 4, 1, 0, 0, 0, 0, currDate.Location())
			} else if month <= 9 {
				tmpDate = time.Date(currDate.Year(), 7, 1, 0, 0, 0, 0, currDate.Location())
			} else {
				tmpDate = time.Date(currDate.Year(), 10, 1, 0, 0, 0, 0, currDate.Location())
			}
		case "最后一天":
			if month <= 3 {
				tmpDate = time.Date(currDate.Year(), 3, 31, 0, 0, 0, 0, currDate.Location())
			} else if month <= 6 {
				tmpDate = time.Date(currDate.Year(), 6, 30, 0, 0, 0, 0, currDate.Location())
			} else if month <= 9 {
				tmpDate = time.Date(currDate.Year(), 9, 30, 0, 0, 0, 0, currDate.Location())
			} else {
				tmpDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, currDate.Location())
			}
		}
		date = tmpDate.Format(utils.FormatDate)
	case "本半年":
		month := currDate.Month()
		var tmpDate time.Time
		switch appointDay {
		case "第一天":
			if month <= 6 {
				tmpDate = time.Date(currDate.Year(), 1, 1, 0, 0, 0, 0, currDate.Location())
			} else {
				tmpDate = time.Date(currDate.Year(), 7, 1, 0, 0, 0, 0, currDate.Location())
			}
		case "最后一天":
			if month <= 6 {
				tmpDate = time.Date(currDate.Year(), 6, 30, 0, 0, 0, 0, currDate.Location())
			} else {
				tmpDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, currDate.Location())
			}
		}
		date = tmpDate.Format(utils.FormatDate)
	case "本年":
		var tmpDate time.Time
		switch appointDay {
		case "第一天":
			tmpDate = time.Date(currDate.Year(), 1, 1, 0, 0, 0, 0, currDate.Location())
		case "最后一天":
			tmpDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, currDate.Location())
		}
		date = tmpDate.Format(utils.FormatDate)
	default:
		errMsg = "错误的日期频度:" + frequency
		err = errors.New(errMsg)
		return
	}

	return
}

// sortTripleDataSet 以第一组数据为基准,排序之后,空数组的位置也要同步变更
func SortChartSeriesDataSet(baseName string, baseDataList []float64, baseSeriesNoDataIndexList []int, dataListMap map[string][]float64, noDataListIndexMap map[string][]int, asc int) (newDataListMap map[string][]float64, newNoDataListIndexMap map[string][]int) {
	newDataListMap = make(map[string][]float64)
	newNoDataListIndexMap = make(map[string][]int)

	indices := make([]int, len(baseDataList))
	newIndices := make([]int, len(baseDataList)-len(baseSeriesNoDataIndexList))
	// 初始化indices
	for i := range indices {
		indices[i] = i
	}
	if len(baseSeriesNoDataIndexList) > 0 { //把空值移动到最右边
		j := 0
		for i := range indices {
			isEmpty := false
			for _, v := range baseSeriesNoDataIndexList {
				if i == v {
					isEmpty = true
					break
				}
			}
			if isEmpty {
				continue
			}
			newIndices[j] = i
			j += 1
		}
		newIndices = append(newIndices, baseSeriesNoDataIndexList...)
		// 根据排序后的indices重新排列所有组的数据
		for i, idx := range newIndices {
			for k, _ := range dataListMap {
				if _, ok := newDataListMap[k]; !ok {
					newDataListMap[k] = make([]float64, len(baseDataList))
				}
				if utils.InArrayByInt(noDataListIndexMap[k], idx) { //如果i位置上的数据为空,那么
					newNoDataListIndexMap[k] = append(newNoDataListIndexMap[k], i)
				}
				newDataListMap[k][i] = dataListMap[k][idx]
			}
		}
		dataListMap = newDataListMap
		noDataListIndexMap = newNoDataListIndexMap
		newDataListMap = make(map[string][]float64)
		newNoDataListIndexMap = make(map[string][]int)
		baseDataList, _ = dataListMap[baseName]
		//先把空的数据移动到最后面
		indices = make([]int, len(baseDataList)-len(baseSeriesNoDataIndexList)) //空值不参与排序
		newIndices = make([]int, len(baseDataList))                             //空值不参与排序
		// 初始化indices
		for i := range indices {
			indices[i] = i
		}

	}
	length := len(indices)
	baseDataSortList := make([]chart_info.ChartSectionSeriesValSort, length)
	for i, value := range baseDataList {
		if i < length {
			baseDataSortList[i] = chart_info.ChartSectionSeriesValSort{Index: i, Value: value}
		}
	}
	if asc == 1 {
		// 使用sort.Sort进行排序
		sort.Sort(chart_info.ChartSectionSeriesValSortAsc(baseDataSortList))
	} else {
		sort.Sort(chart_info.ChartSectionSeriesValSortDesc(baseDataSortList))
	}

	for k, v := range baseDataSortList {
		indices[k] = v.Index
	}

	for i := range newIndices {
		if i < length {
			newIndices[i] = indices[i]
		} else {
			newIndices[i] = i
		}
	}
	// 根据排序后的indices重新排列所有组的数据
	for i, idx := range newIndices {
		for k, _ := range dataListMap {
			if _, ok := newDataListMap[k]; !ok {
				newDataListMap[k] = make([]float64, len(baseDataList))
			}
			if utils.InArrayByInt(noDataListIndexMap[k], idx) { //如果i位置上的数据为空,那么
				newNoDataListIndexMap[k] = append(newNoDataListIndexMap[k], i)
			}
			newDataListMap[k][i] = dataListMap[k][idx]
		}
	}
	return
}