package models

import (
	"encoding/json"
	"errors"
	"eta/eta_index_lib/models/mgo"
	"eta/eta_index_lib/utils"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/shopspring/decimal"
	"go.mongodb.org/mongo-driver/bson"
	"strconv"
	"time"
)

type EdbInfo struct {
	EdbInfoId        int    `orm:"column(edb_info_id);pk"`
	EdbInfoType      int    `description:"指标类型，0：普通指标，1：预测指标"`
	SourceName       string `description:"来源名称"`
	Source           int    `description:"来源id"`
	EdbCode          string `description:"指标编码"`
	EdbName          string `description:"指标名称"`
	EdbNameEn        string `description:"英文指标名称"`
	EdbNameSource    string `description:"指标名称来源"`
	Frequency        string `description:"频率"`
	Unit             string `description:"单位"`
	UnitEn           string `description:"英文单位"`
	StartDate        string `description:"起始日期"`
	EndDate          string `description:"终止日期"`
	ClassifyId       int    `description:"分类id"`
	SysUserId        int
	SysUserRealName  string
	UniqueCode       string `description:"指标唯一编码"`
	CreateTime       time.Time
	ModifyTime       time.Time
	MinValue         float64 `description:"指标最小值"`
	MaxValue         float64 `description:"指标最大值"`
	CalculateFormula string  `description:"计算公式"`
	EdbType          int     `description:"指标类型:1:基础指标,2:计算指标"`
	IsUpdate         int     `description:"当天是否已更新，1:未更新,2:已更新"`
	Sort             int     `description:"排序字段"`
	LatestDate       string  `description:"数据最新日期（实际日期）"`
	LatestValue      float64 `description:"数据最新值（实际值）"`
	EndValue         float64 `description:"数据的最新值（预测日期的最新值）"`
	MoveType         int     `description:"移动方式:1:领先(默认),2:滞后"`
	MoveFrequency    string  `description:"移动频度"`
	NoUpdate         int8    `description:"是否停止更新，0：继续更新；1：停止更新"`
	ServerUrl        string  `description:"服务器地址"`
	ChartImage       string  `description:"图表图片"`
	Calendar         string  `description:"公历/农历" orm:"default(公历);"`
	EmptyType        int     `description:"空值处理类型（0查找前后35天，1不计算，2前值填充，3后值填充，4等于0）"`
	MaxEmptyType     int     `description:"MAX、MIN公式空值处理类型（1、等于0；2、跳过空值）"`
	DataDateType     string  `orm:"column(data_date_type);size(255);null;default(交易日)"`
	ManualSave       int     `description:"是否有手动保存过上下限: 0-否; 1-是"`
	TerminalCode     string  `description:"终端编码，用于配置在机器上"`
	DataUpdateTime   string  `description:"最近一次数据发生变化的时间"`
	ErDataUpdateDate string  `description:"本次更新，数据发生变化的最早日期"`
	SourceIndexName  string  `description:"数据源中的指标名称"`
	SubSource        int     `description:"子数据来源:0:经济数据库,1:日期序列"`
	SubSourceName    string  `description:"子数据来源名称"`
	IndicatorCode    string  `description:"指标代码"`
	StockCode        string  `description:"证券代码"`
	Extra            string  `description:"指标的额外配置"`
}

func (e *EdbInfo) Add() (err error) {
	o := orm.NewOrm()
	_, err = o.Insert(e)
	return
}

// AddEdbInfo 添加指标
func AddEdbInfo(item *EdbInfo) (lastId int64, err error) {
	o := orm.NewOrm()
	lastId, err = o.Insert(item)
	return
}

// EdbInfoList 指标数据列表
type EdbInfoList struct {
	EdbInfoId       int                    `orm:"column(edb_info_id);pk"`
	EdbInfoType     int                    `description:"指标类型，0：普通指标，1：预测指标"`
	SourceName      string                 `description:"来源名称"`
	Source          int                    `description:"来源id"`
	EdbCode         string                 `description:"指标编码"`
	EdbNameEn       string                 `description:"英文指标名称"`
	EdbName         string                 `description:"指标名称"`
	Frequency       string                 `description:"频率"`
	FrequencyEn     string                 `description:"英文频率"`
	Unit            string                 `description:"单位"`
	UnitEn          string                 `description:"英文单位"`
	StartDate       string                 `description:"起始日期"`
	EndDate         string                 `description:"终止日期"`
	LatestDate      string                 `description:"数据最新日期（实际日期）"`
	LatestValue     float64                `description:"数据最新值（实际值）"`
	EndValue        float64                `description:"数据的最新值（预测日期的最新值）"`
	ClassifyId      int                    `description:"分类id"`
	UniqueCode      string                 `description:"指标唯一编码"`
	SysUserId       int                    `description:"创建人id"`
	SysUserRealName string                 `description:"创建人姓名"`
	ModifyTime      string                 `description:"最新修改时间"`
	CreateTime      string                 `description:"创建时间"`
	EdbNameAlias    string                 `json:"-" description:"指标名称,别名"`
	EdbType         int                    `description:"指标类型:1:基础指标,2:计算指标"`
	ChartImage      string                 `description:"图表图片"`
	RuleType        int                    `description:"预测规则，1：最新，2：固定值"`
	FixedValue      float64                `description:"固定值"`
	DataList        []*EdbData             `description:"实际指标数据"`
	PredictDataList []*EdbData             `description:"预测指标数据"`
	Button          EdbClassifyItemsButton `description:"操作权限"`
	IsEnEdb         bool                   `description:"是否展示英文标识"`
	DataDateType    string                 `description:"数据日期类型，枚举值：交易日、自然日"`
	EmptyType       int                    `description:"空值处理类型（0查找前后35天，1不计算，2前值填充，3后值填充，4等于0）"`
	MaxEmptyType    int                    `description:"MAX、MIN公式空值处理类型（1、等于0；2、跳过空值）"`
	SubSource       int                    `description:"子数据来源:0:经济数据库,1:日期序列"`
	SubSourceName   string                 `description:"子数据来源名称"`
	IndicatorCode   string                 `description:"指标代码"`
	StockCode       string                 `description:"证券代码"`
	NoUpdate        int8                   `description:"是否停止更新，0：继续更新；1：停止更新"`
}

// EdbClassifyItemsButton 操作按钮
type EdbClassifyItemsButton struct {
	AddButton         bool `description:"是否可添加"`
	OpButton          bool `description:"是否可编辑"`
	DeleteButton      bool `description:"是否可删除"`
	MoveButton        bool `description:"是否可移动"`
	ShowEdbRelation   bool `description:"是否展示关联指标"`
	ShowChartRelation bool `description:"是否展示关联图表"`
}

// GetEdbInfoByName 根据指标名称获取所有的指标数据列表
func GetEdbInfoByName(edbName string) (items []*EdbInfoList, err error) {
	o := orm.NewOrm()
	sql := ` SELECT * FROM edb_info WHERE edb_name=? `
	_, err = o.Raw(sql, edbName).QueryRows(&items)
	return
}

// ModifyEdbInfoNameSource 根据来源修改指标名称
func ModifyEdbInfoNameSource(edbNameSource string, edbInfoId int) (err error) {
	o := orm.NewOrm()
	sql := ` UPDATE  edb_info SET edb_name_source=? WHERE edb_info_id = ? `
	_, err = o.Raw(sql, edbNameSource, edbInfoId).Exec()
	return
}

// GetEdbInfoById 根据指标id获取指标信息
func GetEdbInfoById(edbInfoId int) (item *EdbInfo, err error) {
	o := orm.NewOrm()
	sql := ` SELECT * FROM edb_info WHERE edb_info_id=? `
	err = o.Raw(sql, edbInfoId).QueryRow(&item)
	return
}

// GetEdbInfoByUniqueCode 根据指标唯一编码获取指标信息
func GetEdbInfoByUniqueCode(uniqueCode string) (item *EdbInfo, err error) {
	o := orm.NewOrm()
	sql := ` SELECT * FROM edb_info WHERE unique_code=? `
	err = o.Raw(sql, uniqueCode).QueryRow(&item)
	return
}

