package services

import (
	"encoding/json"
	"errors"
	"eta/eta_api/models/data_manage"
	excelModel "eta/eta_api/models/data_manage/excel"
	"eta/eta_api/models/data_manage/excel/request"
	"eta/eta_api/services/alarm_msg"
	"eta/eta_api/services/data"
	"eta/eta_api/services/sandbox"
	"eta/eta_api/utils"
	"fmt"
	"strconv"
	"time"
)

// 全局的指标替换
func DealReplaceEdbCache() {
	var err error
	for {
		utils.Rc.Brpop(utils.CACHE_KEY_REPLACE_EDB, func(b []byte) {
			defer func() {
				if err != nil {
					utils.FileLog.Info("DealReplaceEdbCache err:" + err.Error())
					go alarm_msg.SendAlarmMsg("替换表格中的指标失败提醒,errmsg:"+err.Error(), 3)
				}
			}()
			record := new(data_manage.ReplaceEdbInfoItem)
			if err = json.Unmarshal(b, &record); err != nil {
				fmt.Println("json unmarshal wrong!")
				return
			}
			oldEdbInfo := record.OldEdbInfo
			newEdbInfo := record.NewEdbInfo
			utils.FileLog.Info(fmt.Sprintf("指标开始替换 DealReplaceEdbCache: 旧指标ID:%d,新指标ID:%d", oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId))
			deleteCache := true
			setNxKey := fmt.Sprintf("EDB_INFO_REPLACE:%d-%d", oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId)
			defer func() {
				if deleteCache {
					utils.Rc.Delete(setNxKey)
				}
			}()
			if !utils.Rc.SetNX(setNxKey, 1, 30*time.Minute) {
				deleteCache = false
				err = fmt.Errorf("替换表格中的指标失败旧指标:%d为新指标%d:正在处理中", oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId)
				return
			}

			// 替换相关性图表配置
			_, err = data_manage.ReplaceMultipleGraphConfigChartEdb(oldEdbInfo, newEdbInfo)
			if err != nil {
				err = fmt.Errorf("替换相关性图表配置失败,errmsg:%s", err.Error())
				return
			}
			// 替换拟合方程指标
			_, err = data_manage.ReplaceEdbInfoInLineEquationMultipleGraphConfig(oldEdbInfo, newEdbInfo)
			if err != nil {
				err = fmt.Errorf("替换拟合方程指标失败,errmsg:%s", err.Error())
				return
			}

			// 替换表格中的指标
			err = ReplaceEdbInExcel(oldEdbInfo, newEdbInfo)
			if err != nil {
				err = fmt.Errorf("替换表格中的指标失败,errmsg:%s", err.Error())
				return
			}

			//替换逻辑图中的指标
			err = sandbox.ReplaceEdbInSandbox(oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId)
			if err != nil {
				err = fmt.Errorf("替换逻辑图中的指标失败,errmsg:%s", err.Error())
				return
			}

			// todo 重置指标引用表
			ReplaceEdbInRelation(oldEdbInfo, newEdbInfo)
		})
	}
}

// ReplaceEdbInExcel 替换表格中的指标
func ReplaceEdbInExcel(oldEdbInfo, newEdbInfo *data_manage.EdbInfo) (err error) {
	defer func() {
		if err != nil {
			go alarm_msg.SendAlarmMsg("替换表格中的指标失败提醒,errmsg:"+err.Error(), 3)
		}
	}()
	//查询和指标相关的时间序列表格和混合表格
	mappingList, err := excelModel.GetExcelEdbMappingByEdbInfoIdAndSource(oldEdbInfo.EdbInfoId, []int{utils.TIME_TABLE, utils.MIXED_TABLE})
	if err != nil {
		err = fmt.Errorf("查询和指标相关的表格失败,错误:%s", err.Error())
		return
	}
	updateList := make([]*excelModel.ExcelInfo, 0)
	// 循环列表,根据表格类型单独处理
	for _, excelMapping := range mappingList {
		//查询和指标相关的混合表格
		excelInfo, tmpErr := excelModel.GetExcelInfoById(excelMapping.ExcelInfoId)
		if tmpErr != nil {
			err = fmt.Errorf("查询和指标相关的混合表格失败,错误:%s", tmpErr.Error())
			return
		}
		// 清除缓存
		key := utils.HZ_CHART_LIB_EXCEL_TABLE_DETAIL + ":" + excelInfo.UniqueCode
		if utils.Re == nil {
			_ = utils.Rc.Delete(key)
		}
		// 根据表格类型,调用不同的处理函数
		switch excelMapping.Source {
		case utils.TIME_TABLE: // 时间序列表格
			// 替换余额表格中的指标
			newExcelInfo, e := replaceEdbInTimeExcel(oldEdbInfo, newEdbInfo, excelInfo)
			if e != nil {
				err = fmt.Errorf("替换余额表格中的指标失败,错误:%s", e.Error())
				return
			}
			updateList = append(updateList, newExcelInfo)
		case utils.MIXED_TABLE, utils.BALANCE_TABLE:
			// 替换余额表格中的指标
			newExcelInfo, e := replaceEdbInBalanceExcel(oldEdbInfo, newEdbInfo, excelInfo)
			if e != nil {
				err = fmt.Errorf("替换余额表格中的指标失败,错误:%s", e.Error())
				return
			}
			updateList = append(updateList, newExcelInfo)
		default:
			// 其他表格类型的处理逻辑
		}
	}

	err = excelModel.ReplaceEdbInExcel(oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId, updateList)
	if err != nil {
		err = fmt.Errorf("替换表格中的指标失败,错误:%s", err.Error())
		return
	}

	//todo 是否需要刷新表格中的指标数据
	return
}

