package data_manage

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

const (
	FactorEdbSeriesCalculateNone = 0
	FactorEdbSeriesCalculating   = 1
	FactorEdbSeriesCalculated    = 2
)

// FactorEdbSeries 因子指标系列表
type FactorEdbSeries struct {
	FactorEdbSeriesId int       `orm:"column(factor_edb_series_id);pk"`
	SeriesName        string    `description:"系列名称"`
	EdbInfoType       int       `description:"关联指标类型:0-普通指标;1-预测指标"`
	CalculateStep     string    `description:"计算步骤-JSON"`
	CalculateState    int       `description:"计算状态: 0-无计算; 1-计算中; 2-计算完成"`
	CreateTime        time.Time `description:"创建时间"`
	ModifyTime        time.Time `description:"修改时间"`
}

func (m *FactorEdbSeries) TableName() string {
	return "factor_edb_series"
}

type FactorEdbSeriesCols struct {
	PrimaryId      string
	SeriesName     string
	EdbInfoType    string
	CalculateStep  string
	CalculateState string
	CreateTime     string
	ModifyTime     string
}

func (m *FactorEdbSeries) Cols() FactorEdbSeriesCols {
	return FactorEdbSeriesCols{
		PrimaryId:      "factor_edb_series_id",
		SeriesName:     "series_name",
		EdbInfoType:    "edb_info_type",
		CalculateStep:  "calculate_step",
		CalculateState: "calculate_state",
		CreateTime:     "create_time",
		ModifyTime:     "modify_time",
	}
}

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

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

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

func (m *FactorEdbSeries) 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.FactorEdbSeriesId).Exec()
	return
}

func (m *FactorEdbSeries) 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 *FactorEdbSeries) 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 *FactorEdbSeries) GetItemById(id int) (item *FactorEdbSeries, 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 *FactorEdbSeries) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *FactorEdbSeries, 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 *FactorEdbSeries) 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 *FactorEdbSeries) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*FactorEdbSeries, 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 *FactorEdbSeries) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*FactorEdbSeries, 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
}

// FactorEdbSeriesItem 多因子系列信息
type FactorEdbSeriesItem struct {
	SeriesId      int                            `description:"多因子系列ID"`
	SeriesName    string                         `description:"系列名称"`
	EdbInfoType   int                            `description:"关联指标类型:0-普通指标;1-预测指标"`
	CalculateStep []FactorEdbSeriesCalculatePars `description:"计算步骤-JSON"`
	CreateTime    string                         `description:"创建时间"`
	ModifyTime    string                         `description:"修改时间"`
}

func (m *FactorEdbSeries) Format2Item() (item *FactorEdbSeriesItem) {
	item = new(FactorEdbSeriesItem)
	item.SeriesId = m.FactorEdbSeriesId
	item.SeriesName = m.SeriesName
	item.EdbInfoType = m.EdbInfoType
	if m.CalculateStep != "" {
		_ = json.Unmarshal([]byte(m.CalculateStep), &item.CalculateStep)
	}
	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, m.CreateTime)
	item.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, m.ModifyTime)
	return
}

// FactorEdbSeriesCalculatePars 计算参数
type FactorEdbSeriesCalculatePars struct {
	Formula       interface{} `description:"N值/移动天数/指数修匀alpha值/计算公式等"`
	Calendar      string      `description:"公历/农历"`
	Frequency     string      `description:"需要转换的频度"`
	MoveType      int         `description:"移动方式: 1-领先(默认); 2-滞后"`
	MoveFrequency string      `description:"移动频度"`
	FromFrequency string      `description:"来源的频度"`
	Source        int         `description:"计算方式来源(不是指标来源)"`
	Sort          int         `description:"计算顺序"`
}