// GetEdbInfoByIdList 根据指标id列表获取指标信息
func GetEdbInfoByIdList(edbInfoIdList []int) (items []*EdbInfo, err error) {
	num := len(edbInfoIdList)
	if num <= 0 {
		return
	}
	o := orm.NewOrm()
	sql := ` SELECT * FROM edb_info WHERE edb_info_id in (` + utils.GetOrmInReplace(num) + `) `
	_, err = o.Raw(sql, edbInfoIdList).QueryRows(&items)
	return
}

// Update 更新EdbInfo信息
func (edbInfo *EdbInfo) Update(cols []string) (err error) {
	o := orm.NewOrm()
	_, err = o.Update(edbInfo, cols...)
	return
}

// EdbInfoSearchData
type EdbInfoSearchData struct {
	EdbDataId     int     `description:"数据ID"`
	EdbInfoId     int     `description:"指标ID"`
	DataTime      string  `description:"数据日期"`
	Value         float64 `description:"数据"`
	EdbCode       string  `description:"指标编码"`
	DataTimestamp int64   `description:"时间戳"`
}

type FindEdbDataListAllCond struct {
	EdbInfoId         int
	StartDataTime     string
	StartDataTimeCond string
	EndDataTime       string
	EndDataTimeCond   string
}

// GetEdbDataListAll
// @Description: 获取指标数据列表 order:1升序，其余值为降序
// @author: Roc
// @datetime 2024-05-08 15:34:01
// @param source int
// @param subSource int
// @param findEdbDataListAllCond FindEdbDataListAllCond
// @param order int  order:1升序，其余值为降序
// @return item []*EdbInfoSearchData
// @return err error
func GetEdbDataListAll(source, subSource int, findEdbDataListAllCond FindEdbDataListAllCond, order int) (item []*EdbInfoSearchData, err error) {
	if source == utils.DATA_SOURCE_BUSINESS {
		return GetEdbDataListAllByMongo(source, subSource, findEdbDataListAllCond, order)
	}

	return GetEdbDataListAllByMysql(source, subSource, findEdbDataListAllCond, order)
}

// GetEdbDataListAllByMysql
// @Description: 从mysql数据库中获取指标数据列表 order:1升序，其余值为降序
// @author: Roc
// @datetime 2024-05-08 15:32:55
// @param source int
// @param subSource int
// @param findEdbDataListAllCond FindEdbDataListAllCond
// @param order int
// @return item []*EdbInfoSearchData
// @return err error
func GetEdbDataListAllByMysql(source, subSource int, findEdbDataListAllCond FindEdbDataListAllCond, order int) (item []*EdbInfoSearchData, err error) {
	if findEdbDataListAllCond.EdbInfoId <= 0 {
		return
	}
	to := orm.NewOrm()

	sql := ``
	tableName := GetEdbDataTableName(source, subSource)
	sql = ` SELECT * FROM %s WHERE 1=1 `
	sql = fmt.Sprintf(sql, tableName)

	var condition string
	var pars []interface{}
	condition += " AND edb_info_id=? "
	pars = append(pars, findEdbDataListAllCond.EdbInfoId)

	// 开始日期
	if findEdbDataListAllCond.StartDataTime != "" && findEdbDataListAllCond.StartDataTimeCond != `` {
		condition += fmt.Sprintf(" AND data_time %s ? ", findEdbDataListAllCond.StartDataTimeCond)
		pars = append(pars, findEdbDataListAllCond.StartDataTime)
	}
	// 结束日期
	if findEdbDataListAllCond.EndDataTime != "" && findEdbDataListAllCond.EndDataTimeCond != `` {
		condition += fmt.Sprintf(" AND data_time %s ? ", findEdbDataListAllCond.EndDataTimeCond)
		pars = append(pars, findEdbDataListAllCond.EndDataTime)
	}

	if condition != "" {
		sql += condition
	}
	if order == 1 {
		sql += ` ORDER BY data_time ASC `
	} else {
		sql += ` ORDER BY data_time DESC `
	}
	_, err = to.Raw(sql, pars).QueryRows(&item)
	return
}

// GetEdbDataListAllByTo
// @Description: 根据事务链接获取指标数据列表 order:1升序，其余值为降序
// @author: Roc
// @datetime 2024-05-08 15:34:06
// @param to orm.TxOrmer
// @param source int
// @param subSource int
// @param findEdbDataListAllCond FindEdbDataListAllCond
// @param order int
// @return item []*EdbInfoSearchData
// @return err error
func GetEdbDataListAllByTo(to orm.TxOrmer, source, subSource int, findEdbDataListAllCond FindEdbDataListAllCond, order int) (item []*EdbInfoSearchData, err error) {
	if source == utils.DATA_SOURCE_BUSINESS {
		return GetEdbDataListAllByMongo(source, subSource, findEdbDataListAllCond, order)
	}

	return GetEdbDataListAllByMysqlTo(to, source, subSource, findEdbDataListAllCond, order)
}

// GetEdbDataListAllByMysqlTo
// @Description: 根据事务链接获取指标数据列表 order:1升序，其余值为降序（Mysql）
// @author: Roc
// @datetime 2024-05-08 15:34:13
// @param to orm.TxOrmer
// @param source int
// @param subSource int
// @param findEdbDataListAllCond FindEdbDataListAllCond
// @param order int
// @return item []*EdbInfoSearchData
// @return err error
func GetEdbDataListAllByMysqlTo(to orm.TxOrmer, source, subSource int, findEdbDataListAllCond FindEdbDataListAllCond, order int) (item []*EdbInfoSearchData, err error) {
	if findEdbDataListAllCond.EdbInfoId <= 0 {
		return
	}
	sql := ``
	tableName := GetEdbDataTableName(source, subSource)
	sql = ` SELECT * FROM %s WHERE 1=1 `
	sql = fmt.Sprintf(sql, tableName)

	var condition string
	var pars []interface{}
	condition += " AND edb_info_id=? "
	pars = append(pars, findEdbDataListAllCond.EdbInfoId)

	// 开始日期
	if findEdbDataListAllCond.StartDataTime != "" && findEdbDataListAllCond.StartDataTimeCond != `` {
		condition += fmt.Sprintf(" AND data_time %s ? ", findEdbDataListAllCond.StartDataTimeCond)
		pars = append(pars, findEdbDataListAllCond.StartDataTime)
	}
	// 结束日期
	if findEdbDataListAllCond.EndDataTime != "" && findEdbDataListAllCond.EndDataTimeCond != `` {
		condition += fmt.Sprintf(" AND data_time %s ? ", findEdbDataListAllCond.EndDataTimeCond)
		pars = append(pars, findEdbDataListAllCond.EndDataTime)
	}

	if condition != "" {
		sql += condition
	}
	if order == 1 {
		sql += ` ORDER BY data_time ASC `
	} else {
		sql += ` ORDER BY data_time DESC `
	}
	_, err = to.Raw(sql, pars).QueryRows(&item)
	return
}

// GetEdbDataListAllByMongo
// @Description: 根据事务链接获取指标数据列表 order:1升序，其余值为降序（Mongo）
// @author: Roc
// @datetime 2024-05-08 15:34:24
// @param source int
// @param subSource int
// @param findEdbDataListAllCond FindEdbDataListAllCond
// @param order int
// @return dataList []*EdbInfoSearchData
// @return err error
func GetEdbDataListAllByMongo(source, subSource int, findEdbDataListAllCond FindEdbDataListAllCond, order int) (dataList []*EdbInfoSearchData, err error) {
	dataList = make([]*EdbInfoSearchData, 0)
	if findEdbDataListAllCond.EdbInfoId <= 0 {
		return
	}
	mogDataObj := mgo.EdbDataBusiness{}
	// 构建查询条件
	queryConditions := bson.M{
		"edb_info_id": findEdbDataListAllCond.EdbInfoId,
	}
	dateCondition, err := mgo.BuildDateCondition(findEdbDataListAllCond.StartDataTime, findEdbDataListAllCond.EndDataTime)
	if err != nil {
		return
	}
	if len(dateCondition) > 0 {
		queryConditions["data_time"] = dateCondition
	}

	sortList := make([]string, 0)
	if order == 1 {
		sortList = append(sortList, "data_time")
	} else {
		sortList = append(sortList, "-data_time")
	}
	// 获取列表数据
	tmpDataList, tmpErr := mogDataObj.GetAllDataList(queryConditions, sortList)
	if tmpErr != nil {
		err = tmpErr
		return
	}
	for k, v := range tmpDataList {
		dataList = append(dataList, &EdbInfoSearchData{
			EdbDataId:     k + 1,
			EdbInfoId:     v.EdbInfoId,
			EdbCode:       v.EdbCode,
			DataTime:      v.DataTime.Format(utils.FormatDate),
			Value:         v.Value,
			DataTimestamp: v.DataTimestamp,
		})
	}
	return
}

