package data_manage

import (
	"encoding/json"
	"eta/eta_api/controllers"
	"eta/eta_api/models"
	"eta/eta_api/models/data_manage"
	"eta/eta_api/models/data_manage/request"
	"eta/eta_api/services/data"
	correlationServ "eta/eta_api/services/data/correlation"
	"eta/eta_api/utils"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

// FactorEdbSeriesController 因子指标系列
type FactorEdbSeriesController struct {
	controllers.BaseAuthController
}

// CalculateFuncList
// @Title 计算方式列表
// @Description 计算方式列表
// @Param   EdbInfoType  query  int  false "指标计算类型: 0-普通指标; 1-预测指标"
// @Success Ret=200 操作成功
// @router /factor_edb_series/calculate_func/list [get]
func (this *FactorEdbSeriesController) CalculateFuncList() {
	br := new(models.BaseResponse).Init()
	defer func() {
		if br.ErrMsg == "" {
			br.IsSendEmail = false
		}
		this.Data["json"] = br
		this.ServeJSON()
	}()
	sysUser := this.SysUser
	if sysUser == nil {
		br.Msg = "请登录"
		br.ErrMsg = "请登录,SysUser Is Empty"
		br.Ret = 408
		return
	}
	edbInfoType, _ := this.GetInt("EdbInfoType", 0)

	funcOb := new(data_manage.FactorEdbSeriesCalculateFunc)
	cond := fmt.Sprintf(` AND %s = ?`, funcOb.Cols().EdbInfoType)
	pars := make([]interface{}, 0)
	pars = append(pars, edbInfoType)
	list, e := funcOb.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC", funcOb.Cols().PrimaryId))
	if e != nil {
		br.Msg = "获取失败"
		br.ErrMsg = fmt.Sprintf("获取计算方式列表失败, Err: %v", e)
		return
	}
	resp := make([]*data_manage.FactorEdbSeriesCalculateFuncItem, 0)
	for _, v := range list {
		resp = append(resp, v.Format2Item())
	}

	br.Data = resp
	br.Ret = 200
	br.Success = true
	br.Msg = "获取成功"
}

// Add
// @Title 新增
// @Description 新增
// @Param	request	body request.AddFactorEdbSeriesReq true "type json string"
// @Success Ret=200 操作成功
// @router /factor_edb_series/add [post]
func (this *FactorEdbSeriesController) Add() {
	br := new(models.BaseResponse).Init()
	defer func() {
		if br.ErrMsg == "" {
			br.IsSendEmail = false
		}
		this.Data["json"] = br
		this.ServeJSON()
	}()
	sysUser := this.SysUser
	if sysUser == nil {
		br.Msg = "请登录"
		br.ErrMsg = "请登录,SysUser Is Empty"
		br.Ret = 408
		return
	}
	var req request.AddFactorEdbSeriesReq
	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
		br.Msg = "参数解析异常"
		br.ErrMsg = fmt.Sprintf("参数解析异常, Err: %v", e)
		return
	}
	req.SeriesName = strings.TrimSpace(req.SeriesName)
	if req.SeriesName == "" {
		br.Msg = "请输入指标系列名称"
		return
	}
	if len(req.EdbInfoIds) <= 0 {
		br.Msg = "请选择因子指标系列"
		return
	}
	if len(req.EdbInfoIds) > 100 {
		br.Msg = "添加指标总数量不得超过100"
		return
	}
	calculateLen := len(req.Calculates)
	if calculateLen > 5 {
		br.Msg = "计算公式不可超过5个"
		return
	}
	var calculatesJson string
	if calculateLen > 0 {
		b, e := json.Marshal(req.Calculates)
		if e != nil {
			br.Msg = "计算方式格式有误"
			br.ErrMsg = "解析计算方式参数失败, Err: " + e.Error()
			return
		}
		calculatesJson = string(b)
		for _, v := range req.Calculates {
			switch v.Source {
			case utils.EdbBaseCalculateNszydpjjs, utils.EdbBaseCalculateHbz, utils.EdbBaseCalculateHcz, utils.EdbBaseCalculateCjjx:
				if v.Formula == nil {
					br.Msg = "请输入N值"
					return
				}
				formula, ok := v.Formula.(string)
				if !ok {
					br.Msg = "N值格式有误"
					return
				}
				formulaInt, _ := strconv.Atoi(formula)
				if formulaInt <= 0 {
					br.Msg = "N值不可小于0, 重新输入"
					return
				}
			case utils.EdbBaseCalculateExponentialSmoothing:
				if v.Formula == nil {
					br.Msg = "请填写alpha值"
					return
				}
				formula, ok := v.Formula.(string)
				if !ok {
					br.Msg = "alpha值格式有误"
					return
				}
				alpha, _ := strconv.ParseFloat(formula, 64)
				if alpha <= 0 || alpha >= 1 {
					br.Msg = "alpha值应在0-1之间, 请重新输入"
					return
				}
			}
		}
	}
	edbArr, e := data_manage.GetEdbInfoByIdList(req.EdbInfoIds)
	if e != nil {
		br.Msg = "操作失败"
		br.ErrMsg = "获取指标列表失败, Err: " + e.Error()
		return
	}
	if len(edbArr) == 0 {
		br.Msg = "因子指标系列有误"
		br.ErrMsg = "因子指标系列长度为0"
		return
	}

	// 新增指标系列
	seriesItem := new(data_manage.FactorEdbSeries)
	seriesItem.SeriesName = req.SeriesName
	seriesItem.EdbInfoType = req.EdbInfoType
	seriesItem.CreateTime = time.Now().Local()
	seriesItem.ModifyTime = time.Now().Local()
	if calculateLen > 0 {
		seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculating
		seriesItem.CalculateStep = calculatesJson
	}
	mappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
	for _, v := range edbArr {
		mappings = append(mappings, &data_manage.FactorEdbSeriesMapping{
			EdbInfoId:  v.EdbInfoId,
			EdbCode:    v.EdbCode,
			CreateTime: time.Now().Local(),
			ModifyTime: time.Now().Local(),
		})
	}
	seriesId, e := seriesItem.CreateSeriesAndMapping(seriesItem, mappings)
	if e != nil {
		br.Msg = "操作失败"
		br.ErrMsg = "新增因子指标系列失败, Err: " + e.Error()
		return
	}

	// 计算指标数据
	var calculateResp data_manage.FactorEdbSeriesStepCalculateResp
	if calculateLen > 0 {
		calculateResp, e = data.FactorEdbStepCalculate(seriesId, edbArr, req.Calculates, this.Lang, false)
		if e != nil {
			br.Msg = "操作失败"
			br.ErrMsg = "计算因子指标失败, Err: " + e.Error()
			return
		}

		// 更新系列计算状态
		cols := []string{seriesItem.Cols().CalculateState, seriesItem.Cols().ModifyTime}
		seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculated
		seriesItem.ModifyTime = time.Now().Local()
		if e = seriesItem.Update(cols); e != nil {
			br.Msg = "操作失败"
			br.ErrMsg = "更新因子指标系列计算状态失败, Err: " + e.Error()
			return
		}
	} else {
		for _, v := range edbArr {
			calculateResp.Success = append(calculateResp.Success, data_manage.FactorEdbSeriesStepCalculateResult{
				EdbInfoId: v.EdbInfoId,
				EdbCode:   v.EdbCode,
				Msg:       "保存成功",
			})
		}
	}
	calculateResp.SeriesId = seriesId

	br.Data = calculateResp
	br.Ret = 200
	br.Success = true
	br.Msg = "操作成功"
	br.IsAddLog = true
}