func replaceEdbInBalanceExcel(oldEdbInfo, newEdbInfo *data_manage.EdbInfo, excelInfo *excelModel.ExcelInfo) (newExcelInfo *excelModel.ExcelInfo, err error) {
	newExcelInfo = excelInfo
	var mixedTableReq request.MixedTableReq
	err = json.Unmarshal([]byte(excelInfo.Content), &mixedTableReq)
	if err != nil {
		err = fmt.Errorf("表格json转结构体失败,Err:" + err.Error())
		return
	}
	// 处理data
	configList := mixedTableReq.Data
	for ck, rowList := range configList {
		for rk, cell := range rowList {
			switch cell.DataType {
			case request.EdbDT: // 指标信息
				if cell.EdbInfoId == oldEdbInfo.EdbInfoId {
					//更换成新指标ID
					configList[ck][rk].EdbInfoId = newEdbInfo.EdbInfoId
				}
			case request.InsertDataDT, request.PopInsertDataDT: // 插值、弹框插值
				if cell.EdbInfoId == oldEdbInfo.EdbInfoId {
					//更换成新指标ID
					configList[ck][rk].EdbInfoId = newEdbInfo.EdbInfoId
				}
			case request.InsertEdbCalculateDataDT: // 插入指标计算公式生成的值
				var config request.CalculateConf
				err = json.Unmarshal([]byte(cell.Value), &config)
				if err != nil {
					return
				}
				if cell.EdbInfoId == oldEdbInfo.EdbInfoId {
					//更换成新指标ID
					configList[ck][rk].EdbInfoId = newEdbInfo.EdbInfoId
				}
				if config.EdbInfoId == oldEdbInfo.EdbInfoId {
					config.EdbInfoId = newEdbInfo.EdbInfoId
					var configStr []byte
					configStr, err = json.Marshal(config)
					if err != nil {
						return
					}
					configList[ck][rk].Value = string(configStr)
				}

			case request.DateDT: // 日期类型
				// 指标日期类型的单元格需要额外将指标id取出来
				if cell.DataTimeType == request.EdbDateDT {
					var config request.EdbDateConf
					err = json.Unmarshal([]byte(cell.Value), &config)
					if err != nil {
						return
					}
					if config.EdbInfoId == oldEdbInfo.EdbInfoId {
						config.EdbInfoId = newEdbInfo.EdbInfoId
						var configStr []byte
						configStr, err = json.Marshal(config)
						if err != nil {
							return
						}
						configList[ck][rk].Value = string(configStr)
					}
				}
			}
		}
	}

	mixedTableReq.Data = configList
	var newContentByte []byte
	newContentByte, err = json.Marshal(mixedTableReq)
	if err != nil {
		return
	}
	// 生成的新内容替换原先的旧内容
	excelInfo.Content = string(newContentByte)
	newExcelInfo = excelInfo
	return
}

