package services

import (
	"eta/eta_index_lib/models"
	"eta/eta_index_lib/services/alarm_msg"
	"eta/eta_index_lib/utils"
	"fmt"
	"sort"
	"strconv"
	"time"
)

// 重置单个计算指标中的引用关系
func ResetEdbRelation(edbInfoId int) {
	var logMsg string
	var replaceTotal int
	var err error
	defer func() {
		if err != nil {
			msg := fmt.Sprintf(" 重置单个计算指标中的引用关系失败 ResetEdbRelation  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:%s", replaceTotal, logMsg))
		}
	}()
	//查询与该计算指标相关的间接引用或者间接引用关系,如果记录不存在,则不处理
	_, err = models.GetEdbInfoRelationByChildEdbInfoId(edbInfoId)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = nil
			return
		}
		err = fmt.Errorf("查询与该计算指标相关的间接引用或者间接引用关系失败,错误信息:%s", err.Error())
		return
	}

	//查询当前计算指标最新的引用指标列表
	newMappingList, err := models.GetEdbInfoCalculateDetailList(edbInfoId)
	if err != nil {
		err = fmt.Errorf("查询当前计算指标最新的指标列表失败,错误信息:%s", err.Error())
		return
	}
	//整理关联的来源指标ID
	newEdbIdList := make([]string, 0)
	newMappingListMap := make(map[int]*models.EdbInfoCalculateDetail)
	for _, v := range newMappingList {
		newEdbIdList = append(newEdbIdList, strconv.Itoa(v.FromEdbInfoId))
		newMappingListMap[v.FromEdbInfoId] = v
	}
	//对指标ID进行排序
	sort.Strings(newEdbIdList)
	newEdbIdStr := ""
	for _, v := range newEdbIdList {
		newEdbIdStr += v + ","
	}
	//二者匹配一下,如果相同,则不处理,如果不同,先查询所有旧的间接引用记录,整理并分组,则删除旧的间接引用记录,新增新的间接引用记录,
	tmpList, err := models.GetEdbInfoRelationListByChildEdbInfoId(edbInfoId)
	if err != nil {
		err = fmt.Errorf("查询当前计算指标的间接引用关系失败,错误信息:%s", err.Error())
		return
	}

	parentRelationIds := make([]int, 0)
	for _, v := range tmpList {
		parentRelationIds = append(parentRelationIds, v.ParentRelationId)
	}
	if len(parentRelationIds) > 0 {
		// 查询单个项目的引用列表作为判断依据
		oldEdbIdList, err := models.GetEdbInfoRelationEdbIdsByParentRelationId(parentRelationIds[0], edbInfoId)
		if err != nil {
			err = fmt.Errorf("查询当前计算指标的间接引用关系失败,错误信息:%s", err.Error())
			return
		}
		sort.Ints(oldEdbIdList)
		oldEdbIdStr := ""
		for _, v := range oldEdbIdList {
			oldEdbIdStr += strconv.Itoa(v) + ","
		}
		// 把切片转成字符串
		if newEdbIdStr == oldEdbIdStr {
			return
		}
		list, e := models.GetEdbInfoRelationByRelationIds(parentRelationIds)
		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([]*models.EdbInfo, 0)
		if len(edbInfoIds) > 0 {
			// 查询指标信息
			edbInfoList, err = models.GetEdbInfoByIdList(edbInfoIds)
			if err != nil {
				err = fmt.Errorf("查询指标信息失败 Err:%s", err)
				return
			}
		}
		calculateEdbMappingListMap, calculateEdbMappingIdsMap, err := GetEdbListByEdbInfoId(edbInfoList)
		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 UpdateSecondEdbInRelation(list []*models.EdbInfoRelation, calculateEdbMappingListMap map[int]*models.EdbInfoCalculateMapping, calculateEdbMappingIdsMap map[int][]int, edbInfoList []*models.EdbInfo) (replaceTotal int, logMsg string, err error) {
	nowTime := time.Now()
	edbInfoRelationIds := make([]int, 0)
	indexCodeList := make([]string, 0)
	addList := make([]*models.EdbInfoRelation, 0)
	refreshIds := make([]int, 0)
	edbInfoMap := make(map[int]*models.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 := &models.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:       childEdbMapping.CreateTime,
						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)
				}
			}
		}
	}

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