// EdbInfoMaxAndMinInfo 指标最新数据记录结构体
type EdbInfoMaxAndMinInfo struct {
	MinDate     string  `description:"最小日期" bson:"min_date"`
	MaxDate     string  `description:"最大日期" bson:"max_date"`
	MinValue    float64 `description:"最小值" bson:"min_value"`
	MaxValue    float64 `description:"最大值" bson:"max_value"`
	LatestValue float64 `description:"最新值" bson:"latest_value"`
	LatestDate  string  `description:"实际数据最新日期" bson:"latest_date"`
	EndValue    float64 `description:"最新值" bson:"end_value"`
}

// GetEdbInfoMaxAndMinInfo 获取指标的最新数据记录信息
func GetEdbInfoMaxAndMinInfo(source, subSource int, edbCode string) (item *EdbInfoMaxAndMinInfo, err error) {
	o := orm.NewOrm()
	sql := ``
	tableName := GetEdbDataTableName(source, subSource)
	sql = ` SELECT MIN(data_time) AS min_date,MAX(data_time) AS max_date,MIN(value) AS min_value,MAX(value) AS max_value FROM %s WHERE edb_code=? `
	sql = fmt.Sprintf(sql, tableName)
	err = o.Raw(sql, edbCode).QueryRow(&item)

	var latest_value float64
	sql = ` SELECT value AS latest_value FROM %s WHERE edb_code=? ORDER BY data_time DESC LIMIT 1 `
	sql = fmt.Sprintf(sql, tableName)
	err = o.Raw(sql, edbCode).QueryRow(&latest_value)
	item.LatestValue = latest_value
	return
}

type EdbIndoDataUpdateTime struct {
	MinDate string `description:"本次更新，数据发生变化的最早日期"`
}

// GetEdbDataUpdateTimeByModify 获取指标的刷新时间获取最早的一条记录
func GetEdbDataUpdateTimeByModify(source, subSource int, edbCode string, dataUpdateTime string) (item *EdbIndoDataUpdateTime, err error) {
	o := orm.NewOrm()
	sql := ``
	tableName := GetEdbDataTableName(source, subSource)
	sql = ` SELECT MIN(data_time) AS min_date FROM %s WHERE edb_code=? and modify_time>=?`
	sql = fmt.Sprintf(sql, tableName)
	err = o.Raw(sql, edbCode, dataUpdateTime).QueryRow(&item)
	return
}

// ModifyEdbInfoMaxAndMinInfo 修改指标的最新数据信息
func ModifyEdbInfoMaxAndMinInfo(edbInfoId int, item *EdbInfoMaxAndMinInfo) (err error) {
	o := orm.NewOrm()
	sql := ` UPDATE edb_info SET start_date=?,end_date=?,min_value=?,max_value=?,is_update=2,latest_date=?,latest_value=?, end_value = ?,modify_time=NOW() WHERE edb_info_id=? `
	_, err = o.Raw(sql, item.MinDate, item.MaxDate, item.MinValue, item.MaxValue, item.MaxDate, item.LatestValue, item.LatestValue, edbInfoId).Exec()
	return
}

// ModifyEdbTimeAndLastInfo 修改指标的最新数据信息(除上下限)
func ModifyEdbTimeAndLastInfo(edbInfoId int, item *EdbInfoMaxAndMinInfo) (err error) {
	o := orm.NewOrm()
	sql := `UPDATE edb_info SET start_date = ?, end_date = ?, is_update = 2,latest_date = ?, latest_value = ?, end_value = ?, modify_time = NOW() WHERE edb_info_id = ?`
	_, err = o.Raw(sql, item.MinDate, item.MaxDate, item.MaxDate, item.LatestValue, item.LatestValue, edbInfoId).Exec()
	return
}

// ModifyEdbDataUpdateTime 修改指标刷新，本次数据刷新的最早日期
func ModifyEdbDataUpdateTime(edbInfoId int, dataUpdateTime, erDataUpdateDate string) (err error) {
	o := orm.NewOrm()
	sql := `UPDATE edb_info SET data_update_time = ?, er_data_update_date = ?, modify_time = NOW() WHERE edb_info_id = ?`
	_, err = o.Raw(sql, dataUpdateTime, erDataUpdateDate, edbInfoId).Exec()
	return
}

// GetLteZeroEdbDataCount
// @Description: 获取小于等于0的数据数量
// @author: Roc
// @datetime 2024-05-31 10:44:39
// @param source int
// @param subSource int
// @param edbInfoId int
// @return count int
// @return err error
func GetLteZeroEdbDataCount(source, subSource, edbInfoId int) (count int, err error) {
	if source == utils.DATA_SOURCE_BUSINESS {
		return GetLteZeroEdbDataCountByMongo(source, subSource, edbInfoId)
	}

	return GetLteZeroEdbDataCountByMysql(source, subSource, edbInfoId)
}

// GetLteZeroEdbDataCountByMongo
// @Description: 获取小于等于0的数据数量（从mongo）
// @author: Roc
// @datetime 2024-05-31 10:41:04
// @param source int
// @param subSource int
// @param edbInfoId int
// @return count int
// @return err error
func GetLteZeroEdbDataCountByMongo(source, subSource, edbInfoId int) (count int, err error) {
	mogDataObj := mgo.EdbDataBusiness{}
	// 构建查询条件
	whereQuery := bson.M{
		"edb_info_id": edbInfoId,
		"value":       bson.M{"$lte": 0},
	}
	// 获数量数据
	tmpCount, err := mogDataObj.GetCountDataList(whereQuery)
	if err != nil {
		return
	}

	count = int(tmpCount)

	return
}

// GetLteZeroEdbDataCountByMysql
// @Description: 获取小于等于0的数据数量（从mysql）
// @author: Roc
// @datetime 2024-05-31 10:29:19
// @param source int
// @param subSource int
// @param edbInfoId int
// @return count int
// @return err error
func GetLteZeroEdbDataCountByMysql(source, subSource, edbInfoId int) (count int, err error) {
	o := orm.NewOrm()
	sql := ``
	tableName := GetEdbDataTableName(source, subSource)
	sql = ` SELECT COUNT(1) AS count FROM %s WHERE 1=1 AND edb_info_id =?  AND value <=0 `
	sql = fmt.Sprintf(sql, tableName)
	err = o.Raw(sql, edbInfoId).QueryRow(&count)
	return
}

// GetLastEdbData 获取最近的一条指标数据
func GetLastEdbData(condition string, pars []interface{}, source, subSource int) (item *EdbInfoSearchData, err error) {
	o := orm.NewOrm()
	sql := ``
	tableName := GetEdbDataTableName(source, subSource)
	sql = ` SELECT * FROM %s WHERE 1=1 `
	sql = fmt.Sprintf(sql, tableName)

	if condition != "" {
		sql += condition
	}
	sql += ` ORDER BY data_time DESC `
	err = o.Raw(sql, pars).QueryRow(&item)
	return
}

// GetEdbInfoByEdbCode 根据指标code获取指标信息
func GetEdbInfoByEdbCode(source int, edbCode string) (item *EdbInfo, err error) {
	o := orm.NewOrm()
	sql := ` SELECT * FROM edb_info WHERE source=? AND edb_code=? `
	err = o.Raw(sql, source, edbCode).QueryRow(&item)
	return
}

