package data_manage

import (
	"errors"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/yidane/formula"
	"eta/eta_api/utils"
	"strconv"
	"strings"
	"time"
)

type EdbDataCalculate struct {
	EdbDataId     int `orm:"column(edb_data_id);pk"`
	EdbInfoId     int
	EdbCode       string
	DataTime      string
	Value         float64
	Status        int
	CreateTime    time.Time
	ModifyTime    time.Time
	DataTimestamp int64
}

func AddEdbDataCalculate(items []*EdbDataCalculate) (err error) {
	o := orm.NewOrmUsingDB("data")
	_, err = o.InsertMulti(1, items)
	return
}

func AddEdbDataCalculateBySql(sqlStr string) (err error) {
	o := orm.NewOrmUsingDB("data")
	_, err = o.Raw(sqlStr).Exec()
	return
}

func ModifyEdbDataCalculate(edbInfoId int64, dataTime string, value float64) (err error) {
	o := orm.NewOrmUsingDB("data")
	sql := ` UPDATE edb_data_calculate SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
	_, err = o.Raw(sql, value, edbInfoId, dataTime).Exec()
	return
}

func GetEdbDataCalculateByCodeAndDate(edbCode string, startDate string) (count int, err error) {
	o := orm.NewOrmUsingDB("data")
	sql := ` SELECT COUNT(1) AS count FROM edb_data_calculate WHERE edb_code=? AND data_time=? `
	err = o.Raw(sql, edbCode, startDate).QueryRow(&count)
	return
}

// 刷新全部数据
func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string) (err error) {
	o := orm.NewOrmUsingDB("data")
	to, err := o.Begin()
	if err != nil {
		return
	}
	defer func() {
		if err != nil {
			_ = to.Rollback()
		} else {
			_ = to.Commit()
		}
	}()
	fmt.Println(startDate, endDate)
	saveDataMap := make(map[string]map[int]float64)
	for _, v := range edbInfoIdArr {
		var condition string
		var pars []interface{}
		condition += " AND edb_info_id=? "
		pars = append(pars, v.EdbInfoId)
		if startDate != "" {
			condition += " AND data_time>=? "
			pars = append(pars, startDate)
		}
		if endDate != "" {
			condition += " AND data_time<=? "
			pars = append(pars, endDate)
		}
		fmt.Println("v.Source:", v.Source)
		dataList, err := GetEdbDataListAll(condition, pars, v.Source, 1)
		if err != nil {
			return err
		}
		dataMap := make(map[string]float64)
		for _, dv := range dataList {
			if val, ok := saveDataMap[dv.DataTime]; ok {
				if _, ok := val[v.EdbInfoId]; !ok {
					val[v.EdbInfoId] = dv.Value
				}
			} else {
				temp := make(map[int]float64)
				temp[v.EdbInfoId] = dv.Value
				saveDataMap[dv.DataTime] = temp
			}
		}
		item := new(CalculateItems)
		item.EdbInfoId = v.EdbInfoId
		item.DataMap = dataMap
	}

	formulaMap := CheckFormula(formulaStr)
	addSql := ` INSERT INTO edb_data_calculate(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
	var isAdd bool

	//获取指标所有数据
	dataList := make([]*EdbDataBase, 0)
	dataTableName := GetEdbDataTableName(source)
	sql := `SELECT * FROM %s WHERE edb_info_id=? `
	sql = fmt.Sprintf(sql, dataTableName)
	_, err = to.Raw(sql, edbInfoId).QueryRows(&dataList)
	if err != nil {
		return err
	}
	dataMap := make(map[string]string)
	for _, v := range dataList {
		dataMap[v.DataTime] = v.Value
	}
	edbInfoIdStr := strconv.Itoa(edbInfoId)
	existDataMap := make(map[string]string)
	for sk, sv := range saveDataMap {
		fmt.Println(sk, sv)
		formulaStr = strings.ToUpper(formulaStr)
		formulaFormStr := ReplaceFormula(edbInfoIdArr, sv, formulaMap, formulaStr, edbInfoIdBytes)
		if formulaFormStr != "" {
			utils.FileLog.Info("formulaFormStr:%s", formulaFormStr)
			expression := formula.NewExpression(formulaFormStr)
			calResult, err := expression.Evaluate()
			if err != nil {
				err = errors.New("计算失败:Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
				fmt.Println(err)
				return err
			}
			calVal, err := calResult.Float64()
			if err != nil {
				err = errors.New("计算失败:获取计算值失败 Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
				fmt.Println(err)
				return err
			}

			saveValue := utils.SubFloatToString(calVal, 4)
			if existVal, ok := dataMap[sk]; !ok {
				dataTime, _ := time.Parse(utils.FormatDate, sk)
				timestamp := dataTime.UnixNano() / 1e6
				timeStr := fmt.Sprintf("%d", timestamp)

				if _, existOk := existDataMap[sk]; !existOk {
					addSql += GetAddSql(edbInfoIdStr, edbCode, sk, timeStr, saveValue)
					isAdd = true
				}
				existDataMap[sk] = sk
			} else {
				if existVal != saveValue {
					sql := ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
					sql = fmt.Sprintf(sql, dataTableName)
					_, err = to.Raw(sql, saveValue, edbInfoId, sk).Exec()
					if err != nil {
						return err
					}
				}
			}
		}
	}
	if isAdd {
		addSql = strings.TrimRight(addSql, ",")
		_, err = to.Raw(addSql).Exec()
		if err != nil {
			fmt.Println("RefreshAllCalculate add Err", err.Error())
			return
		}
	}
	return
}