package data_manage

import (
	"eta/eta_api/models/data_manage"
	"eta/eta_api/utils"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/rdlucklib/rdluck_tools/paging"
	"strings"
	"time"
)

// AiPredictModelIndex AI预测模型标的
type AiPredictModelIndex struct {
	AiPredictModelIndexId int       `orm:"column(ai_predict_model_index_id);pk"`
	IndexName             string    `description:"标的名称"`
	IndexCode             string    `description:"自生成的指标编码"`
	ClassifyId            int       `description:"分类ID"`
	ModelFramework        string    `description:"模型框架"`
	PredictDate           time.Time `description:"预测日期"`
	PredictValue          float64   `description:"预测值"`
	PredictFrequency      string    `description:"预测频度"`
	DirectionAccuracy     string    `description:"方向准确度"`
	AbsoluteDeviation     string    `description:"绝对偏差"`
	ExtraConfig           string    `description:"模型参数"`
	Sort                  int       `description:"排序"`
	SysUserId             int       `description:"创建人ID"`
	SysUserRealName       string    `description:"创建人姓名"`
	LeftMin               string    `description:"图表左侧最小值"`
	LeftMax               string    `description:"图表左侧最大值"`
	CreateTime            time.Time `description:"创建时间"`
	ModifyTime            time.Time `description:"修改时间"`
}

func (m *AiPredictModelIndex) TableName() string {
	return "ai_predict_model_index"
}

type AiPredictModelIndexCols struct {
	PrimaryId         string
	IndexName         string
	IndexCode         string
	ClassifyId        string
	ModelFramework    string
	PredictDate       string
	PredictValue      string
	DirectionAccuracy string
	AbsoluteDeviation string
	ExtraConfig       string
	Sort              string
	SysUserId         string
	SysUserRealName   string
	LeftMin           string
	LeftMax           string
	CreateTime        string
	ModifyTime        string
}

func (m *AiPredictModelIndex) Cols() AiPredictModelIndexCols {
	return AiPredictModelIndexCols{
		PrimaryId:         "ai_predict_model_index_id",
		IndexName:         "index_name",
		IndexCode:         "index_code",
		ClassifyId:        "classify_id",
		ModelFramework:    "model_framework",
		PredictDate:       "predict_date",
		PredictValue:      "predict_value",
		DirectionAccuracy: "direction_accuracy",
		AbsoluteDeviation: "absolute_deviation",
		ExtraConfig:       "extra_config",
		Sort:              "sort",
		SysUserId:         "sys_user_id",
		SysUserRealName:   "sys_user_real_name",
		LeftMin:           "left_min",
		LeftMax:           "left_max",
		CreateTime:        "create_time",
		ModifyTime:        "modify_time",
	}
}

func (m *AiPredictModelIndex) Create() (err error) {
	o := orm.NewOrmUsingDB("data")
	id, err := o.Insert(m)
	if err != nil {
		return
	}
	m.AiPredictModelIndexId = int(id)
	return
}

func (m *AiPredictModelIndex) CreateMulti(items []*AiPredictModelIndex) (err error) {
	if len(items) == 0 {
		return
	}
	o := orm.NewOrmUsingDB("data")
	_, err = o.InsertMulti(len(items), items)
	return
}

func (m *AiPredictModelIndex) Update(cols []string) (err error) {
	o := orm.NewOrmUsingDB("data")
	_, err = o.Update(m, cols...)
	return
}

func (m *AiPredictModelIndex) Remove() (err error) {
	o := orm.NewOrmUsingDB("data")
	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
	_, err = o.Raw(sql, m.AiPredictModelIndexId).Exec()
	return
}

func (m *AiPredictModelIndex) MultiRemove(ids []int) (err error) {
	if len(ids) == 0 {
		return
	}
	o := orm.NewOrmUsingDB("data")
	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.Cols().PrimaryId, utils.GetOrmInReplace(len(ids)))
	_, err = o.Raw(sql, ids).Exec()
	return
}