// Edit
// @Title 编辑
// @Description 编辑
// @Param	request	body request.EditFactorEdbSeriesReq true "type json string"
// @Success Ret=200 操作成功
// @router /factor_edb_series/edit [post]
func (this *FactorEdbSeriesController) Edit() {
	br := new(models.BaseResponse).Init()
	defer func() {
		if br.ErrMsg == "" {
			br.IsSendEmail = false
		}
		this.Data["json"] = br
		this.ServeJSON()
	}()
	sysUser := this.SysUser
	if sysUser == nil {
		br.Msg = "请登录"
		br.ErrMsg = "请登录,SysUser Is Empty"
		br.Ret = 408
		return
	}
	var req request.EditFactorEdbSeriesReq
	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
		br.Msg = "参数解析异常"
		br.ErrMsg = fmt.Sprintf("参数解析异常, Err: %v", e)
		return
	}
	if req.SeriesId <= 0 {
		br.Msg = "参数有误"
		br.ErrMsg = fmt.Sprintf("参数有误, SeriesId: %d", req.SeriesId)
		return
	}
	req.SeriesName = strings.TrimSpace(req.SeriesName)
	if req.SeriesName == "" {
		br.Msg = "请输入指标系列名称"
		return
	}
	if len(req.EdbInfoIds) <= 0 {
		br.Msg = "请选择因子指标系列"
		return
	}
	if len(req.EdbInfoIds) > 100 {
		br.Msg = "添加指标总数量不得超过100"
		return
	}
	calculateLen := len(req.Calculates)
	if calculateLen > 5 {
		br.Msg = "计算公式不可超过5个"
		return
	}
	var calculatesJson string
	if calculateLen > 0 {
		b, e := json.Marshal(req.Calculates)
		if e != nil {
			br.Msg = "计算方式格式有误"
			br.ErrMsg = "解析计算方式参数失败, Err: " + e.Error()
			return
		}
		calculatesJson = string(b)
		for _, v := range req.Calculates {
			switch v.Source {
			case utils.EdbBaseCalculateNszydpjjs, utils.EdbBaseCalculateHbz, utils.EdbBaseCalculateHcz, utils.EdbBaseCalculateCjjx:
				if v.Formula == nil {
					br.Msg = "请输入N值"
					return
				}
				formula, ok := v.Formula.(string)
				if !ok {
					br.Msg = "N值格式有误"
					return
				}
				formulaInt, _ := strconv.Atoi(formula)
				if formulaInt <= 0 {
					br.Msg = "N值不可小于0, 重新输入"
					return
				}
			case utils.EdbBaseCalculateExponentialSmoothing:
				if v.Formula == nil {
					br.Msg = "请填写alpha值"
					return
				}
				formula, ok := v.Formula.(string)
				if !ok {
					br.Msg = "alpha值格式有误"
					return
				}
				alpha, _ := strconv.ParseFloat(formula, 64)
				if alpha <= 0 || alpha >= 1 {
					br.Msg = "alpha值应在0-1之间, 请重新输入"
					return
				}
			}
		}
	}
	seriesOb := new(data_manage.FactorEdbSeries)
	seriesItem, e := seriesOb.GetItemById(req.SeriesId)
	if e != nil {
		if e.Error() == utils.ErrNoRow() {
			br.Msg = "该因子指标系列不存在"
			return
		}
		br.Msg = "获取失败"
		br.ErrMsg = "获取因子指标系列失败, Err: " + e.Error()
		return
	}

	edbArr, e := data_manage.GetEdbInfoByIdList(req.EdbInfoIds)
	if e != nil {
		br.Msg = "操作失败"
		br.ErrMsg = "获取指标列表失败, Err: " + e.Error()
		return
	}
	if len(edbArr) == 0 {
		br.Msg = "因子指标系列有误"
		br.ErrMsg = "因子指标系列长度为0"
		return
	}
	var calculateResp data_manage.FactorEdbSeriesStepCalculateResp
	calculateResp.SeriesId = seriesItem.FactorEdbSeriesId

	// 如果不需要进行重新计算(比如只改了系列名称)那么只更新指标系列
	seriesItem.SeriesName = req.SeriesName
	seriesItem.EdbInfoType = req.EdbInfoType
	seriesItem.ModifyTime = time.Now().Local()
	updateCols := []string{seriesOb.Cols().SeriesName, seriesOb.Cols().EdbInfoType, seriesOb.Cols().ModifyTime}
	if !req.Recalculate {
		if e = seriesItem.Update(updateCols); e != nil {
			br.Msg = "操作成功"
			br.ErrMsg = "更新因子指标系列信息失败, Err: " + e.Error()
			return
		}
		for _, v := range edbArr {
			calculateResp.Success = append(calculateResp.Success, data_manage.FactorEdbSeriesStepCalculateResult{
				EdbInfoId: v.EdbInfoId,
				EdbCode:   v.EdbCode,
				Msg:       "保存成功",
			})
		}
		br.Data = calculateResp
		br.Ret = 200
		br.Success = true
		br.Msg = "操作成功"
		return
	}

	// 更新系列信息和指标关联
	if calculateLen > 0 {
		seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculating
		seriesItem.CalculateStep = calculatesJson
		updateCols = append(updateCols, seriesOb.Cols().CalculateState, seriesOb.Cols().CalculateStep)
	}
	mappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
	for _, v := range edbArr {
		mappings = append(mappings, &data_manage.FactorEdbSeriesMapping{
			EdbInfoId:  v.EdbInfoId,
			EdbCode:    v.EdbCode,
			CreateTime: time.Now().Local(),
			ModifyTime: time.Now().Local(),
		})
	}
	if e = seriesItem.EditSeriesAndMapping(seriesItem, mappings, updateCols); e != nil {
		br.Msg = "操作失败"
		br.ErrMsg = "编辑因子指标系列失败, Err: " + e.Error()
		return
	}

	// 重新计算
	calculateResp, e = data.FactorEdbStepCalculate(seriesItem.FactorEdbSeriesId, edbArr, req.Calculates, this.Lang, req.Recalculate)
	if e != nil {
		br.Msg = "操作失败"
		br.ErrMsg = "计算因子指标失败, Err: " + e.Error()
		return
	}

	// 更新系列计算状态
	cols := []string{seriesItem.Cols().CalculateState, seriesItem.Cols().ModifyTime}
	seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculated
	seriesItem.ModifyTime = time.Now().Local()
	if e = seriesItem.Update(cols); e != nil {
		br.Msg = "操作失败"
		br.ErrMsg = "更新因子指标系列计算状态失败, Err: " + e.Error()
		return
	}

	br.Data = calculateResp
	br.Ret = 200
	br.Success = true
	br.Msg = "操作成功"
	br.IsAddLog = true
}