// 设置成禁用状态
func DisableEdbInfoNoUpdate(edbInfo *models.EdbInfo) (err error) {
	// 如果一个计算指标里,包涵的基础指标是停用状态,那么计算指标也要是停用状态停用状态
	newBaseEdbInfoList := make([]int, 0)
	hasFind := make(map[int]struct{})
	newBaseEdbInfoIds, err := FindBaseEdbInfo(edbInfo.EdbInfoId, newBaseEdbInfoList, hasFind)
	if err != nil {
		err = fmt.Errorf("查找基础指标信息失败,err:%v", err)
		return
	}
	// 查询是否存在停用指标,如果存在,则计算指标也要是停用状态
	total, err := models.GetEdbInfoNoUpdateTotalByIdList(newBaseEdbInfoIds)
	if err != nil {
		err = fmt.Errorf("查询基础指标信息失败,err:%v", err)
		return
	}
	if total > 0 {
		edbInfo.NoUpdate = 1
		edbInfo.ModifyTime = time.Now()
		err = edbInfo.Update([]string{"NoUpdate", "ModifyTime"})
		if err != nil {
			err = fmt.Errorf("更新计算指标刷新状态失败,err:%v", err)
			return
		}
	}
	return
}

// 找到基础指标的过程
func FindBaseEdbInfo(edbInfoId int, baseEdbInfoList []int, hasFind map[int]struct{}) (newBaseEdbInfoList []int, err error) {
	newBaseEdbInfoList = baseEdbInfoList
	if _, ok := hasFind[edbInfoId]; ok {
		return
	}
	// 先找到所有的引用关系
	//查询当前计算指标最新的引用指标列表
	newMappingList, err := models.GetEdbInfoCalculateDetailList(edbInfoId)
	if err != nil {
		err = fmt.Errorf("查询当前计算指标最新的指标列表失败,错误信息:%s", err.Error())
		return
	}
	hasFind[edbInfoId] = struct{}{}
	for _, mapping := range newMappingList {
		newBaseEdbInfoList = append(newBaseEdbInfoList, mapping.FromEdbInfoId)
		if mapping.EdbType == 1 { // 如果是基础指标,则加入,否则继续找
		} else {
			newBaseEdbInfoList, err = FindBaseEdbInfo(mapping.FromEdbInfoId, newBaseEdbInfoList, hasFind)
		}
	}
	return
}

// 查找当前计算指标的所有溯源指标
func GetEdbListByEdbInfoId(edbInfoList []*models.EdbInfo) (edbMappingListMap map[int]*models.EdbInfoCalculateMapping, edbInfoMappingRootIdsMap map[int][]int, err error) {
	if len(edbInfoList) == 0 {
		return
	}
	edbInfoIds := make([]int, 0)
	for _, v := range edbInfoList {
		if v.EdbType == 2 && v.EdbInfoType == 0 { //普通计算指标,排除预算指标
			edbInfoIds = append(edbInfoIds, v.EdbInfoId)
		}
	}
	if len(edbInfoIds) == 0 {
		return
	}
	//查询指标信息
	allEdbMappingMap := make(map[int][]*models.EdbInfoCalculateMappingInfo, 0)
	allMappingList, e := models.GetEdbInfoCalculateMappingListByEdbInfoIds(edbInfoIds)
	if e != nil {
		err = fmt.Errorf("GetEdbInfoCalculateMappingListByEdbInfoIds err: %s", e.Error())
		return
	}
	for _, v := range allMappingList {
		if _, ok := allEdbMappingMap[v.EdbInfoId]; !ok {
			allEdbMappingMap[v.EdbInfoId] = make([]*models.EdbInfoCalculateMappingInfo, 0)
		}
		allEdbMappingMap[v.EdbInfoId] = append(allEdbMappingMap[v.EdbInfoId], v)
	}
	//查询指标映射
	//查询所有指标数据
	//查询这个指标相关的mapping信息放到数组里,
	//将得到的指标ID信息放到数组里
	hasFindMap := make(map[int]struct{})
	edbInfoIdMap := make(map[int]struct{})
	edbMappingList := make([]*models.EdbInfoCalculateMapping, 0)
	edbInfoMappingRootIdsMap = make(map[int][]int, 0)
	edbMappingMap := make(map[int]struct{})
	for _, edbInfo := range edbInfoList {
		if edbInfo.EdbType == 2 && edbInfo.EdbInfoType == 0 {
			edbInfoId := edbInfo.EdbInfoId
			edbMappingList, err = getCalculateEdbInfoByEdbInfoId(allEdbMappingMap, edbInfoId, hasFindMap, edbInfoIdMap, edbMappingList, edbMappingMap, edbInfoMappingRootIdsMap, edbInfoId)
			if err != nil {
				err = fmt.Errorf(" GetCalculateEdbInfoByEdbInfoId err: %s", err.Error())
				return
			}
		}
	}
	if len(edbMappingList) == 0 {
		return
	}
	// 查询指标信息
	// 指标信息map
	edbInfoIdList := make([]int, 0)
	for k, _ := range edbInfoIdMap {
		edbInfoIdList = append(edbInfoIdList, k)
	}
	edbMappingListMap = make(map[int]*models.EdbInfoCalculateMapping)

	if len(edbMappingList) > 0 {
		for _, v := range edbMappingList {
			edbMappingListMap[v.EdbInfoCalculateMappingId] = v
		}
	}
	return
}

