package models

import (
	"errors"
	"eta/eta_index_lib/utils"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/shopspring/decimal"
	"strconv"
	"strings"
	"time"
)

// AddCalculateNszydpjjs N数值移动平均计算
func AddCalculateNszydpjjs(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, edbCode, uniqueCode string, sysUserId int, sysUserRealName string, formulaInt int) (edbInfo *EdbInfo, err error) {
	o := orm.NewOrm()
	to, err := o.Begin()
	defer func() {
		if err != nil {
			fmt.Println("AddCalculateNszydpjjs,Err:" + err.Error())
			_ = to.Rollback()
		} else {
			_ = to.Commit()
		}
	}()
	if req.EdbInfoId <= 0 {
		edbInfo = new(EdbInfo)
		edbInfo.Source = utils.DATA_SOURCE_CALCULATE_NSZYDPJJS
		edbInfo.SourceName = "N数值移动平均计算"
		edbInfo.EdbCode = edbCode
		edbInfo.EdbName = req.EdbName
		edbInfo.EdbNameSource = req.EdbName
		edbInfo.Frequency = req.Frequency
		edbInfo.Unit = req.Unit
		edbInfo.ClassifyId = req.ClassifyId
		edbInfo.SysUserId = sysUserId
		edbInfo.SysUserRealName = sysUserRealName
		edbInfo.CreateTime = time.Now()
		edbInfo.ModifyTime = time.Now()
		edbInfo.UniqueCode = uniqueCode
		edbInfo.CalculateFormula = req.Formula
		edbInfo.EdbNameEn = req.EdbName
		edbInfo.UnitEn = req.Unit
		edbInfo.EdbType = 2
		edbInfo.Sort = GetAddEdbMaxSortByClassifyId(req.ClassifyId, utils.EDB_INFO_TYPE)
		newEdbInfoId, tmpErr := to.Insert(edbInfo)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		edbInfo.EdbInfoId = int(newEdbInfoId)

		//关联关系
		{
			calculateMappingItem := new(EdbInfoCalculateMapping)
			calculateMappingItem.CreateTime = time.Now()
			calculateMappingItem.ModifyTime = time.Now()
			calculateMappingItem.Sort = 1
			calculateMappingItem.EdbCode = edbCode
			calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
			calculateMappingItem.FromEdbInfoId = fromEdbInfo.EdbInfoId
			calculateMappingItem.FromEdbCode = fromEdbInfo.EdbCode
			calculateMappingItem.FromEdbName = fromEdbInfo.EdbName
			calculateMappingItem.FromSource = fromEdbInfo.Source
			calculateMappingItem.FromSourceName = fromEdbInfo.SourceName
			calculateMappingItem.FromTag = ""
			calculateMappingItem.Source = edbInfo.Source
			calculateMappingItem.SourceName = edbInfo.SourceName
			calculateMappingItem.FromSubSource = fromEdbInfo.SubSource
			_, err = to.Insert(calculateMappingItem)
			if err != nil {
				return
			}
		}
	} else {
		edbInfo, err = GetEdbInfoById(req.EdbInfoId)
		if err != nil {
			return
		}
		dataTableName := GetEdbDataTableName(utils.DATA_SOURCE_CALCULATE_NSZYDPJJS, utils.DATA_SUB_SOURCE_EDB)
		deleteSql := ` DELETE FROM %s WHERE edb_info_id=? `
		deleteSql = fmt.Sprintf(deleteSql, dataTableName)
		_, err = to.Raw(deleteSql, req.EdbInfoId).Exec()
		if err != nil {
			return
		}
	}

	//计算数据
	err = refreshAllCalculateNszydpjjs(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, formulaInt, fromEdbInfo, edbInfo.EdbCode, "")
	return
}