// GetEdbInfoOnlyByEdbCode 仅根据指标code获取指标信息
func GetEdbInfoOnlyByEdbCode(edbCode string) (item *EdbInfo, err error) {
	o := orm.NewOrm()
	sql := ` SELECT * FROM edb_info WHERE edb_code=? `
	err = o.Raw(sql, edbCode).QueryRow(&item)
	return
}

// GetEdbInfoCalculateListByCondition 获取指标关系列表
func GetEdbInfoCalculateListByCondition(condition string, pars []interface{}) (items []*EdbInfoCalculateMapping, err error) {
	o := orm.NewOrm()

	sql := ` SELECT * FROM edb_info_calculate_mapping WHERE 1=1 `
	if condition != "" {
		sql += condition
	}
	_, err = o.Raw(sql, pars).QueryRows(&items)
	return
}

// GetEdbInfoCalculateCountByCondition 获取关联指标数量
func GetEdbInfoCalculateCountByCondition(condition string, pars []interface{}) (count int, err error) {
	o := orm.NewOrm()

	sql := ` SELECT COUNT(1) AS count FROM edb_info_calculate_mapping WHERE 1=1 `
	if condition != "" {
		sql += condition
	}
	err = o.Raw(sql, pars).QueryRow(&count)
	return
}

// 优化版本-处理数据精度问题
type EdbInfoSearchDataV1 struct {
	EdbDataId int    `description:"数据ID"`
	DataTime  string `description:"数据日期"`
	Value     string `description:"数据"`
}

// 优化版本-处理数据精度问题
func GetEdbDataListAllV1(condition string, pars []interface{}, source, subSource, order int) (item []*EdbInfoSearchDataV1, err error) {
	o := orm.NewOrm()
	sql := ``
	tableName := GetEdbDataTableName(source, subSource)
	sql = ` SELECT * FROM %s WHERE 1=1 `
	sql = fmt.Sprintf(sql, tableName)

	if condition != "" {
		sql += condition
	}
	if order == 1 {
		sql += ` ORDER BY data_time ASC `
	} else {
		sql += ` ORDER BY data_time DESC `
	}
	_, err = o.Raw(sql, pars).QueryRows(&item)
	return
}

// GetEdbDataListAllV1ByTo 通过事务链接获取数据列表
func GetEdbDataListAllV1ByTo(to orm.TxOrmer, condition string, pars []interface{}, source, subSource, order int) (item []*EdbInfoSearchDataV1, err error) {
	sql := ``
	tableName := GetEdbDataTableName(source, subSource)
	sql = ` SELECT * FROM %s WHERE 1=1 `
	sql = fmt.Sprintf(sql, tableName)

	if condition != "" {
		sql += condition
	}
	if order == 1 {
		sql += ` ORDER BY data_time ASC `
	} else {
		sql += ` ORDER BY data_time DESC `
	}
	_, err = to.Raw(sql, pars).QueryRows(&item)
	return
}

// GetEdbInfoByCondition 获取指标列表
func GetEdbInfoByCondition(condition string, pars []interface{}, order int) (item []*EdbInfo, err error) {
	o := orm.NewOrm()
	sql := ` SELECT * FROM edb_info WHERE 1=1 `
	if condition != "" {
		sql += condition
	}
	if order == 1 {
		sql += ` ORDER BY end_date ASC `
	} else {
		sql += ` ORDER BY edb_info_id ASC `
	}
	_, err = o.Raw(sql, pars).QueryRows(&item)
	return
}

// UnifiedModifyEdbInfoMaxAndMinInfo 统一修改指标的最大最小值
func UnifiedModifyEdbInfoMaxAndMinInfo(edbInfo *EdbInfo) (err error, errMsg string) {
	// 修改最大最小值
	maxAndMinItem, err := GetEdbInfoMaxAndMinInfo(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbCode)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = nil
			return
		}

		errMsg = "刷新指标失败！"
		err = errors.New("获取指标最大最小值失败，err:" + err.Error())
		return
	}

	if maxAndMinItem != nil {
		// ETA1.0.3改-如果指标有手动保存过, 那么就不更新指标的最大最小值
		if edbInfo.ManualSave == 1 {
			err = ModifyEdbTimeAndLastInfo(edbInfo.EdbInfoId, maxAndMinItem)
			if err != nil {
				errMsg = "刷新指标失败！"
				err = errors.New("修改指标最新日期和数据失败，err:" + err.Error())
				return
			}
		} else {
			err = ModifyEdbInfoMaxAndMinInfo(edbInfo.EdbInfoId, maxAndMinItem)
			if err != nil {
				errMsg = "刷新指标失败！"
				err = errors.New("修改指标最大最小值失败，err:" + err.Error())
				return
			}
		}
	}

	// 刷新关联的预测指标
	go RefreshPredictStandardBaseByGeneralEdbInfoId(edbInfo.EdbInfoId)

	//go ModifyPredictEdbInfoMaxAndMinInfoBySourceEdbInfoId(edbInfo.EdbInfoId, maxAndMinItem)
	return
}

// UnifiedModifyEdbInfoMaxAndMinInfoDataUpdate 统一修改指标的最大最小值以及数据更新时间点
func UnifiedModifyEdbInfoMaxAndMinInfoDataUpdate(edbInfo *EdbInfo, dataUpdateTime string) (erDataUpdateDate string, err error, errMsg string) {
	err, errMsg = UnifiedModifyEdbInfoMaxAndMinInfo(edbInfo)
	if err != nil {
		return
	}
	// 获取本次刷新，指标数据更新的最早日期
	erDataUpdateTime, tErr := GetEdbDataUpdateTimeByModify(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbCode, dataUpdateTime)
	if tErr != nil {
		if tErr.Error() != utils.ErrNoRow() { //本次刷新指标数据无变化
			errMsg = "刷新指标失败！"
			err = errors.New("查询指标刷新，数据更新的最早日期失败，err:" + tErr.Error())
			return
		}
	} else if erDataUpdateTime.MinDate != "" {
		err = ModifyEdbDataUpdateTime(edbInfo.EdbInfoId, dataUpdateTime, erDataUpdateTime.MinDate)
		if err != nil {
			errMsg = "刷新指标失败！"
			err = errors.New("修改指标数据更新的最早日期失败，err:" + tErr.Error())
			return
		}
		erDataUpdateDate = erDataUpdateTime.MinDate
	}
	return
}

// UnifiedModifyPredictEdbInfoMaxAndMinInfo 统一修改预测运算指标的最大最小值
func UnifiedModifyPredictEdbInfoMaxAndMinInfo(edbInfo *EdbInfo, latestDateStr string, latestValue float64) (err error, errMsg string) {
	// 修改最大最小值
	maxAndMinItem, err := GetEdbInfoMaxAndMinInfo(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbCode)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = nil
			return
		}

		errMsg = "刷新指标失败！"
		err = errors.New("获取指标最大最小值失败，err:" + err.Error())
		return
	}

	// 最晚的日期的值
	maxAndMinItem.EndValue = maxAndMinItem.LatestValue

	if maxAndMinItem != nil {
		maxAndMinItem.LatestDate = latestDateStr
		maxAndMinItem.LatestValue = latestValue
		err = ModifyPredictEdbInfoMaxAndMinInfo(edbInfo.EdbInfoId, maxAndMinItem)
		if err != nil {
			errMsg = "刷新指标失败！"
			err = errors.New("修改指标最大最小值失败，err:" + err.Error())
			return
		}
	}
	return
}