// Detail
// @Title 详情
// @Description 详情
// @Param   SeriesId  query  int  false  "多因子指标系列ID"
// @Success 200 {object} data_manage.FactorEdbSeriesDetail
// @router /factor_edb_series/detail [get]
func (this *FactorEdbSeriesController) Detail() {
	br := new(models.BaseResponse).Init()
	defer func() {
		if br.ErrMsg == "" {
			br.IsSendEmail = false
		}
		this.Data["json"] = br
		this.ServeJSON()
	}()
	sysUser := this.SysUser
	if sysUser == nil {
		br.Msg = "请登录"
		br.ErrMsg = "请登录,SysUser Is Empty"
		br.Ret = 408
		return
	}
	seriesId, _ := this.GetInt("SeriesId", 0)
	if seriesId <= 0 {
		br.Msg = "参数有误"
		br.ErrMsg = fmt.Sprintf("参数有误, SeriesId: %d", seriesId)
		return
	}

	seriesOb := new(data_manage.FactorEdbSeries)
	series, e := seriesOb.GetItemById(seriesId)
	if e != nil {
		if e.Error() == utils.ErrNoRow() {
			br.Msg = "该因子指标系列不存在"
			return
		}
		br.Msg = "获取失败"
		br.ErrMsg = "获取因子指标系列失败, Err: " + e.Error()
		return
	}

	mappingOb := new(data_manage.FactorEdbSeriesMapping)
	cond := fmt.Sprintf(" AND %s = ?", mappingOb.Cols().FactorEdbSeriesId)
	pars := make([]interface{}, 0)
	pars = append(pars, seriesId)
	mappings, e := mappingOb.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC", mappingOb.Cols().CreateTime))
	if e != nil {
		br.Msg = "获取失败"
		br.ErrMsg = "获取因子指标系列关联失败, Err: " + e.Error()
		return
	}

	resp := new(data_manage.FactorEdbSeriesDetail)
	resp.FactorEdbSeriesItem = series.Format2Item()
	for _, m := range mappings {
		resp.EdbMappings = append(resp.EdbMappings, m.Format2Item())
	}

	br.Data = resp
	br.Ret = 200
	br.Success = true
	br.Msg = "获取成功"
}