func (m *AiPredictModelIndex) RemoveByCondition(condition string, pars []interface{}) (err error) {
	if condition == "" {
		return
	}
	o := orm.NewOrmUsingDB("data")
	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s`, m.TableName(), condition)
	_, err = o.Raw(sql, pars).Exec()
	return
}

func (m *AiPredictModelIndex) GetItemById(id int) (item *AiPredictModelIndex, err error) {
	o := orm.NewOrmUsingDB("data")
	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
	err = o.Raw(sql, id).QueryRow(&item)
	return
}

func (m *AiPredictModelIndex) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *AiPredictModelIndex, err error) {
	o := orm.NewOrmUsingDB("data")
	order := ``
	if orderRule != "" {
		order = ` ORDER BY ` + orderRule
	}
	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
	err = o.Raw(sql, pars).QueryRow(&item)
	return
}

func (m *AiPredictModelIndex) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
	o := orm.NewOrmUsingDB("data")
	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
	err = o.Raw(sql, pars).QueryRow(&count)
	return
}

func (m *AiPredictModelIndex) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*AiPredictModelIndex, err error) {
	o := orm.NewOrmUsingDB("data")
	fields := strings.Join(fieldArr, ",")
	if len(fieldArr) == 0 {
		fields = `*`
	}
	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
	if orderRule != "" {
		order = ` ORDER BY ` + orderRule
	}
	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
	_, err = o.Raw(sql, pars).QueryRows(&items)
	return
}

func (m *AiPredictModelIndex) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*AiPredictModelIndex, err error) {
	o := orm.NewOrmUsingDB("data")
	fields := strings.Join(fieldArr, ",")
	if len(fieldArr) == 0 {
		fields = `*`
	}
	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
	if orderRule != "" {
		order = ` ORDER BY ` + orderRule
	}
	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
	return
}

// AiPredictModelIndexItem AI预测模型标的信息
type AiPredictModelIndexItem struct {
	IndexId           int     `description:"标的ID"`
	IndexName         string  `description:"标的名称"`
	IndexCode         string  `description:"自生成的指标编码"`
	ClassifyId        int     `description:"分类ID"`
	ClassifyName      string  `description:"分类名称"`
	ModelFramework    string  `description:"模型框架"`
	PredictDate       string  `description:"预测日期"`
	PredictValue      float64 `description:"预测值"`
	PredictFrequency  string  `description:"预测频度"`
	DirectionAccuracy string  `description:"方向准确度"`
	AbsoluteDeviation string  `description:"绝对偏差"`
	ExtraConfig       string  `description:"模型参数"`
	SysUserId         int     `description:"创建人ID"`
	SysUserRealName   string  `description:"创建人姓名"`
	CreateTime        string  `description:"创建时间"`
	ModifyTime        string  `description:"修改时间"`
}

func (m *AiPredictModelIndex) Format2Item() (item *AiPredictModelIndexItem) {
	item = new(AiPredictModelIndexItem)
	item.IndexId = m.AiPredictModelIndexId
	item.IndexName = m.IndexName
	item.IndexCode = m.IndexCode
	item.ClassifyId = m.ClassifyId
	item.ModelFramework = m.ModelFramework
	item.PredictDate = utils.TimeTransferString(utils.FormatDate, m.PredictDate)
	item.PredictValue = m.PredictValue
	item.PredictFrequency = m.PredictFrequency
	item.DirectionAccuracy = m.DirectionAccuracy
	item.AbsoluteDeviation = m.AbsoluteDeviation
	item.ExtraConfig = m.ExtraConfig
	item.SysUserId = m.SysUserId
	item.SysUserRealName = m.SysUserRealName
	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, m.CreateTime)
	item.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, m.ModifyTime)
	return
}

type AiPredictModelIndexPageListResp struct {
	Paging *paging.PagingItem
	List   []*AiPredictModelIndexItem `description:"列表"`
}

// RemoveIndexAndData 删除标的及数据
func (m *AiPredictModelIndex) RemoveIndexAndData(indexId int) (err error) {
	o := orm.NewOrmUsingDB("data")
	tx, e := o.Begin()
	if e != nil {
		err = fmt.Errorf("trans begin err: %v", e)
		return
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
			return
		}
		_ = tx.Commit()
	}()

	sql := `DELETE FROM ai_predict_model_index WHERE ai_predict_model_index_id = ? LIMIT 1`
	_, e = tx.Raw(sql, indexId).Exec()
	if e != nil {
		err = fmt.Errorf("remove index err: %v", e)
		return
	}
	sql = ` DELETE FROM ai_predict_model_data WHERE ai_predict_model_index_id = ?`
	_, e = tx.Raw(sql, indexId).Exec()
	if e != nil {
		err = fmt.Errorf("remove index data err: %v", e)
		return
	}
	return
}

// UpdateAiPredictModelIndexSortByClassifyId 根据分类id更新排序
func UpdateAiPredictModelIndexSortByClassifyId(classifyId, nowSort int, prevEdbInfoId int, updateSort string) (err error) {
	o := orm.NewOrmUsingDB("data")
	sql := ` UPDATE ai_predict_model_index SET sort = ` + updateSort + ` WHERE classify_id = ?`
	if prevEdbInfoId > 0 {
		sql += ` AND ( sort > ? or ( ai_predict_model_index_id > ` + fmt.Sprint(prevEdbInfoId) + ` and sort=` + fmt.Sprint(nowSort) + ` )) `
	} else {
		sql += ` AND ( sort > ? )`
	}
	_, err = o.Raw(sql, classifyId, nowSort).Exec()
	return
}

// GetFirstAiPredictModelIndexByClassifyId 获取当前分类下,且排序数相同 的排序第一条的数据
func GetFirstAiPredictModelIndexByClassifyId(classifyId int) (item *AiPredictModelIndex, err error) {
	o := orm.NewOrmUsingDB("data")
	sql := ` SELECT * FROM ai_predict_model_index WHERE classify_id = ? order by sort asc,ai_predict_model_index_id asc limit 1`
	err = o.Raw(sql, classifyId).QueryRow(&item)
	return
}

type AiPredictModelImportData struct {
	Index *AiPredictModelIndex
	Data  []*AiPredictModelData
}

// ImportIndexAndData 导入数据
func (m *AiPredictModelIndex) ImportIndexAndData(createIndexes, updateIndexes []*AiPredictModelImportData, updateCols []string) (err error) {
	if len(createIndexes) == 0 && len(updateIndexes) == 0 {
		return
	}
	o := orm.NewOrmUsingDB("data")
	tx, e := o.Begin()
	if e != nil {
		err = fmt.Errorf("trans begin err: %v", e)
		return
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
			return
		}
		_ = tx.Commit()
	}()

	if len(updateIndexes) > 0 {
		for _, v := range updateIndexes {
			// 更新指标
			_, e = tx.Update(v.Index, updateCols...)
			if e != nil {
				err = fmt.Errorf("update index err: %v", e)
				return
			}
			for _, d := range v.Data {
				d.AiPredictModelIndexId = v.Index.AiPredictModelIndexId
				d.IndexCode = v.Index.IndexCode
				d.DataTimestamp = d.DataTime.UnixNano() / 1e6
			}

			// 清空指标并新增
			sql := `DELETE FROM ai_predict_model_data WHERE ai_predict_model_index_id = ?`
			_, e = tx.Raw(sql, v.Index.AiPredictModelIndexId).Exec()
			if e != nil {
				err = fmt.Errorf("clear index data err: %v", e)
				return
			}
			_, e = tx.InsertMulti(utils.MultiAddNum, v.Data)
			if e != nil {
				err = fmt.Errorf("insert index data err: %v", e)
				return
			}
		}
	}

	if len(createIndexes) > 0 {
		for _, v := range createIndexes {
			indexId, e := tx.Insert(v.Index)
			if e != nil {
				err = fmt.Errorf("insert index err: %v", e)
				return
			}
			for _, d := range v.Data {
				d.AiPredictModelIndexId = int(indexId)
				d.IndexCode = v.Index.IndexCode
				d.DataTimestamp = d.DataTime.UnixNano() / 1e6
			}
			_, e = tx.InsertMulti(utils.MultiAddNum, v.Data)
			if e != nil {
				err = fmt.Errorf("insert index data err: %v", e)
				return
			}
		}
	}
	return
}

type AiPredictModelDetailResp struct {
	TableData      []*AiPredictModelDataItem        `description:"表格数据"`
	ChartView      *data_manage.ChartInfoDetailResp `description:"月度预测数据图表"`
	DailyChartView *data_manage.ChartInfoDetailResp `description:"日度预测数据图表"`
}

type AiPredictModelIndexSaveReq struct {
	IndexId      int                           `description:"指标ID"`
	MonthlyChart *AiPredictModelIndexSaveChart `description:"月度图表信息"`
	DailyChart   *AiPredictModelIndexSaveChart `description:"日度图表信息"`
}

type AiPredictModelIndexSaveChart struct {
	LeftMin string `description:"图表左侧最小值"`
	LeftMax string `description:"图表左侧最大值"`
	Unit    string `description:"单位"`
}

type AiPredictModelIndexExtraConfig struct {
	MonthlyChart struct {
		LeftMin string `description:"图表左侧最小值"`
		LeftMax string `description:"图表左侧最大值"`
		Unit    string `description:"单位"`
	}
	DailyChart struct {
		LeftMin           string `description:"图表左侧最小值"`
		LeftMax           string `description:"图表左侧最大值"`
		Unit              string `description:"单位"`
		PredictLegendName string `description:"预测图例的名称(通常为Predicted)"`
	}
}