// GetChartPredictEdbInfoDataListByConfList 获取图表的预测指标的未来数据
func GetChartPredictEdbInfoDataListByConfList(predictEdbConfList []*PredictEdbConfAndData, filtrateStartDateStr, latestDateStr, endDateStr, frequency, dataDateType string, realPredictEdbInfoData []*EdbInfoSearchData) (predictEdbInfoData []*EdbInfoSearchData, minValue, maxValue float64, err error) {
	endDate, err := time.ParseInLocation(utils.FormatDate, endDateStr, time.Local)
	if err != nil {
		return
	}

	latestDate, err := time.ParseInLocation(utils.FormatDate, latestDateStr, time.Local)
	if err != nil {
		return
	}

	// 开始预测数据的时间
	startDate := latestDate

	// 如果有筛选时间的话
	if filtrateStartDateStr != `` {
		filtrateStartDate, tmpErr := time.ParseInLocation(utils.FormatDate, filtrateStartDateStr, time.Local)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		//如果筛选时间晚于实际数据时间，那么就以筛选时间作为获取预测数据的时间
		if filtrateStartDate.After(latestDate) {
			startDate = filtrateStartDate.AddDate(0, 0, -1)
		}
	}

	//var dateArr []string
	// 对应日期的值
	existMap := make(map[string]float64)
	for _, v := range realPredictEdbInfoData {
		//dateArr = append(dateArr, v.DataTime)
		existMap[v.DataTime] = v.Value
	}

	predictEdbInfoData = make([]*EdbInfoSearchData, 0)
	//dataValue := lastDataValue
	//预测规则，1：最新，2：固定值，3：同比，4：同差，5：环比，6：环差，7：N期移动均值，8：N期段线性外推值

	for _, predictEdbConf := range predictEdbConfList {
		//dataEndTime := endDate
		//if predictEdbConf.EndDate.Before(dataEndTime) {
		//	dataEndTime = predictEdbConf.EndDate
		//}
		endDate = predictEdbConf.EndDate
		var tmpMinValue, tmpMaxValue float64 // 当前预测结果中的最大/最小值

		dayList := getPredictEdbDayList(startDate, endDate, frequency, dataDateType)
		if len(dayList) <= 0 { // 如果未来没有日期的话，那么就退出当前循环，进入下一个循环
			continue
		}

		switch predictEdbConf.RuleType {
		case 1: //1：最新
			var lastDataValue float64 //最新值
			tmpAllData := make([]*EdbInfoSearchData, 0)
			tmpAllData = append(tmpAllData, realPredictEdbInfoData...)
			tmpAllData = append(tmpAllData, predictEdbInfoData...)
			lenTmpAllData := len(tmpAllData)
			if lenTmpAllData > 0 {
				lastDataValue = tmpAllData[lenTmpAllData-1].Value
			}
			predictEdbInfoData = GetChartPredictEdbInfoDataListByRule1(predictEdbConf.PredictEdbInfoId, lastDataValue, dayList, predictEdbInfoData, existMap)
			tmpMaxValue = lastDataValue
			tmpMinValue = lastDataValue
		case 2: //2：固定值
			tmpValDecimal, tmpErr := decimal.NewFromString(predictEdbConf.Value)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			dataValue, _ := tmpValDecimal.Float64()
			predictEdbInfoData = GetChartPredictEdbInfoDataListByRule1(predictEdbConf.PredictEdbInfoId, dataValue, dayList, predictEdbInfoData, existMap)

			tmpMaxValue = dataValue
			tmpMinValue = dataValue
		case 3: //3：同比
			tmpValDecimal, tmpErr := decimal.NewFromString(predictEdbConf.Value)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			tbValue, _ := tmpValDecimal.Float64()
			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleTb(predictEdbConf.PredictEdbInfoId, tbValue, dayList, frequency, realPredictEdbInfoData, predictEdbInfoData, existMap)
		case 4: //4：同差
			tmpValDecimal, tmpErr := decimal.NewFromString(predictEdbConf.Value)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			tcValue, _ := tmpValDecimal.Float64()
			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleTc(predictEdbConf.PredictEdbInfoId, tcValue, dayList, frequency, realPredictEdbInfoData, predictEdbInfoData, existMap)
		case 5: //5：环比
			tmpValDecimal, tmpErr := decimal.NewFromString(predictEdbConf.Value)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			hbValue, _ := tmpValDecimal.Float64()
			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleHb(predictEdbConf.PredictEdbInfoId, hbValue, dayList, realPredictEdbInfoData, predictEdbInfoData, existMap)
		case 6: //6：环差
			tmpValDecimal, tmpErr := decimal.NewFromString(predictEdbConf.Value)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			hcValue, _ := tmpValDecimal.Float64()
			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleHc(predictEdbConf.PredictEdbInfoId, hcValue, dayList, realPredictEdbInfoData, predictEdbInfoData, existMap)
		case 7: //7：N期移动均值
			nValue, tmpErr := strconv.Atoi(predictEdbConf.Value)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleNMoveMeanValue(predictEdbConf.PredictEdbInfoId, nValue, dayList, realPredictEdbInfoData, predictEdbInfoData, existMap)
		case 8: //8：N期段线性外推值
			nValue, tmpErr := strconv.Atoi(predictEdbConf.Value)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			predictEdbInfoData, tmpMinValue, tmpMaxValue, err = GetChartPredictEdbInfoDataListByRuleNLinearRegression(predictEdbConf.PredictEdbInfoId, nValue, dayList, realPredictEdbInfoData, predictEdbInfoData, existMap)
			if err != nil {
				return
			}
		case 9: //9：动态环差”预测规则；
			hcDataMap := make(map[string]float64) //规则计算的环差值map

			if predictEdbConf.PredictEdbInfoId > 0 {
				tmpPredictEdbRuleDataList, tmpErr := GetPredictEdbRuleDataItemList(predictEdbConf.PredictEdbInfoId, predictEdbConf.ConfigId, startDate.Format(utils.FormatDate), endDate.Format(utils.FormatDate))
				if tmpErr != nil {
					err = tmpErr
					return
				}
				for _, v := range tmpPredictEdbRuleDataList {
					hcDataMap[v.DataTime] = v.Value
				}
			} else {
				if len(predictEdbConf.DataList) <= 0 {
					return
				}
				for _, v := range predictEdbConf.DataList {
					currentDate, tmpErr := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
					if tmpErr != nil {
						continue
					}
					// 只处理时间段内的数据
					if currentDate.Before(startDate) || currentDate.After(endDate) {
						continue
					}
					hcDataMap[v.DataTime] = v.Value
				}
			}

			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleTrendsHC(predictEdbConf.PredictEdbInfoId, dayList, realPredictEdbInfoData, predictEdbInfoData, hcDataMap, existMap)
		case 10: //10：根据 给定终值后插值 规则获取预测数据
			tmpValDecimal, tmpErr := decimal.NewFromString(predictEdbConf.Value)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			finalValue, _ := tmpValDecimal.Float64()
			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleFinalValueHc(predictEdbConf.PredictEdbInfoId, finalValue, dayList, realPredictEdbInfoData, predictEdbInfoData, existMap)
		case 11: //11：根据 季节性 规则获取预测数据
			var seasonConf SeasonConf
			tmpErr := json.Unmarshal([]byte(predictEdbConf.Value), &seasonConf)
			if tmpErr != nil {
				err = errors.New("季节性配置信息异常:" + tmpErr.Error())
				return
			}
			calendar := "公历"
			if seasonConf.Calendar == "农历" {
				calendar = "农历"
			}
			yearList := make([]int, 0)
			//选择方式，1：连续N年；2：指定年份
			if seasonConf.YearType == 1 {
				if seasonConf.NValue < 1 {
					err = errors.New("连续N年不允许小于1")
					return
				}

				currYear := time.Now().Year()
				for i := 0; i < seasonConf.NValue; i++ {
					yearList = append(yearList, currYear-i-1)
				}
			} else {
				yearList = seasonConf.YearList
			}
			predictEdbInfoData, tmpMinValue, tmpMaxValue, err = GetChartPredictEdbInfoDataListByRuleSeason(predictEdbConf.PredictEdbInfoId, yearList, calendar, dayList, realPredictEdbInfoData, predictEdbInfoData, existMap)
			if err != nil {
				return
			}
		case 12: //12：根据 移动平均同比 规则获取预测数据
			var moveAverageConf MoveAverageConf
			tmpErr := json.Unmarshal([]byte(predictEdbConf.Value), &moveAverageConf)
			if tmpErr != nil {
				err = errors.New("季节性配置信息异常:" + tmpErr.Error())
				return
			}
			predictEdbInfoData, tmpMinValue, tmpMaxValue, err = GetChartPredictEdbInfoDataListByRuleMoveAverageTb(predictEdbConf.PredictEdbInfoId, moveAverageConf.NValue, moveAverageConf.Year, dayList, realPredictEdbInfoData, predictEdbInfoData, existMap)
			if err != nil {
				return
			}
		case 13: //13：根据 同比增速差值 规则获取预测数据
			tmpValDecimal, tmpErr := decimal.NewFromString(predictEdbConf.Value)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			tbEndValue, _ := tmpValDecimal.Float64()
			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleTbzscz(predictEdbConf.PredictEdbInfoId, tbEndValue, dayList, frequency, realPredictEdbInfoData, predictEdbInfoData, existMap)
		case 14: //14：根据 一元线性拟合 规则获取预测数据
			var ruleConf RuleLineNhConf
			err = json.Unmarshal([]byte(predictEdbConf.Value), &ruleConf)
			if err != nil {
				err = errors.New("一元线性拟合规则配置信息异常:" + err.Error())
				return
			}

			// 规则计算的拟合残差值map
			newNhccDataMap := make(map[string]float64)
			if predictEdbConf.PredictEdbInfoId > 0 { //已经生成的动态数据
				tmpPredictEdbRuleDataList, tmpErr := GetPredictEdbRuleDataItemList(predictEdbConf.PredictEdbInfoId, predictEdbConf.ConfigId, startDate.Format(utils.FormatDate), endDate.Format(utils.FormatDate))
				if tmpErr != nil {
					err = tmpErr
					return
				}
				for _, v := range tmpPredictEdbRuleDataList {
					newNhccDataMap[v.DataTime] = v.Value
				}
			} else { //未生成的动态数据，需要使用外部传入的数据进行计算
				newNhccDataMap, err, _ = getCalculateNhccData(append(realPredictEdbInfoData, predictEdbInfoData...), ruleConf)
			}

			predictEdbInfoData, tmpMinValue, tmpMaxValue, err = GetChartPredictEdbInfoDataListByRuleLineNh(predictEdbConf.PredictEdbInfoId, dayList, realPredictEdbInfoData, predictEdbInfoData, newNhccDataMap, existMap)
			if err != nil {
				return
			}

		case 15: //15：N年均值：过去N年同期均值。过去N年可以连续或者不连续，指标数据均用线性插值补全为日度数据后计算；
			predictEdbInfoData, tmpMinValue, tmpMaxValue, err = GetChartPredictEdbInfoDataListByRuleNAnnualAverage(predictEdbConf.PredictEdbInfoId, predictEdbConf.Value, dayList, realPredictEdbInfoData, predictEdbInfoData, existMap)
			if err != nil {
				return
			}

		case 16: //16：年度值倒推
			predictEdbInfoData, tmpMinValue, tmpMaxValue, err = GetChartPredictEdbInfoDataListByRuleAnnualValueInversion(predictEdbConf.PredictEdbInfoId, predictEdbConf.Value, dayList, frequency, realPredictEdbInfoData, predictEdbInfoData, existMap)
			if err != nil {
				return
			}
		}

		// 下一个规则的开始日期
		{
			lenPredictEdbInfoData := len(predictEdbInfoData)
			if lenPredictEdbInfoData > 0 {
				tmpDataEndTime, _ := time.ParseInLocation(utils.FormatDate, predictEdbInfoData[lenPredictEdbInfoData-1].DataTime, time.Local)
				if startDate.Before(tmpDataEndTime) {
					startDate = tmpDataEndTime
				}
			}
		}

		if tmpMinValue < minValue {
			minValue = tmpMinValue
		}
		if tmpMaxValue < maxValue {
			maxValue = tmpMaxValue
		}
	}

	return
}

