package data_manage

import (
	"database/sql"
	"eta/eta_api/utils"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"strings"
	"time"
)

const (
	ModelDataSourceMonthly = 1 // 月度预测数据
	ModelDataSourceDaily   = 2 // 日度预测数据
)

// AiPredictModelData AI预测模型标的数据
type AiPredictModelData struct {
	AiPredictModelDataId  int             `orm:"column(ai_predict_model_data_id);pk"`
	AiPredictModelIndexId int             `description:"标的ID"`
	IndexCode             string          `description:"标的编码"`
	DataTime              time.Time       `description:"数据日期"`
	Value                 sql.NullFloat64 `description:"实际值"`
	PredictValue          sql.NullFloat64 `description:"预测值"`
	Direction             string          `description:"方向"`
	DeviationRate         string          `description:"偏差率"`
	CreateTime            time.Time       `description:"创建时间"`
	ModifyTime            time.Time       `description:"修改时间"`
	DataTimestamp         int64           `description:"数据日期时间戳"`
	Source                int             `description:"来源:1-月度预测(默认);2-日度预测"`
}

func (m *AiPredictModelData) TableName() string {
	return "ai_predict_model_data"
}

type AiPredictModelDataCols struct {
	PrimaryId             string
	AiPredictModelIndexId string
	IndexCode             string
	DataTime              string
	Value                 string
	PredictValue          string
	Direction             string
	DeviationRate         string
	CreateTime            string
	ModifyTime            string
	DataTimestamp         string
	Source                string
}

func (m *AiPredictModelData) Cols() AiPredictModelDataCols {
	return AiPredictModelDataCols{
		PrimaryId:             "ai_predict_model_data_id",
		AiPredictModelIndexId: "ai_predict_model_index_id",
		IndexCode:             "index_code",
		DataTime:              "data_time",
		Value:                 "value",
		PredictValue:          "predict_value",
		Direction:             "direction",
		DeviationRate:         "deviation_rate",
		CreateTime:            "create_time",
		ModifyTime:            "modify_time",
		DataTimestamp:         "data_timestamp",
		Source:                "source",
	}
}

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

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

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

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

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

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

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

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

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

func (m *AiPredictModelData) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*AiPredictModelData, 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
	}
	sqlRun := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
	_, err = o.Raw(sqlRun, pars).QueryRows(&items)
	return
}

func (m *AiPredictModelData) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*AiPredictModelData, 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
	}
	sqlRun := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
	_, err = o.Raw(sqlRun, pars, startSize, pageSize).QueryRows(&items)
	return
}

// AiPredictModelDataItem AI预测模型标的数据
type AiPredictModelDataItem struct {
	DataId        int      `description:"ID"`
	IndexId       int      `description:"标的ID"`
	IndexCode     string   `description:"标的编码"`
	DataTime      string   `description:"数据日期"`
	Value         *float64 `description:"实际值"`
	PredictValue  *float64 `description:"预测值"`
	Direction     string   `description:"方向"`
	DeviationRate string   `description:"偏差率"`
	DataTimestamp int64    `description:"数据日期时间戳"`
}

func (m *AiPredictModelData) Format2Item() (item *AiPredictModelDataItem) {
	item = new(AiPredictModelDataItem)
	item.DataId = m.AiPredictModelDataId
	item.IndexId = m.AiPredictModelIndexId
	item.IndexCode = m.IndexCode
	item.DataTime = utils.TimeTransferString(utils.FormatDate, m.DataTime)
	if m.Value.Valid {
		item.Value = &m.Value.Float64
	}
	if m.PredictValue.Valid {
		item.PredictValue = &m.PredictValue.Float64
	}
	item.Direction = m.Direction
	item.DeviationRate = m.DeviationRate
	item.DataTimestamp = m.DataTimestamp
	return
}