func replaceEdbInTimeExcel(oldEdbInfo, newEdbInfo *data_manage.EdbInfo, excelInfo *excelModel.ExcelInfo) (newExcelInfo *excelModel.ExcelInfo, err error) {
	newExcelInfo = excelInfo

	var tableDataConfig request.TimeTableDataConfig
	err = json.Unmarshal([]byte(excelInfo.Content), &tableDataConfig)
	if err != nil {
		err = errors.New("表格json转结构体失败,Err:" + err.Error())
		return
	}
	if len(tableDataConfig.EdbInfoIdList) <= 0 {
		return
	}
	// 实际期数没有的情况下,直接返回吧
	if tableDataConfig.Num <= 0 {
		return
	}

	// 先处理edbInfoList
	for k, id := range tableDataConfig.EdbInfoIdList {
		if id == oldEdbInfo.EdbInfoId {
			tableDataConfig.EdbInfoIdList[k] = newEdbInfo.EdbInfoId
		}
	}

	// 先处理tableEdbInfoList
	for k, tableEdbInfo := range tableDataConfig.TableEdbInfoList {
		if tableEdbInfo.EdbInfoId == oldEdbInfo.EdbInfoId {
			tableDataConfig.TableEdbInfoList[k].EdbInfoId = newEdbInfo.EdbInfoId
		}
	}

	var newContentByte []byte
	newContentByte, err = json.Marshal(tableDataConfig)
	if err != nil {
		return
	}
	// 生成的新内容替换原先的旧内容
	excelInfo.Content = string(newContentByte)
	newExcelInfo = excelInfo
	return
}

func ReplaceEdbInRelation(oldEdbInfo, newEdbInfo *data_manage.EdbInfo) {
	var err error
	var logMsg string
	var replaceTotal int
	defer func() {
		if err != nil {
			msg := fmt.Sprintf(" 替换指标引用表中的指标,并修改引用时间 replaceEdbInRelation  err: %v", err)
			utils.FileLog.Info(msg)
			fmt.Println(msg)
			go alarm_msg.SendAlarmMsg(msg, 3)
		}
		if logMsg != `` {
			utils.FileLog.Info(fmt.Sprintf("替换指标引用表中的指标记录 替换总数%d,旧的指标id:%d,新的指标id:%d;涉及到的引用id:%s", replaceTotal, oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId, logMsg))
		}
	}()

	calculateEdbMappingListMap := make(map[int]*data_manage.EdbInfoCalculateMapping)
	calculateEdbMappingIdsMap := make(map[int][]int)
	childEdbMappingIds := make([]int, 0)
	//indexCodeList := make([]string, 0)
	//refreshIds := make([]int, 0)

	//分页查询,每次处理500条记录
	pageSize := 500

	// 替换直接引用中的指标
	if newEdbInfo.EdbType == 2 {
		edbInfoList := make([]*data_manage.EdbInfo, 0)
		edbInfoList = append(edbInfoList, newEdbInfo)
		calculateEdbMappingListMap, calculateEdbMappingIdsMap, err = data.GetEdbListByEdbInfoId(edbInfoList, false)
		if err != nil {
			err = fmt.Errorf("查询指标关联指标列表失败 Err:%s", err)
			return
		}
		var ok bool
		childEdbMappingIds, ok = calculateEdbMappingIdsMap[newEdbInfo.EdbInfoId]
		if !ok {
			err = fmt.Errorf("查询%d指标关联指标列表为空", newEdbInfo.EdbInfoId)
			return
		}
	}
	total, err := data_manage.GetReplaceEdbInfoRelationTotal(oldEdbInfo.EdbInfoId)
	if err != nil {
		err = fmt.Errorf("查询引用表中关联的指标总数失败 err: %v", err)
		return
	}
	totalPage := 0
	if total > 0 {
		totalPage = (total + pageSize - 1) / pageSize // 使用整数除法,并添加一页以防有余数
		//查询图表列表
		for i := 0; i < totalPage; i += 1 {
			startSize := i * pageSize
			list, e := data_manage.GetReplaceEdbInfoRelationList(oldEdbInfo.EdbInfoId, startSize, pageSize)
			if e != nil {
				err = fmt.Errorf("查询图表关联指标列表失败 Err:%s", e)
				return
			}
			if len(list) == 0 {
				break
			}
			replaceTotal1, logMsg1, e := replaceEdbInRelation(oldEdbInfo, newEdbInfo, list, childEdbMappingIds, calculateEdbMappingListMap)
			if e != nil {
				err = e
				return
			}
			replaceTotal += replaceTotal1
			logMsg += logMsg1
		}
	}

	// 更新间接引用中的指标
	//查询相关的记录总数
	total, err = data_manage.GetReplaceChildEdbInfoRelationTotal(oldEdbInfo.EdbInfoId)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = nil
		} else {
			err = fmt.Errorf("查询引用表中关联的指标总数失败 err: %v", err)
			return
		}
	}
	if total > 0 {
		totalPage = (total + pageSize - 1) / pageSize // 使用整数除法,并添加一页以防有余数
		//查询列表
		for i := 0; i < totalPage; i += 1 {
			startSize := i * pageSize
			tmpList, e := data_manage.GetReplaceChildEdbInfoRelationList(oldEdbInfo.EdbInfoId, startSize, pageSize)
			if e != nil {
				err = fmt.Errorf("查询图表关联指标列表失败 Err:%s", e)
				return
			}
			// 查询直接引用
			relationIds := make([]int, 0)
			for _, v := range tmpList {
				relationIds = append(relationIds, v.ParentRelationId)
			}
			if len(relationIds) > 0 {
				list, e := data_manage.GetEdbInfoRelationByRelationIds(relationIds)
				if e != nil {
					err = fmt.Errorf("查询图表关联指标列表失败 Err:%s", e)
					return
				}
				//查询直接引用指标关联关系
				edbInfoListMap := make(map[int]struct{})
				edbInfoIds := make([]int, 0)
				for _, v := range list {
					if _, ok := edbInfoListMap[v.EdbInfoId]; !ok {
						edbInfoListMap[v.EdbInfoId] = struct{}{}
						edbInfoIds = append(edbInfoIds, v.EdbInfoId)
					}
				}
				edbInfoList := make([]*data_manage.EdbInfo, 0)
				if len(edbInfoIds) > 0 {
					// 查询指标信息
					edbInfoList, err = data_manage.GetEdbInfoByIdList(edbInfoIds)
					if err != nil {
						err = fmt.Errorf("查询指标信息失败 Err:%s", err)
						return
					}
				}
				calculateEdbMappingListMap, calculateEdbMappingIdsMap, err = data.GetEdbListByEdbInfoId(edbInfoList, false)
				if err != nil {
					err = fmt.Errorf("查询指标关联指标列表失败 Err:%s", err)
					return
				}

				//如何过滤掉只有间接引用,没有直接引用的
				replaceTotal1, logMsg1, e := UpdateSecondEdbInRelation(list, calculateEdbMappingListMap, calculateEdbMappingIdsMap, edbInfoList)
				if e != nil {
					err = e
					return
				}
				replaceTotal += replaceTotal1
				logMsg += logMsg1
			}
		}
	}

	return
}