// GetPredictEdbDayList 获取预测指标日期列表

// GetPredictEdbDayList 获取预测指标日期列表
func getPredictEdbDayList(startDate, endDate time.Time, frequency, dataDateType string) (dayList []time.Time) {
	if dataDateType == `` {
		dataDateType = `交易日`
	}
	switch frequency {
	case "日度":
		for currDate := startDate.AddDate(0, 0, 1); currDate.Before(endDate) || currDate.Equal(endDate); currDate = currDate.AddDate(0, 0, 1) {
			// 如果日期类型是交易日的时候，那么需要将周六、日排除
			if dataDateType == `交易日` && (currDate.Weekday() == time.Sunday || currDate.Weekday() == time.Saturday) {
				continue
			}
			dayList = append(dayList, currDate)
		}
	case "周度":
		//nextDate := startDate.AddDate(0, 0, 7)
		for currDate := startDate.AddDate(0, 0, 7); currDate.Before(endDate) || currDate.Equal(endDate); currDate = currDate.AddDate(0, 0, 7) {
			dayList = append(dayList, currDate)
		}
	case "旬度":
		for currDate := startDate.AddDate(0, 0, 1); currDate.Before(endDate) || currDate.Equal(endDate); {
			nextDate := currDate.AddDate(0, 0, 1)
			//每个月的10号、20号、最后一天，那么就写入
			if nextDate.Day() == 11 || nextDate.Day() == 21 || nextDate.Day() == 1 {
				dayList = append(dayList, currDate)
			}
			currDate = nextDate
		}
	case "月度":
		for currDate := startDate; currDate.Before(endDate) || currDate.Equal(endDate); {
			currDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, time.Now().Location()).AddDate(0, 1, -1)
			if !currDate.After(endDate) && !currDate.Equal(startDate) {
				dayList = append(dayList, currDate)
			}
			currDate = currDate.AddDate(0, 0, 1)
		}
	case "季度":
		for currDate := startDate; currDate.Before(endDate) || currDate.Equal(endDate); {
			// 每月的最后一天
			currDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, time.Now().Location()).AddDate(0, 1, -1)
			if !currDate.After(endDate) && !currDate.Equal(startDate) {
				// 季度日期就写入，否则不写入
				if currDate.Month() == 3 || currDate.Month() == 6 || currDate.Month() == 9 || currDate.Month() == 12 {
					dayList = append(dayList, currDate)
				}
			}
			currDate = currDate.AddDate(0, 0, 1)
		}
	case "半年度":
		for currDate := startDate; currDate.Before(endDate) || currDate.Equal(endDate); {
			// 每月的最后一天
			currDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, time.Now().Location()).AddDate(0, 1, -1)
			if !currDate.After(endDate) && !currDate.Equal(startDate) {
				// 半年度日期就写入，否则不写入
				if currDate.Month() == 6 || currDate.Month() == 12 {
					dayList = append(dayList, currDate)
				}
			}
			currDate = currDate.AddDate(0, 0, 1)
		}
	case "年度":
		for currDate := startDate; currDate.Before(endDate) || currDate.Equal(endDate); {
			currDate = time.Date(currDate.Year()+1, 12, 31, 0, 0, 0, 0, time.Now().Location())
			if !currDate.After(endDate) && !currDate.Equal(startDate) {
				dayList = append(dayList, currDate)
			}
		}
	}
	return
}

// GetPredictDataListByPredictEdbInfo 根据预测指标信息获取预测指标的数据，order:1升序，其余值为降序
func GetPredictDataListByPredictEdbInfo(edbInfo *EdbInfo, order int, startDate string) (dataList []*EdbInfoSearchData, sourceEdbInfoItem *EdbInfo, err error, errMsg string) {
	// 查找该预测指标配置
	predictEdbConfList, err := GetPredictEdbConfAndDataListById(edbInfo.EdbInfoId)
	if err != nil && err.Error() != utils.ErrNoRow() {
		errMsg = "获取预测指标配置信息失败"
		return
	}
	if len(predictEdbConfList) == 0 {
		errMsg = "获取预测指标配置信息失败"
		err = errors.New(errMsg)
		return
	}
	predictEdbConf := predictEdbConfList[0]

	// 来源指标
	sourceEdbInfoItem, err = GetEdbInfoById(predictEdbConf.SourceEdbInfoId)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			errMsg = "找不到来源指标信息"
			err = errors.New(errMsg)
		}
		return
	}

	dataList, err, errMsg = GetPredictDataListByPredictEdbConfList(edbInfo, sourceEdbInfoItem, predictEdbConfList, order, startDate)

	return
}