// CreateSeriesAndMapping 新增系列和指标关联
func (m *FactorEdbSeries) CreateSeriesAndMapping(item *FactorEdbSeries, mappings []*FactorEdbSeriesMapping) (seriesId int, err error) {
	if item == nil {
		err = fmt.Errorf("series is nil")
		return
	}
	o := orm.NewOrmUsingDB("data")
	tx, e := o.Begin()
	if e != nil {
		err = fmt.Errorf("orm begin err: %v", e)
		return
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
			return
		}
		_ = tx.Commit()
	}()

	id, e := tx.Insert(item)
	if e != nil {
		err = fmt.Errorf("insert series err: %v", e)
		return
	}
	seriesId = int(id)
	item.FactorEdbSeriesId = seriesId

	if len(mappings) > 0 {
		for _, v := range mappings {
			v.FactorEdbSeriesId = seriesId
		}
		_, e = tx.InsertMulti(200, mappings)
		if e != nil {
			err = fmt.Errorf("insert multi mapping err: %v", e)
			return
		}
	}
	return
}

// EditSeriesAndMapping 编辑系列和指标关联
func (m *FactorEdbSeries) EditSeriesAndMapping(item *FactorEdbSeries, mappings []*FactorEdbSeriesMapping, updateCols []string) (err error) {
	if item == nil {
		err = fmt.Errorf("series is nil")
		return
	}
	o := orm.NewOrmUsingDB("data")
	tx, e := o.Begin()
	if e != nil {
		err = fmt.Errorf("orm begin err: %v", e)
		return
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
			return
		}
		_ = tx.Commit()
	}()

	_, e = tx.Update(item, updateCols...)
	if e != nil {
		err = fmt.Errorf("update series err: %v", e)
		return
	}

	// 清除原指标关联
	mappingOb := new(FactorEdbSeriesMapping)
	cond := fmt.Sprintf("%s = ?", mappingOb.Cols().FactorEdbSeriesId)
	pars := make([]interface{}, 0)
	pars = append(pars, item.FactorEdbSeriesId)
	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s`, mappingOb.TableName(), cond)
	_, e = tx.Raw(sql, pars).Exec()
	if e != nil {
		err = fmt.Errorf("remove mapping err: %v", e)
		return
	}

	if len(mappings) > 0 {
		for _, v := range mappings {
			v.FactorEdbSeriesId = item.FactorEdbSeriesId
		}
		_, e = tx.InsertMulti(200, mappings)
		if e != nil {
			err = fmt.Errorf("insert multi mapping err: %v", e)
			return
		}
	}
	return
}

// FactorEdbSeriesStepCalculateResp 批量计算响应
type FactorEdbSeriesStepCalculateResp struct {
	SeriesId int                                  `description:"多因子指标系列ID"`
	Fail     []FactorEdbSeriesStepCalculateResult `description:"计算失败的指标"`
	Success  []FactorEdbSeriesStepCalculateResult `description:"计算成功的指标"`
}

// FactorEdbSeriesStepCalculateResult 批量计算结果
type FactorEdbSeriesStepCalculateResult struct {
	EdbInfoId int    `description:"指标ID"`
	EdbCode   string `description:"指标编码"`
	Msg       string `description:"提示信息"`
	ErrMsg    string `description:"错误信息"`
}

// FactorEdbSeriesDetail 因子指标系列-详情
type FactorEdbSeriesDetail struct {
	*FactorEdbSeriesItem
	EdbMappings []*FactorEdbSeriesMappingItem
}

// FactorEdbSeriesCorrelationMatrixResp 因子指标系列-相关性矩阵响应
type FactorEdbSeriesCorrelationMatrixResp struct {
	Fail    []FactorEdbSeriesCorrelationMatrixItem `description:"计算失败的指标"`
	Success []FactorEdbSeriesCorrelationMatrixItem `description:"计算成功的指标"`
}

// FactorEdbSeriesCorrelationMatrixItem 因子指标系列-相关性矩阵信息
type FactorEdbSeriesCorrelationMatrixItem struct {
	SeriesId     int                                      `description:"因子指标系列ID"`
	EdbInfoId    int                                      `description:"指标ID"`
	EdbCode      string                                   `description:"指标编码"`
	EdbName      string                                   `description:"指标名称"`
	Values       []FactorEdbSeriesCorrelationMatrixValues `description:"X轴和Y轴数据"`
	Msg          string                                   `description:"提示信息"`
	ErrMsg       string                                   `description:"错误信息"`
	Used         bool                                     `description:"是否选中"`
	SourceName   string                                   `description:"指标来源名称"`
	SourceNameEn string                                   `description:"英文指标来源名称"`
}

// FactorEdbSeriesCorrelationMatrixValues 因子指标系列-相关性矩阵XY值
type FactorEdbSeriesCorrelationMatrixValues struct {
	XData int     `description:"X轴数据"`
	YData float64 `description:"Y轴数据"`
}

// FactorEdbSeriesCorrelationMatrixOrder 排序规则[0 1 2 3 -1 -2 -3]
type FactorEdbSeriesCorrelationMatrixOrder []FactorEdbSeriesCorrelationMatrixValues

func (a FactorEdbSeriesCorrelationMatrixOrder) Len() int {
	return len(a)
}

func (a FactorEdbSeriesCorrelationMatrixOrder) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a FactorEdbSeriesCorrelationMatrixOrder) Less(i, j int) bool {
	// 非负数优先
	if a[i].XData >= 0 && a[j].XData < 0 {
		return true
	}
	if a[i].XData < 0 && a[j].XData >= 0 {
		return false
	}
	// 非负数升序排序
	if a[i].XData >= 0 {
		return a[i].XData < a[j].XData
	}
	// 负数按绝对值的降序排序(即数值的升序)
	return a[i].XData > a[j].XData
}

// RemoveSeriesAndMappingByFactorEdbSeriesId 删除系列和指标关联
func (m *FactorEdbSeries) RemoveSeriesAndMappingByFactorEdbSeriesId(factorEdbSeriesChartMapping *FactorEdbSeriesChartMapping) (err error) {
	o := orm.NewOrmUsingDB("data")
	tx, e := o.Begin()
	if e != nil {
		err = fmt.Errorf("orm begin err: %v", e)
		return
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
			return
		}
		_ = tx.Commit()
	}()
	factorEdbSeriesId := factorEdbSeriesChartMapping.FactorEdbSeriesId
	err = factorEdbSeriesChartMapping.Remove()
	if err != nil {
		err = fmt.Errorf("factorEdbSeriesChartMapping.delete err: %v", err)
		return
	}
	if factorEdbSeriesId == 0 {
		return
	}

	// 清除原指标关联
	seriesOb := new(FactorEdbSeries)
	cond := fmt.Sprintf("%s = ?", seriesOb.Cols().PrimaryId)
	pars := make([]interface{}, 0)
	pars = append(pars, factorEdbSeriesId)
	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s`, seriesOb.TableName(), cond)
	_, e = tx.Raw(sql, pars).Exec()
	if e != nil {
		err = fmt.Errorf("remove FactorEdbSeries err: %v", e)
		return
	}

	// 清除原指标关联
	mappingOb := new(FactorEdbSeriesMapping)
	cond1 := fmt.Sprintf("%s = ?", mappingOb.Cols().FactorEdbSeriesId)
	pars1 := make([]interface{}, 0)
	pars1 = append(pars1, factorEdbSeriesId)
	sql = fmt.Sprintf(`DELETE FROM %s WHERE %s`, mappingOb.TableName(), cond1)
	_, e = tx.Raw(sql, pars1).Exec()
	if e != nil {
		err = fmt.Errorf("remove mapping err: %v", e)
		return
	}
	dataOb := new(FactorEdbSeriesCalculateDataQjjs)
	//删除原指标数据
	cond2 := fmt.Sprintf("%s = ?", dataOb.Cols().FactorEdbSeriesId)
	pars2 := make([]interface{}, 0)
	pars2 = append(pars2, factorEdbSeriesId)
	sql = fmt.Sprintf(`DELETE FROM %s WHERE %s`, dataOb.TableName(), cond2)
	_, e = tx.Raw(sql, pars2).Exec()
	if e != nil {
		err = fmt.Errorf("remove mapping err: %v", e)
		return
	}
	return
}

// CalculateCorrelationMatrixPars 计算相关性矩阵参数
type CalculateCorrelationMatrixPars struct {
	BaseEdbInfoId int               `description:"标的指标ID"`
	SeriesIds     []int             `description:"系列IDs"`
	Correlation   CorrelationConfig `description:"相关性配置"`
}