// 完成直接引用中的指标替换工程
func replaceEdbInRelation(oldEdbInfo, newEdbInfo *data_manage.EdbInfo, list []*data_manage.EdbInfoRelation, childEdbMappingIds []int, calculateEdbMappingListMap map[int]*data_manage.EdbInfoCalculateMapping) (replaceTotal int, logMsg string, err error) {
	replaceEdbIds := make([]int, 0)
	//calculateEdbMappingListMap := make(map[int]*data_manage.EdbInfoCalculateMapping)
	//calculateEdbMappingIdsMap := make(map[int][]int)
	//childEdbMappingIds := make([]int, 0)
	indexCodeList := make([]string, 0)
	addList := make([]*data_manage.EdbInfoRelation, 0)
	refreshIds := make([]int, 0)
	nowTime := time.Now()
	for _, v := range list {
		replaceEdbIds = append(replaceEdbIds, v.EdbInfoRelationId)
		if newEdbInfo.EdbType == 2 {
			for _, childEdbMappingId := range childEdbMappingIds {
				childEdbMapping, ok2 := calculateEdbMappingListMap[childEdbMappingId]
				if !ok2 {
					continue
				}

				if childEdbMapping.FromSource == utils.DATA_SOURCE_MYSTEEL_CHEMICAL {
					indexCodeList = append(indexCodeList, childEdbMapping.FromEdbCode)
				}
				tmp1 := &data_manage.EdbInfoRelation{
					ReferObjectId:      v.ReferObjectId,
					ReferObjectType:    v.ReferObjectType,
					ReferObjectSubType: v.ReferObjectSubType,
					EdbInfoId:          childEdbMapping.FromEdbInfoId,
					EdbName:            childEdbMapping.FromEdbName,
					Source:             childEdbMapping.FromSource,
					EdbCode:            childEdbMapping.FromEdbCode,
					CreateTime:         nowTime,
					ModifyTime:         nowTime,
					RelationTime:       nowTime,
					RelationType:       1,
					RootEdbInfoId:      newEdbInfo.EdbInfoId,
					ChildEdbInfoId:     childEdbMapping.EdbInfoId,
				}
				tmp1.RelationCode = fmt.Sprintf("%d_%d_%d_%d", tmp1.RootEdbInfoId, tmp1.ReferObjectId, tmp1.ReferObjectType, tmp1.ReferObjectSubType)
				addList = append(addList, tmp1)
				refreshIds = append(refreshIds, childEdbMapping.FromEdbInfoId)
				// todo 防止重复
			}
		}
		logMsg += strconv.Itoa(v.EdbInfoRelationId) + ";"
	}
	if len(replaceEdbIds) > 0 {
		err = data_manage.ReplaceRelationEdbInfoId(oldEdbInfo, newEdbInfo, replaceEdbIds, addList, refreshIds, indexCodeList)
		if err != nil {
			logMsg = ""
			err = fmt.Errorf("替换指标引用表中的指标ID失败 Err:%s", err)
			return
		}
		replaceTotal = len(replaceEdbIds)
	}
	return
}