// GetPredictDataListByPredictEdbConfList 根据预测指标信息获取预测指标的数据，order:1升序，其余值为降序
func GetPredictDataListByPredictEdbConfList(edbInfo, sourceEdbInfoItem *EdbInfo, predictEdbConfList []*PredictEdbConfAndData, order int, startDate string) (dataList []*EdbInfoSearchData, err error, errMsg string) {
	allDataList := make([]*EdbInfoSearchData, 0)
	//获取指标数据（实际已生成）
	tmpDataList, err := GetEdbDataListAll(sourceEdbInfoItem.Source, sourceEdbInfoItem.SubSource, FindEdbDataListAllCond{
		EdbInfoId:         sourceEdbInfoItem.EdbInfoId,
		StartDataTime:     startDate,
		StartDataTimeCond: ">=",
	}, 1)
	if err != nil {
		return
	}

	// 默认认为上一个查询是把所有的数据查出来了
	allDataList = tmpDataList

	// 如果条件中有选择了日期，那么上次查询实际并不是把所有的数据查出来了
	// 那么需要把日期给过滤掉，然后筛选所有的数据，用于未来指标的生成
	if startDate != `` {
		allDataList, err = GetEdbDataListAll(sourceEdbInfoItem.Source, sourceEdbInfoItem.SubSource, FindEdbDataListAllCond{
			EdbInfoId: sourceEdbInfoItem.EdbInfoId,
		}, 1)
		if err != nil {
			return
		}
	}

	// 获取预测指标未来的数据
	predictDataList := make([]*EdbInfoSearchData, 0)

	endDateStr := edbInfo.EndDate //预测指标的结束日期

	var predictMinValue, predictMaxValue float64
	// 如果有配置的预测规则，那么就进行预测
	if len(predictEdbConfList) > 0 {
		predictDataList, predictMinValue, predictMaxValue, err = GetChartPredictEdbInfoDataListByConfList(predictEdbConfList, startDate, sourceEdbInfoItem.LatestDate, endDateStr, edbInfo.Frequency, edbInfo.DataDateType, allDataList)
		if err != nil {
			return
		}
	}

	//order:1升序，其余值为降序
	if order == 1 {
		dataList = append(tmpDataList, predictDataList...)
	} else {
		// 先倒序预测数据
		lenPredictDataList := len(predictDataList)
		if lenPredictDataList > 0 {
			for k := range predictDataList {
				dataList = append(dataList, predictDataList[lenPredictDataList-k-1])
			}
		}

		// 接着倒序实际指标
		lenDataList := len(tmpDataList)
		for k := range tmpDataList {
			dataList = append(dataList, tmpDataList[lenDataList-k-1])
		}
	}
	if len(predictDataList) > 0 {
		// 如果最小值 大于 预测值，那么将预测值作为最小值数据返回
		if edbInfo.MinValue > predictMinValue {
			edbInfo.MinValue = predictMinValue
		}

		// 如果最大值 小于 预测值，那么将预测值作为最大值数据返回
		if edbInfo.MaxValue < predictMaxValue {
			edbInfo.MaxValue = predictMaxValue
		}
	}
	return
}

// GetPredictEdbDataListAll 获取该预测指标所有的数据 ，order:1升序，其余值为降序
func GetPredictEdbDataListAll(edbInfo *EdbInfo, order int) (items []*EdbInfoSearchData, err error) {
	if edbInfo.Source == utils.DATA_SOURCE_PREDICT { //普通的预测指标是没有入库数据的，直接往配置里面获取
		items, _, err, _ = GetPredictDataListByPredictEdbInfo(edbInfo, 1, "")
	} else {
		items, err = GetEdbDataListAll(edbInfo.Source, edbInfo.SubSource, FindEdbDataListAllCond{
			EdbInfoId: edbInfo.EdbInfoId,
		}, order)
	}
	return
}

// GetPredictEdbDataListAllByStartDate 根据开始日期获取该预测指标所有的数据 ，order:1升序，其余值为降序
func GetPredictEdbDataListAllByStartDate(edbInfo *EdbInfo, order int, startDate string) (items []*EdbInfoSearchData, err error) {
	if edbInfo.Source == utils.DATA_SOURCE_PREDICT { //普通的预测指标是没有入库数据的，直接往配置里面获取
		items, _, err, _ = GetPredictDataListByPredictEdbInfo(edbInfo, order, startDate)
	} else {
		items, err = GetEdbDataListAll(edbInfo.Source, edbInfo.SubSource, FindEdbDataListAllCond{
			EdbInfoId:         edbInfo.EdbInfoId,
			StartDataTime:     startDate,
			StartDataTimeCond: ">=",
		}, order)
	}
	return
}

// ModifyPredictEdbInfoMaxAndMinInfo 修改预测指标的最新数据信息
func ModifyPredictEdbInfoMaxAndMinInfo(edbInfoId int, item *EdbInfoMaxAndMinInfo) (err error) {
	o := orm.NewOrm()
	sql := ` UPDATE edb_info SET start_date=?,end_date=?,min_value=?,max_value=?,is_update=2,latest_date=?,latest_value=?,end_value=?,modify_time=NOW() WHERE edb_info_id=? `
	_, err = o.Raw(sql, item.MinDate, item.MaxDate, item.MinValue, item.MaxValue, item.LatestDate, item.LatestValue, item.EndValue, edbInfoId).Exec()
	return
}

// ModifyCalculateEdbInfo 修改计算指标信息
func ModifyCalculateEdbInfo(edbName, frequency, unit, calculateFormula string, classifyId, edbInfoId int) (err error) {
	o := orm.NewOrm()
	sql := ` UPDATE  edb_info
			SET
			  edb_name =?,
			  edb_name_source =?,
			  frequency = ?,
			  unit = ?,
			  classify_id = ?,
			  calculate_formula=?,
			  modify_time = NOW()
			WHERE edb_info_id = ?`
	_, err = o.Raw(sql, edbName, edbName, frequency, unit, classifyId, calculateFormula, edbInfoId).Exec()
	return
}

func GetEdbInfoItemByCondition(condition string, pars []interface{}) (item *EdbInfoList, err error) {
	o := orm.NewOrm()
	sql := ` SELECT * FROM edb_info WHERE 1=1 `
	if condition != "" {
		sql += condition
	}
	err = o.Raw(sql, pars).QueryRow(&item)
	return
}

func GetEdbInfoItemListByCondition() (items []*EdbInfoList, err error) {
	o := orm.NewOrm()
	sql := ` SELECT * FROM edb_info WHERE 1=1 `
	_, err = o.Raw(sql).QueryRows(&items)
	return
}

// EdbInfoDetailReq 指标详情请求
type EdbInfoDetailReq struct {
	UniqueCode string `description:"指标唯一编码"`
	EdbCode    string `description:"指标编码"`
}

// EdbInfoDetailResp 指标详情返回
type EdbInfoDetailResp struct {
	SourceName    string `description:"来源名称"`
	EdbCode       string `description:"指标编码"`
	EdbName       string `description:"指标名称"`
	EdbNameSource string `description:"指标名称来源"`
	Frequency     string `description:"频率"`
	Unit          string `description:"单位"`
	StartDate     string `description:"起始日期"`
	EndDate       string `description:"终止日期"`
	UniqueCode    string `description:"指标唯一编码"`
	CreateTime    time.Time
	ModifyTime    time.Time
	MinValue      float64 `description:"指标最小值"`
	MaxValue      float64 `description:"指标最大值"`
	EdbNameEn     string  `description:"英文指标名称"`
	UnitEn        string  `description:"英文单位"`
	LatestDate    string  `description:"数据最新日期"`
	LatestValue   float64 `description:"数据最新值"`
	ChartImage    string  `description:"图表图片"`
	DataList      []*EdbInfoSearchData
}

type AddEdbInfoParams struct {
	Source       int    `description:"来源id"`
	EdbCode      string `description:"指标编码"`
	EdbName      string `description:"指标名称"`
	Frequency    string `description:"频率"`
	Unit         string `description:"单位"`
	ClassifyId   int    `description:"分类id"`
	TerminalCode string `description:"终端编码"`
	AdminId      int    `description:"创建人ID"`
	AdminName    string `description:"创建人姓名"`
}