// EditCalculateNszydpjjs 修改N数值移动平均计算
func EditCalculateNszydpjjs(edbInfo *EdbInfo, req *EdbInfoCalculateBatchEditReq, fromEdbInfo *EdbInfo, formulaInt int, oldCalculateFormula string) (err error) {
	o := orm.NewOrm()
	to, err := o.Begin()
	defer func() {
		if err != nil {
			fmt.Println("EditCalculateNszydpjjs,Err:" + err.Error())
			_ = to.Rollback()
		} else {
			_ = to.Commit()
		}
	}()

	//修改指标信息
	edbInfo.EdbName = req.EdbName
	edbInfo.EdbNameSource = req.EdbName
	edbInfo.Frequency = req.Frequency
	edbInfo.Unit = req.Unit
	edbInfo.ClassifyId = req.ClassifyId
	edbInfo.CalculateFormula = req.Formula
	edbInfo.EdbNameEn = req.EdbNameEn
	edbInfo.UnitEn = req.UnitEn
	edbInfo.ModifyTime = time.Now()
	_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime", "EdbNameEn", "UnitEn")
	if err != nil {
		return
	}

	var existCondition string
	var existPars []interface{}
	existCondition += " AND edb_info_id=? AND from_edb_info_id=? "
	existPars = append(existPars, edbInfo.EdbInfoId, req.FromEdbInfoId)

	//判断计算指标是否被更换
	count, err := GetEdbInfoCalculateCountByCondition(existCondition, existPars)
	if err != nil && err.Error() != utils.ErrNoRow() {
		err = errors.New("判断指标是否改变失败,Err:" + err.Error())
		return
	}
	fmt.Println("oldCalculateFormula:", oldCalculateFormula)
	fmt.Println("req.Formula:", req.Formula)
	fmt.Println("count:", count)
	if count > 0 && oldCalculateFormula == req.Formula { // 指标未被替换,同时N值未修改,无需重新计算
		return
	}

	if count <= 0 {
		// 需要删除原先的 计算指标关联的,基础指标的关联关系
		sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? `
		_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
		if err != nil {
			return
		}

		// 添加新的关联关系
		{
			calculateMappingItem := &EdbInfoCalculateMapping{
				EdbInfoCalculateMappingId: 0,
				EdbInfoId:                 edbInfo.EdbInfoId,
				Source:                    utils.DATA_SOURCE_CALCULATE_NSZYDPJJS,
				SourceName:                "N数值移动平均计算",
				EdbCode:                   edbInfo.EdbCode,
				FromEdbInfoId:             fromEdbInfo.EdbInfoId,
				FromEdbCode:               fromEdbInfo.EdbCode,
				FromEdbName:               fromEdbInfo.EdbName,
				FromSource:                fromEdbInfo.Source,
				FromSourceName:            fromEdbInfo.SourceName,
				FromTag:                   "",
				Sort:                      1,
				CreateTime:                time.Now(),
				ModifyTime:                time.Now(),
				FromSubSource:             fromEdbInfo.SubSource,
			}
			_, err = to.Insert(calculateMappingItem)
			if err != nil {
				return
			}
		}
	}
	//清空原有数据
	sql := ` DELETE FROM edb_data_calculate_nszydpjjs WHERE edb_info_id = ? `
	_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
	if err != nil {
		return
	}

	//计算数据
	err = refreshAllCalculateNszydpjjs(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, formulaInt, fromEdbInfo, edbInfo.EdbCode, "")

	return
}

// RefreshAllCalculateNszydpjjs 刷新全部N数值移动平均计算
func RefreshAllCalculateNszydpjjs(edbInfoId, source, subSource, formulaInt int, fromEdbInfo *EdbInfo, edbCode, startDate string) (err error) {
	o := orm.NewOrm()
	to, err := o.Begin()
	defer func() {
		if err != nil {
			fmt.Println("RefreshCalculateNszydpjjs Err:" + err.Error())
			utils.FileLog.Info("RefreshCalculateNszydpjjs Err:" + err.Error())
			_ = to.Rollback()
		} else {
			_ = to.Commit()
		}
	}()

	//计算数据
	err = refreshAllCalculateNszydpjjs(to, edbInfoId, source, subSource, formulaInt, fromEdbInfo, edbCode, startDate)
	return
}

// refreshAllCalculateNszydpjjs 更新全部N数值移动平均计算
func refreshAllCalculateNszydpjjs(to orm.TxOrmer, edbInfoId, source, subSource, formulaInt int, fromEdbInfo *EdbInfo, edbCode, startDate string) (err error) {
	edbInfoIdStr := strconv.Itoa(edbInfoId)
	fmt.Println(edbInfoIdStr)
	fmt.Println("refreshAllCalculateNszydpjjs startDate:", startDate)
	//计算数据
	var condition string
	var pars []interface{}
	condition += " AND edb_info_id=? "
	pars = append(pars, edbInfoId)

	existDataList, err := GetEdbDataListAllV1ByTo(to, condition, pars, source, subSource, 0)
	if err != nil {
		fmt.Println("existDataList GetEdbDataListAll Err:" + err.Error())
		return err
	}

	existDataMap := make(map[string]*EdbInfoSearchDataV1)
	removeDataTimeMap := make(map[string]int) //需要移除的日期数据
	for _, v := range existDataList {
		existDataMap[v.DataTime] = v
		removeDataTimeMap[v.DataTime] = 1
	}

	// 获取来源数据
	fromDataList, err := GetEdbDataListAll(fromEdbInfo.Source, fromEdbInfo.SubSource, FindEdbDataListAllCond{
		EdbInfoId: fromEdbInfo.EdbInfoId,
	}, 0)
	if err != nil {
		fmt.Println("from GetEdbDataListAll Err:" + err.Error())
		return err
	}
	//fmt.Println("fromPars:", fromPars)
	//fromDataList, err := GetEdbDataListAllV1ByTo(to, fromCondition, fromPars, fromEdbInfo.Source, fromEdbInfo.SubSource, 0)

	var fromDateArr []string
	fromDataMap := make(map[string]*EdbInfoSearchData)
	for _, v := range fromDataList {
		fromDateArr = append(fromDateArr, v.DataTime)
		fromDataMap[v.DataTime] = v
	}

	addSql := ` INSERT INTO edb_data_calculate_nszydpjjs(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
	var isAdd bool
	dataTableName := GetEdbDataTableName(source, subSource)
	arrLen := len(fromDateArr)
	existAddDataMap := make(map[string]string)
	for ak, av := range fromDateArr {
		//处理第一个值
		var valArr []float64
		if findItem, ok := fromDataMap[av]; ok {
			valArr = append(valArr, findItem.Value)
		} else {
			continue
		}
		if ak+1 != arrLen {
			//处理除第一个值之外的N-1个值
			for i := 1; i < formulaInt; i++ {
				arrIndex := ak + i
				if arrIndex >= arrLen {
					break
				}
				arrVal := fromDateArr[arrIndex]
				if findItem, ok := fromDataMap[arrVal]; ok {
					valArr = append(valArr, findItem.Value)
				} else {
					continue
				}
			}
		}
		valArrLen := len(valArr)
		//var totalVal float64
		totalVal := decimal.NewFromFloat(0.00)
		for _, v := range valArr {
			newDecimal := decimal.NewFromFloat(v)
			totalVal = totalVal.Add(newDecimal)
		}
		af := totalVal //decimal.NewFromFloat(totalVal)
		bf := decimal.NewFromFloat(float64(valArrLen))
		val, _ := af.Div(bf).Float64()
		valStr := decimal.NewFromFloat(val).RoundCeil(4).String()

		if existVal, existOk := existDataMap[av]; !existOk {
			currentDate, err := time.ParseInLocation(utils.FormatDate, av, time.Local)
			if err != nil {
				return err
			}
			timestamp := currentDate.UnixNano() / 1e6
			timestampStr := fmt.Sprintf("%d", timestamp)
			if _, existOk := existAddDataMap[av]; !existOk {
				addSql += GetAddSql(edbInfoIdStr, edbCode, av, timestampStr, valStr)
				isAdd = true
			}
			existAddDataMap[av] = av
		} else {
			//校验待删除日期数据里面是否存在该元素,如果存在的话,那么移除该日期
			delete(removeDataTimeMap, av)

			existValDecimal, err := decimal.NewFromString(existVal.Value)
			existStr := existValDecimal.String()
			fmt.Println(existStr, valStr, av)
			if existStr != valStr {
				sql := ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
				sql = fmt.Sprintf(sql, dataTableName)
				_, err = to.Raw(sql, valStr, edbInfoId, av).Exec()
				if err != nil {
					return err
				}
			}
		}
	}

	//删除已经不存在的指标数据(由于该指标当日的数据删除了)
	{
		removeDateList := make([]string, 0)
		for dateTime := range removeDataTimeMap {
			removeDateList = append(removeDateList, dateTime)
		}
		removeNum := len(removeDateList)
		if removeNum > 0 {
			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (`+utils.GetOrmInReplace(removeNum)+`) `, dataTableName)
			_, err = to.Raw(sql, edbInfoId, removeDateList).Exec()
			if err != nil {
				err = fmt.Errorf("删除不存在的指标数据失败,Err:" + err.Error())
				return
			}
		}
	}

	if isAdd {
		addSql = strings.TrimRight(addSql, ",")
		utils.FileLog.Info("addSql:" + addSql)
		_, err = to.Raw(addSql).Exec()
		if err != nil {
			return err
		}
	}
	return
}