// CorrelationMatrix
// @Title 因子指标系列-相关性矩阵
// @Description 因子指标系列-相关性矩阵
// @Param	request	body request.FactorEdbSeriesCorrelationMatrixReq true "type json string"
// @Success 200 {object} data_manage.FactorEdbSeriesCorrelationMatrixItem
// @router /factor_edb_series/correlation/matrix [post]
func (this *FactorEdbSeriesController) CorrelationMatrix() {
	br := new(models.BaseResponse).Init()
	defer func() {
		if br.ErrMsg == "" {
			br.IsSendEmail = false
		}
		this.Data["json"] = br
		this.ServeJSON()
	}()
	sysUser := this.SysUser
	if sysUser == nil {
		br.Msg = "请登录"
		br.ErrMsg = "请登录,SysUser Is Empty"
		br.Ret = 408
		return
	}
	var req request.FactorEdbSeriesCorrelationMatrixReq
	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
		br.Msg = "参数解析异常"
		br.ErrMsg = fmt.Sprintf("参数解析异常, Err: %v", e)
		return
	}
	if req.BaseEdbInfoId <= 0 {
		br.Msg = "请选择标的指标"
		return
	}
	if len(req.SeriesIds) == 0 {
		br.Msg = "请选择因子指标系列"
		return
	}
	if req.Correlation.LeadValue <= 0 {
		br.Msg = "分析周期不允许设置为负数或0"
		return
	}
	if req.Correlation.LeadUnit == "" {
		br.Msg = "请选择分析周期频度"
		return
	}
	leadUnitDays, ok := utils.FrequencyDaysMap[req.Correlation.LeadUnit]
	if !ok {
		br.Msg = "错误的分析周期频度"
		br.ErrMsg = fmt.Sprintf("分析周期频度有误: %s", req.Correlation.LeadUnit)
		return
	}

	if req.Correlation.CalculateUnit == "" {
		br.Msg = "请选择计算窗口频度"
		return
	}
	calculateUnitDays, ok := utils.FrequencyDaysMap[req.Correlation.CalculateUnit]
	if !ok {
		br.Msg = "错误的计算窗口频度"
		br.ErrMsg = fmt.Sprintf("计算窗口频度有误: %s", req.Correlation.CalculateUnit)
		return
	}
	leadDays := 2 * req.Correlation.LeadValue * leadUnitDays
	calculateDays := req.Correlation.CalculateValue * calculateUnitDays
	if calculateDays < leadDays {
		br.Msg = "计算窗口必须≥2*分析周期"
		return
	}

	// 获取标的指标信息及数据
	baseEdb, e := data_manage.GetEdbInfoById(req.BaseEdbInfoId)
	if e != nil {
		if e.Error() == utils.ErrNoRow() {
			br.Msg = "标的指标不存在"
			return
		}
		br.Msg = "获取失败"
		br.ErrMsg = "获取标的指标信息失败, Err: " + e.Error()
		return
	}
	dataListA := make([]*data_manage.EdbDataList, 0)
	{
		// 标的指标数据日期区间
		startDate := time.Now().AddDate(0, 0, -calculateDays).Format(utils.FormatDate)
		endDate := time.Now().Format(utils.FormatDate)
		startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
		startDate = startDateTime.AddDate(0, 0, 1).Format(utils.FormatDate) // 不包含第一天
		switch baseEdb.EdbInfoType {
		case 0:
			dataListA, e = data_manage.GetEdbDataList(baseEdb.Source, baseEdb.SubSource, baseEdb.EdbInfoId, startDate, endDate)
		case 1:
			_, dataListA, _, _, e, _ = data.GetPredictDataListByPredictEdbInfoId(baseEdb.EdbInfoId, startDate, endDate, false)
		default:
			br.Msg = "获取失败"
			br.ErrMsg = fmt.Sprintf("标的指标类型异常: %d", baseEdb.EdbInfoType)
			return
		}
		if e != nil {
			br.Msg = "获取失败"
			br.ErrMsg = "获取标的指标数据失败, Err:" + e.Error()
			return
		}
	}

	// 获取因子系列
	seriesIdItem := make(map[int]*data_manage.FactorEdbSeries)
	{
		ob := new(data_manage.FactorEdbSeries)
		cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().PrimaryId, utils.GetOrmInReplace(len(req.SeriesIds)))
		pars := make([]interface{}, 0)
		pars = append(pars, req.SeriesIds)
		items, e := ob.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC", ob.Cols().PrimaryId))
		if e != nil {
			br.Msg = "获取失败"
			br.ErrMsg = "获取因子指标系列失败, Err: " + e.Error()
			return
		}
		if len(items) != len(req.SeriesIds) {
			br.Msg = "获取失败"
			br.ErrMsg = "因子指标系列数量有误"
			return
		}
		for _, v := range items {
			seriesIdItem[v.FactorEdbSeriesId] = v
		}
	}

	// 获取因子指标
	edbMappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
	edbInfoIds := make([]int, 0)
	{
		ob := new(data_manage.FactorEdbSeriesMapping)
		cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(req.SeriesIds)))
		pars := make([]interface{}, 0)
		pars = append(pars, req.SeriesIds)
		order := fmt.Sprintf("%s ASC, %s ASC", ob.Cols().FactorEdbSeriesId, ob.Cols().EdbInfoId)
		items, e := ob.GetItemsByCondition(cond, pars, []string{}, order)
		if e != nil {
			br.Msg = "获取失败"
			br.ErrMsg = "获取因子指标关联失败, Err: " + e.Error()
			return
		}
		for _, v := range items {
			edbInfoIds = append(edbInfoIds, v.EdbInfoId)
		}
		edbMappings = items
	}
	edbIdItem := make(map[int]*data_manage.EdbInfo)
	edbItems, e := data_manage.GetEdbInfoByIdList(edbInfoIds)
	if e != nil {
		br.Msg = "获取失败"
		br.ErrMsg = "获取因子指标失败, Err: " + e.Error()
		return
	}
	for _, v := range edbItems {
		edbIdItem[v.EdbInfoId] = v
	}

	// 获取因子指标数据, 计算相关性
	resp := new(data_manage.FactorEdbSeriesCorrelationMatrixResp)
	calculateDataOb := new(data_manage.FactorEdbSeriesCalculateData)

	calculateWorkers := make(chan struct{}, 10)
	wg := sync.WaitGroup{}
	edbExists := make(map[string]bool)
	chartKeyMap := make(map[string]*data_manage.FactorEdbSeriesChartMapping)
	for _, v := range edbMappings {
		existsKey := fmt.Sprintf("%d-%d", v.FactorEdbSeriesId, v.EdbInfoId)
		if edbExists[existsKey] {
			continue
		}
		edbExists[existsKey] = true

		edbItem := edbIdItem[v.EdbInfoId]
		if edbItem == nil {
			continue
		}
		seriesItem := seriesIdItem[v.FactorEdbSeriesId]
		if seriesItem == nil {
			continue
		}

		wg.Add(1)
		go func(mapping *data_manage.FactorEdbSeriesMapping, edb *data_manage.EdbInfo, series *data_manage.FactorEdbSeries) {
			defer func() {
				wg.Done()
				<-calculateWorkers
			}()
			calculateWorkers <- struct{}{}

			var item data_manage.FactorEdbSeriesCorrelationMatrixItem
			item.SeriesId = series.FactorEdbSeriesId
			item.EdbInfoId = edb.EdbInfoId
			item.EdbCode = edb.EdbCode
			item.EdbName = edb.EdbName

			// 指标来源
			edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
			edbList = append(edbList, &data_manage.ChartEdbInfoMapping{
				EdbInfoId:           edb.EdbInfoId,
				EdbInfoCategoryType: edb.EdbInfoType,
				EdbType:             edb.EdbType,
				Source:              edb.Source,
				SourceName:          edb.SourceName,
			})
			sourceNameList, sourceNameEnList := data.GetEdbSourceByEdbInfoIdList(edbList)
			item.SourceName = strings.Join(sourceNameList, ",")
			item.SourceNameEn = strings.Join(sourceNameEnList, ",")

			// 获取指标数据
			dataListB := make([]*data_manage.EdbDataList, 0)
			if series.CalculateState == data_manage.FactorEdbSeriesCalculated {
				cond := fmt.Sprintf(" AND %s = ? AND %s = ?", calculateDataOb.Cols().FactorEdbSeriesId, calculateDataOb.Cols().EdbInfoId)
				pars := make([]interface{}, 0)
				pars = append(pars, mapping.FactorEdbSeriesId, mapping.EdbInfoId)
				dataItems, e := calculateDataOb.GetItemsByCondition(cond, pars, []string{calculateDataOb.Cols().DataTime, calculateDataOb.Cols().Value}, fmt.Sprintf("%s ASC", calculateDataOb.Cols().DataTime))
				if e != nil {
					item.Msg = fmt.Sprintf("计算失败")
					item.ErrMsg = fmt.Sprintf("获取计算数据失败, err: %v", e)
					resp.Fail = append(resp.Fail, item)
					return
				}
				dataListB = data_manage.TransEdbSeriesCalculateData2EdbDataList(dataItems)
			} else {
				switch edb.EdbInfoType {
				case 0:
					dataListB, e = data_manage.GetEdbDataList(edb.Source, edb.SubSource, edb.EdbInfoId, "", "")
				case 1:
					_, dataListB, _, _, e, _ = data.GetPredictDataListByPredictEdbInfoId(edb.EdbInfoId, "", "", false)
				default:
					item.Msg = fmt.Sprintf("计算失败")
					item.ErrMsg = fmt.Sprintf("指标类型异常, edbType: %d", edb.EdbInfoType)
					resp.Fail = append(resp.Fail, item)
					return
				}
			}

			// 计算相关性
			xEdbIdValue, yDataList, e := correlationServ.CalculateCorrelation(req.Correlation.LeadValue, req.Correlation.LeadUnit, baseEdb.Frequency, edb.Frequency, dataListA, dataListB)
			if e != nil {
				item.Msg = fmt.Sprintf("计算失败")
				item.ErrMsg = fmt.Sprintf("相关性计算失败, err: %v", e)
				resp.Fail = append(resp.Fail, item)
				return
			}

			// X及Y轴数据
			yData := yDataList[0].Value
			yLen := len(yData)
			values := make([]data_manage.FactorEdbSeriesCorrelationMatrixValues, len(xEdbIdValue))
			for k, x := range xEdbIdValue {
				var y float64
				if k >= 0 && k < yLen {
					y = yData[k]
				}
				y = utils.SubFloatToFloat(y, 2)
				values[k] = data_manage.FactorEdbSeriesCorrelationMatrixValues{
					XData: x, YData: y,
				}
			}

			// 图表关联-此处添加的chart_info_id=0
			newMapping := new(data_manage.FactorEdbSeriesChartMapping)
			newMapping.CalculateType = data_manage.FactorEdbSeriesChartCalculateTypeCorrelation

			// 计算参数
			var calculatePars data_manage.FactorEdbSeriesChartCalculateCorrelationReq
			calculatePars.BaseEdbInfoId = req.BaseEdbInfoId
			calculatePars.LeadValue = req.Correlation.LeadValue
			calculatePars.LeadUnit = req.Correlation.LeadUnit
			calculatePars.CalculateValue = req.Correlation.CalculateValue
			calculatePars.CalculateUnit = req.Correlation.CalculateUnit
			bc, e := json.Marshal(calculatePars)
			if e != nil {
				item.Msg = fmt.Sprintf("计算失败")
				item.ErrMsg = fmt.Sprintf("计算参数JSON格式化失败, err: %v", e)
				resp.Fail = append(resp.Fail, item)
				return
			}
			newMapping.CalculatePars = string(bc)

			// 计算结果, 注此处保存的是排序前的顺序
			bv, e := json.Marshal(values)
			if e != nil {
				item.Msg = fmt.Sprintf("计算失败")
				item.ErrMsg = fmt.Sprintf("计算结果JSON格式化失败, err: %v", e)
				resp.Fail = append(resp.Fail, item)
				return
			}
			newMapping.CalculateData = string(bv)
			newMapping.FactorEdbSeriesId = mapping.FactorEdbSeriesId
			newMapping.EdbInfoId = mapping.EdbInfoId
			newMapping.CreateTime = time.Now().Local()
			newMapping.ModifyTime = time.Now().Local()
			chartKeyMap[existsKey] = newMapping

			// 按照固定规则排期数[0 1 2 3 -1 -2 -3], 仅矩阵展示为此顺序
			sort.Sort(data_manage.FactorEdbSeriesCorrelationMatrixOrder(values))
			item.Msg = "计算成功"
			item.Values = values
			resp.Success = append(resp.Success, item)
		}(v, edbItem, seriesItem)
	}
	wg.Wait()

	// 新增图表关联, 此处按照顺序添加
	chartMappings := make([]*data_manage.FactorEdbSeriesChartMapping, 0)
	for _, v := range edbMappings {
		k := fmt.Sprintf("%d-%d", v.FactorEdbSeriesId, v.EdbInfoId)
		item := chartKeyMap[k]
		if item == nil {
			continue
		}
		chartMappings = append(chartMappings, item)
	}
	chartMappingOb := new(data_manage.FactorEdbSeriesChartMapping)
	if e = chartMappingOb.ClearAndCreateMapping(req.SeriesIds, chartMappings); e != nil {
		br.Msg = "获取失败"
		br.ErrMsg = fmt.Sprintf("新增图表关联失败, Err: %v", e)
		return
	}

	br.Data = resp
	br.Ret = 200
	br.Success = true
	br.Msg = "获取成功"
}