package services

import (
	"encoding/json"
	aiPredictModel "eta/eta_api/models/ai_predict_model"
	"eta/eta_api/models/data_manage"
	"eta/eta_api/services/data"
	"eta/eta_api/utils"
	"fmt"
	"sort"
	"time"
)

func ImportAiPredictModelIndexAndData(imports []*aiPredictModel.AiPredictModelImportData) (err error) {
	if len(imports) == 0 {
		return
	}

	// 查询已存在的标的
	indexOb := new(aiPredictModel.AiPredictModelIndex)
	indexNameItem := make(map[string]*aiPredictModel.AiPredictModelIndex)
	{
		list, e := indexOb.GetItemsByCondition("", make([]interface{}, 0), []string{}, "")
		if e != nil {
			err = fmt.Errorf("获取标的失败, %v", e)
			return
		}
		for _, v := range list {
			indexNameItem[v.IndexName] = v
		}
	}

	updateCols := []string{indexOb.Cols().ClassifyId, indexOb.Cols().ModelFramework, indexOb.Cols().PredictDate, indexOb.Cols().PredictValue, indexOb.Cols().DirectionAccuracy, indexOb.Cols().AbsoluteDeviation, indexOb.Cols().ExtraConfig, indexOb.Cols().SysUserId, indexOb.Cols().SysUserRealName, indexOb.Cols().ModifyTime}
	updateIndexes := make([]*aiPredictModel.AiPredictModelImportData, 0)
	createIndexes := make([]*aiPredictModel.AiPredictModelImportData, 0)
	for _, v := range imports {
		exist := indexNameItem[v.Index.IndexName]
		// 编辑
		if exist != nil {
			// 图例信息
			if exist.ExtraConfig != "" && v.Index.ExtraConfig != "" {
				var oldConfig, newConfig aiPredictModel.AiPredictModelIndexExtraConfig
				if e := json.Unmarshal([]byte(exist.ExtraConfig), &oldConfig); e != nil {
					err = fmt.Errorf("标的原配置解析失败, Config: %s, Err: %v", exist.ExtraConfig, e)
					return
				}
				if e := json.Unmarshal([]byte(v.Index.ExtraConfig), &newConfig); e != nil {
					err = fmt.Errorf("标的新配置解析失败, Config: %s, Err: %v", v.Index.ExtraConfig, e)
					return
				}
				oldConfig.DailyChart.PredictLegendName = newConfig.DailyChart.PredictLegendName
				b, _ := json.Marshal(oldConfig)
				v.Index.ExtraConfig = string(b)
			}

			v.Index.AiPredictModelIndexId = exist.AiPredictModelIndexId
			v.Index.IndexCode = exist.IndexCode
			updateIndexes = append(updateIndexes, v)
			continue
		}

		// 新增
		indexCode, e := utils.GenerateEdbCode(1, "IPM")
		if e != nil {
			err = fmt.Errorf("生成标的编码失败, %v", e)
			return
		}
		v.Index.IndexCode = indexCode
		createIndexes = append(createIndexes, v)
	}

	// 新增/更新指标
	if e := indexOb.ImportIndexAndData(createIndexes, updateIndexes, updateCols); e != nil {
		err = fmt.Errorf("导入指标失败, %v", e)
		return
	}
	return
}