func UpdateSecondEdbInRelation(list []*data_manage.EdbInfoRelation, calculateEdbMappingListMap map[int]*data_manage.EdbInfoCalculateMapping, calculateEdbMappingIdsMap map[int][]int, edbInfoList []*data_manage.EdbInfo) (replaceTotal int, logMsg string, err error) {
	nowTime := time.Now()
	edbInfoRelationIds := make([]int, 0)
	indexCodeList := make([]string, 0)
	addList := make([]*data_manage.EdbInfoRelation, 0)
	refreshIds := make([]int, 0)
	edbInfoMap := make(map[int]*data_manage.EdbInfo)
	for _, v := range edbInfoList {
		edbInfoMap[v.EdbInfoId] = v
	}
	// 查询所有的直接引用,删除所有的间接引用,添加所有直接引用的间接引用
	for _, v := range list {
		if v.RelationType == 0 {
			edbInfoRelationIds = append(edbInfoRelationIds, v.EdbInfoRelationId)
			edbInfo, ok := edbInfoMap[v.EdbInfoId]
			if !ok {
				err = fmt.Errorf("查询指标信息失败 EdbInfoId:%d", v.EdbInfoId)
				return
			}
			if edbInfo.EdbType == 2 { //计算指标
				childEdbMappingIds, ok := calculateEdbMappingIdsMap[edbInfo.EdbInfoId]
				if !ok {
					err = fmt.Errorf("查询%d指标关联指标列表为空", edbInfo.EdbInfoId)
					return
				}
				for _, childEdbMappingId := range childEdbMappingIds {
					childEdbMapping, ok2 := calculateEdbMappingListMap[childEdbMappingId]
					if !ok2 {
						continue
					}

					if childEdbMapping.FromSource == utils.DATA_SOURCE_MYSTEEL_CHEMICAL {
						indexCodeList = append(indexCodeList, childEdbMapping.FromEdbCode)
					}
					tmp1 := &data_manage.EdbInfoRelation{
						ReferObjectId:      v.ReferObjectId,
						ReferObjectType:    v.ReferObjectType,
						ReferObjectSubType: v.ReferObjectSubType,
						EdbInfoId:          childEdbMapping.FromEdbInfoId,
						EdbName:            childEdbMapping.FromEdbName,
						Source:             childEdbMapping.FromSource,
						EdbCode:            childEdbMapping.FromEdbCode,
						CreateTime:         nowTime,
						ModifyTime:         nowTime,
						RelationTime:       nowTime,
						RelationType:       1,
						RootEdbInfoId:      edbInfo.EdbInfoId,
						ChildEdbInfoId:     childEdbMapping.EdbInfoId,
					}
					tmp1.RelationCode = fmt.Sprintf("%d_%d_%d_%d", tmp1.RootEdbInfoId, tmp1.ReferObjectId, tmp1.ReferObjectType, tmp1.ReferObjectSubType)
					addList = append(addList, tmp1)
					refreshIds = append(refreshIds, childEdbMapping.FromEdbInfoId)
				}
			}
			logMsg += strconv.Itoa(v.EdbInfoRelationId) + ";"
		}
	}

	if len(edbInfoRelationIds) > 0 {
		err = data_manage.UpdateSecondRelationEdbInfoId(edbInfoRelationIds, addList, refreshIds, indexCodeList)
		if err != nil {
			logMsg = ""
			err = fmt.Errorf("替换指标引用表中的指标ID失败 Err:%s", err)
			return
		}
		replaceTotal = len(edbInfoRelationIds)
	}
	return
}