// EdbInfoAdd 添加指标到指标库
func EdbInfoAdd(req *AddEdbInfoParams, serverUrl string, sysUserId int, sysUserRealName string) (edbInfo *EdbInfo, err error) {
	source := req.Source
	//判断指标名称是否存在
	var condition string
	var pars []interface{}
	//condition += " AND source=? "
	//pars = append(pars, source)

	condition += " AND edb_code=? "
	pars = append(pars, req.EdbCode)

	items, err := GetEdbInfoByCondition(condition, pars, 0)
	if err != nil {
		err = errors.New("判断指标是否存在失败,Err:" + err.Error())
		return
	}

	if len(items) > 0 {
		sql := ` UPDATE edb_info SET classify_id=?,modify_time=NOW() WHERE edb_code=? `
		o := orm.NewOrm()
		_, err = o.Raw(sql, req.ClassifyId, req.EdbCode).Exec()
		if err != nil {
			err = errors.New("更新指标分类信息失败,Err:" + err.Error())
			return
		}
		edbInfo = items[0]
		return
	}

	edbInfo = new(EdbInfo)
	edbInfo.Source = source
	sourceNameMap := map[int]string{
		utils.DATA_SOURCE_THS:                 "同花顺",
		utils.DATA_SOURCE_WIND:                "wind",
		utils.DATA_SOURCE_PB:                  "彭博",
		utils.DATA_SOURCE_PB_FINANCE:          "彭博财务",
		utils.DATA_SOURCE_MANUAL:              "手工数据",
		utils.DATA_SOURCE_LZ:                  "隆众",
		utils.DATA_SOURCE_YS:                  "SMM",
		utils.DATA_SOURCE_GL:                  "钢联",
		utils.DATA_SOURCE_ZZ:                  "郑商所",
		utils.DATA_SOURCE_DL:                  "大商所",
		utils.DATA_SOURCE_SH:                  "上期所",
		utils.DATA_SOURCE_CFFEX:               "中金所",
		utils.DATA_SOURCE_SHFE:                "上期能源",
		utils.DATA_SOURCE_GIE:                 "欧洲天然气",
		utils.DATA_SOURCE_LT:                  "路透",
		utils.DATA_SOURCE_COAL:                "中国煤炭市场网",
		utils.DATA_SOURCE_GOOGLE_TRAVEL:       "our world in data",
		utils.DATA_SOURCE_MYSTEEL_CHEMICAL:    "钢联化工",
		utils.DATA_SOURCE_EIA_STEO:            "EIA STEO报告",
		utils.DATA_SOURCE_COM_TRADE:           "UN",
		utils.DATA_SOURCE_SCI:                 "SCI",
		utils.DATA_SOURCE_BAIINFO:             "BAIINFO",
		utils.DATA_SOURCE_STOCK_PLANT:         "存量装置",
		utils.DATA_SOURCE_NATIONAL_STATISTICS: "国家统计局",
		utils.DATA_SOURCE_FUBAO:               "富宝数据",
	}

	sourceName, ok := sourceNameMap[source]
	if !ok {
		edbSource := EdbSourceIdMap[source]
		if edbSource != nil {
			sourceName = edbSource.SourceName
		}
		if sourceName == "" {
			err = errors.New("指标来源异常")
			return
		}
	}
	edbInfo.SourceName = sourceName

	edbType := 1 //基础指标
	if source == utils.DATA_SOURCE_STOCK_PLANT {
		edbType = 2 //计算指标
	}

	var sourceIndexName string

	// 钢联化工需要校验下信息是否完整
	if source == utils.DATA_SOURCE_MYSTEEL_CHEMICAL {
		indexObj := new(BaseFromMysteelChemicalIndex)
		tmpItem, tmpErr := indexObj.GetIndexItem(req.EdbCode)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		if tmpItem == nil || tmpItem.IndexName == `` {
			err = errors.New("指标信息不全")
			return
		}
	}
	//获取该层级下最大的排序数
	maxSort, err := GetEdbAndClassifyMaxSort(req.ClassifyId, 0)
	if err != nil {
		err = errors.New("查询排序信息失败，Err:" + err.Error())
		return
	}

	edbInfo.EdbCode = req.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.StartDate = "1990-01-01"
	edbInfo.CreateTime = time.Now()
	edbInfo.ModifyTime = time.Now()
	edbInfo.ServerUrl = serverUrl
	edbInfo.TerminalCode = req.TerminalCode
	edbInfo.Sort = maxSort + 1
	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
	edbInfo.UniqueCode = utils.MD5(utils.DATA_PREFIX + "_" + req.EdbCode + timestamp)
	itemVal, err := GetEdbInfoMaxAndMinInfo(source, utils.DATA_SUB_SOURCE_EDB, req.EdbCode)
	if itemVal != nil && err == nil {
		edbInfo.MaxValue = itemVal.MaxValue
		edbInfo.MinValue = itemVal.MinValue
	}
	edbInfo.EdbType = edbType
	edbInfo.SourceIndexName = sourceIndexName
	edbInfoId, err := AddEdbInfo(edbInfo)
	if err != nil {
		err = errors.New("保存失败，Err:" + err.Error())
		return
	}
	edbInfo.EdbInfoId = int(edbInfoId)
	return
}

// EdbInfoRefreshCheckReq 指标数据更新情况查询
type EdbInfoRefreshCheckReq struct {
	Source         int    `description:"来源id"`
	LatestDate     string `description:"数据最新日期"`
	FrequencyBatch string `description:"更新频度"`
}

// EdbInfoRefreshCheckResp 指标数据更新情况查询
type EdbInfoRefreshCheckResp struct {
	UpdateNum   int `description:"已更新指标数"`
	UnUpdateNum int `description:"未更新指标数"`
}

// ResetEdbClassifyReq 指标重新分类请求体
type ResetEdbClassifyReq struct {
	IndexCode      string `description:"指标编码"`
	ClassifyFirst  string `description:"一级分类名称"`
	ClassifySecond string `description:"二级分类名称"`
	ClassifyThird  string `description:"三级分类名称"`
}

// GetEdbInfoMaxSortByClassifyId 获取分类下指标的最大的排序数
func GetEdbInfoMaxSortByClassifyId(classifyId int) (sort int, err error) {
	o := orm.NewOrm()
	sql := `SELECT Max(sort) AS sort FROM edb_info WHERE classify_id=? `
	err = o.Raw(sql, classifyId).QueryRow(&sort)
	return
}

func GetEdbAndClassifyMaxSort(parentId int, classifyType uint8) (maxSort int, err error) {
	//获取该层级下最大的排序数
	classifyMaxSort, err := GetEdbClassifyMaxSort(parentId, classifyType)
	if err != nil {
		return
	}
	maxSort = classifyMaxSort
	edbMaxSort, err := GetEdbInfoMaxSortByClassifyId(parentId)
	if err != nil {
		return
	}
	if maxSort < edbMaxSort {
		maxSort = edbMaxSort
	}
	return
}

// CalculateEdbExtra 指标运算额外配置
type CalculateEdbExtra struct {
	DateTag string `description:"时间序列的生成方式，all 表示所选指标的时间序列并集"`
}

// CalculateLjzEdbExtra 累计值额外配置
type CalculateLjzEdbExtra struct {
	LastValType int `description:"最新值处理：0默认、均值填充"`
}

// GetEdbInfoByEdbCodeList
// @Description: 根据来源和指标编码列表获取指标信息列表
// @author: Roc
// @datetime 2024-05-31 16:31:52
// @param source int
// @param edbCodeList []string
// @return items []*EdbInfo
// @return err error
func GetEdbInfoByEdbCodeList(source int, edbCodeList []string) (items []*EdbInfo, err error) {
	num := len(edbCodeList)
	if num <= 0 {
		return
	}
	o := orm.NewOrm()
	sql := ` SELECT * FROM edb_info WHERE source=? AND edb_code IN (` + utils.GetOrmInReplace(num) + `) `
	_, err = o.Raw(sql, source, edbCodeList).QueryRows(&items)

	return
}