// getCalculateEdbInfoByEdbInfoId 计算指标追溯
func getCalculateEdbInfoByEdbInfoId(allEdbMappingMap map[int][]*models.EdbInfoCalculateMappingInfo, edbInfoId int, hasFindMap map[int]struct{}, edbInfoIdMap map[int]struct{}, edbMappingList []*models.EdbInfoCalculateMapping, edbMappingMap map[int]struct{}, edbInfoMappingRootIdsMap map[int][]int, rootEdbInfoId int) (newEdbMappingList []*models.EdbInfoCalculateMapping, err error) {
	newEdbMappingList = edbMappingList
	_, ok := hasFindMap[edbInfoId]
	if ok {
		return
	}

	if _, ok1 := edbInfoIdMap[edbInfoId]; !ok1 {
		edbInfoIdMap[edbInfoId] = struct{}{}
	}
	edbInfoMappingList := make([]*models.EdbInfoCalculateMappingInfo, 0)
	edbInfoMappingList, ok = allEdbMappingMap[edbInfoId]
	if !ok {
		edbInfoMappingList, err = models.GetEdbInfoCalculateMappingListByEdbInfoId(edbInfoId)
		if err != nil {
			err = fmt.Errorf("GetEdbInfoCalculateMappingListByEdbInfoId err: %s", err.Error())
			return
		}
	}
	hasFindMap[edbInfoId] = struct{}{}
	if len(edbInfoMappingList) > 0 {
		fromEdbInfoIdList := make([]int, 0)
		edbInfoMappingIdList := make([]int, 0)
		for _, v := range edbInfoMappingList {
			fromEdbInfoIdList = append(fromEdbInfoIdList, v.FromEdbInfoId)
			edbInfoMappingIdList = append(edbInfoMappingIdList, v.EdbInfoCalculateMappingId)
			if _, ok1 := edbInfoIdMap[v.FromEdbInfoId]; !ok1 {
				edbInfoIdMap[v.FromEdbInfoId] = struct{}{}
			}
			if _, ok2 := edbMappingMap[v.EdbInfoCalculateMappingId]; !ok2 {
				edbMappingMap[v.EdbInfoCalculateMappingId] = struct{}{}
				tmp := &models.EdbInfoCalculateMapping{
					EdbInfoCalculateMappingId: v.EdbInfoCalculateMappingId,
					EdbInfoId:                 v.EdbInfoId,
					Source:                    v.Source,
					SourceName:                v.SourceName,
					EdbCode:                   v.EdbCode,
					FromEdbInfoId:             v.FromEdbInfoId,
					FromEdbCode:               v.FromEdbCode,
					FromEdbName:               v.FromEdbName,
					FromSource:                v.FromSource,
					FromSourceName:            v.FromSourceName,
					FromTag:                   v.FromTag,
					Sort:                      v.Sort,
					CreateTime:                v.CreateTime,
					ModifyTime:                v.ModifyTime,
				}
				newEdbMappingList = append(newEdbMappingList, tmp)

			}

			if edbInfoId != v.FromEdbInfoId && (v.FromEdbType == 2 || v.FromEdbInfoType == 1) {
				// 查过了就不查了
				if _, ok2 := hasFindMap[v.FromEdbInfoId]; !ok2 {
					newEdbMappingList, err = getCalculateEdbInfoByEdbInfoId(allEdbMappingMap, v.FromEdbInfoId, hasFindMap, edbInfoIdMap, newEdbMappingList, edbMappingMap, edbInfoMappingRootIdsMap, rootEdbInfoId)
					if err != nil {
						err = fmt.Errorf("traceEdbInfoByEdbInfoId err: %s", err.Error())
						return
					}
				}
			}
			hasFindMap[v.FromEdbInfoId] = struct{}{}
		}
		edbInfoMappingRootIdsMap[rootEdbInfoId] = append(edbInfoMappingRootIdsMap[rootEdbInfoId], edbInfoMappingIdList...)
	}

	return
}