func GetAiPredictChartDetailByData(indexItem *aiPredictModel.AiPredictModelIndex, indexData []*aiPredictModel.AiPredictModelData, source int) (resp *data_manage.ChartInfoDetailResp, err error) {
	resp = new(data_manage.ChartInfoDetailResp)

	// 标的配置
	var extraConfig aiPredictModel.AiPredictModelIndexExtraConfig
	if indexItem.ExtraConfig != "" {
		if e := json.Unmarshal([]byte(indexItem.ExtraConfig), &extraConfig); e != nil {
			err = fmt.Errorf("标的额外配置解析失败, Config: %s, Err: %v", indexItem.ExtraConfig, e)
			return
		}
	}

	// 图表信息
	var predictLegendName, confLeftMin, confLeftMax, unit string
	if source == aiPredictModel.ModelDataSourceDaily {
		predictLegendName = extraConfig.DailyChart.PredictLegendName
		if predictLegendName == "" {
			predictLegendName = "Predicted"
		}
		unit = extraConfig.DailyChart.Unit
		confLeftMin = extraConfig.DailyChart.LeftMin
		confLeftMax = extraConfig.DailyChart.LeftMax
	}
	if source == aiPredictModel.ModelDataSourceMonthly {
		predictLegendName = "预测值"
		unit = extraConfig.MonthlyChart.Unit
		confLeftMin = extraConfig.MonthlyChart.LeftMin
		confLeftMax = extraConfig.MonthlyChart.LeftMax
	}
	// 这里简单兼容下吧,暂时就不修数据了
	if confLeftMin == "" {
		confLeftMin = indexItem.LeftMin
	}
	if confLeftMax == "" {
		confLeftMax = indexItem.LeftMax
	}

	// 获取曲线图主题样式
	chartView := new(data_manage.ChartInfoView)
	chartView.ChartType = utils.CHART_SOURCE_DEFAULT
	chartTheme, e := data.GetChartThemeConfig(0, chartView.ChartType, utils.CHART_TYPE_CURVE)
	if e != nil {
		err = fmt.Errorf("获取图表主题样式失败, %v", e)
		return
	}
	chartView.ChartThemeStyle = chartTheme.Config
	chartView.ChartThemeId = chartTheme.ChartThemeId

	chartView.ChartName = indexItem.IndexName
	chartView.ChartNameEn = indexItem.IndexName
	chartView.DateType = 3
	chartView.Calendar = "公历"
	chartView.ChartSource = "AI预测模型"
	chartView.ChartSourceEn = "AI预测模型"
	chartView.Unit = unit
	chartView.UnitEn = unit

	// EdbList-固定一条为标的实际值、一条为预测值
	edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
	edbActual, edbPredict := new(data_manage.ChartEdbInfoMapping), new(data_manage.ChartEdbInfoMapping)
	edbActual.EdbName = indexItem.IndexName
	edbActual.EdbNameEn = indexItem.IndexName
	edbActual.IsAxis = 1
	edbActual.Unit = unit
	edbActual.UnitEn = unit

	edbPredict.EdbName = predictLegendName
	edbPredict.EdbNameEn = predictLegendName
	edbPredict.IsAxis = 1
	edbPredict.Unit = unit
	edbPredict.UnitEn = unit
	actualData, predictData := make([]*data_manage.EdbDataList, 0), make([]*data_manage.EdbDataList, 0)

	var startDate, endDate time.Time
	var actualValues, predictValues []float64
	var actualNewest, predictNewest bool
	var actualLatestTimestamp int64 // 实际值最后一天的时间戳,作为日度图表的分割线
	for k, v := range indexData {
		// 如果实际值和预测值都是null那么该日期无效直接忽略
		if !v.Value.Valid && !v.PredictValue.Valid {
			continue
		}

		// 将有效值加入[]float64,最后取极值
		if v.Value.Valid {
			actualValues = append(actualValues, v.Value.Float64)
		}
		if v.PredictValue.Valid {
			predictValues = append(predictValues, v.PredictValue.Float64)
		}

		// 开始结束时间
		if k == 0 {
			startDate = v.DataTime
			endDate = v.CreateTime
		}
		if v.DataTime.Before(startDate) {
			startDate = v.DataTime
		}
		if v.DataTime.After(endDate) {
			endDate = v.DataTime
		}

		// 指标数据
		if v.Value.Valid {
			if !actualNewest {
				edbActual.LatestDate = v.DataTime.Format(utils.FormatDate)
				edbActual.LatestValue = v.Value.Float64
				actualLatestTimestamp = v.DataTime.UnixNano() / 1e6
				actualNewest = true
			}
			actualData = append(actualData, &data_manage.EdbDataList{
				DataTime:      v.DataTime.Format(utils.FormatDate),
				Value:         v.Value.Float64,
				DataTimestamp: v.DataTimestamp,
			})
		}
		if v.PredictValue.Valid {
			if !predictNewest {
				edbPredict.LatestDate = v.DataTime.Format(utils.FormatDate)
				edbPredict.LatestValue = v.Value.Float64
				predictNewest = true
			}
			predictData = append(predictData, &data_manage.EdbDataList{
				DataTime:      v.DataTime.Format(utils.FormatDate),
				Value:         v.PredictValue.Float64,
				DataTimestamp: v.DataTimestamp,
			})
		}
	}

	// 图表数据这里均做一个升序排序
	sort.Slice(actualData, func(i, j int) bool {
		return actualData[i].DataTimestamp < actualData[j].DataTimestamp
	})
	sort.Slice(predictData, func(i, j int) bool {
		return predictData[i].DataTimestamp < predictData[j].DataTimestamp
	})

	// 极值
	actualMin, actualMax := utils.FindMinMax(actualValues)
	predictMin, predictMax := utils.FindMinMax(predictValues)
	edbActual.MinData = actualMin
	edbActual.MaxData = actualMax
	edbPredict.MinData = predictMin
	edbPredict.MaxData = predictMax

	edbActual.DataList = actualData
	edbPredict.DataList = predictData
	edbList = append(edbList, edbActual, edbPredict)

	// 上下限
	if confLeftMin != "" {
		chartView.LeftMin = confLeftMin
	} else {
		leftMin := actualMin
		if leftMin > predictMin {
			leftMin = predictMin
		}
		chartView.LeftMin = fmt.Sprint(leftMin)
	}
	if confLeftMax != "" {
		chartView.LeftMax = confLeftMax
	} else {
		leftMax := actualMax
		if leftMax < predictMax {
			leftMax = predictMax
		}
		chartView.LeftMax = fmt.Sprint(leftMax)
	}

	chartView.StartDate = startDate.Format(utils.FormatDate)
	chartView.EndDate = endDate.Format(utils.FormatDate)

	// 日度图表的分割线日期
	if source == aiPredictModel.ModelDataSourceDaily {
		var dataResp struct {
			ActualLatestTimestamp int64
		}
		dataResp.ActualLatestTimestamp = actualLatestTimestamp
		resp.DataResp = dataResp
	}

	resp.ChartInfo = chartView
	resp.EdbInfoList = edbList
	return
}