package data_manage

import (
	"eta/eta_task/utils"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"time"
	"unsafe"
)

// 持仓榜单表
type TradePositionTop struct {
	Id            uint64    `orm:"column(id);pk"`
	ClassifyName  string    //分类名称
	ClassifyType  string    //分类名称下的类型
	DataTime      string    //数据日期
	CreateTime    time.Time //插入时间
	ModifyTime    time.Time //修改时间
	DealShortName string    //成交量公司简称
	DealValue     int       //成交量
	DealChange    int       //成交变化量
	DealType      int       //交易类型:1多单,2空单,3净多单,4净空单
	SourceType    int       //数据来源,0是原始数据的值,1是由T+1日推算出的值,2是由T日的榜单数据推算出的值
	Rank          int       //排名
}

type TradePositionDalianTop struct {
	TradePositionTop
}

type TradePositionZhengzhouTop struct {
	TradePositionTop
}

type TradePositionCffexTop struct {
	TradePositionTop
}

type TradePositionShanghaiTop struct {
	TradePositionTop
}

type TradePositionIneTop struct {
	TradePositionTop
}

type TradePositionGuangzhouTop struct {
	TradePositionTop
}

func InsertMultiTradePositionTop(exchange string, items []*TradePositionTop) (err error) {
	o := orm.NewOrm()
	if exchange == "dalian" {
		list := make([]*TradePositionDalianTop, 0)
		for _, v := range items {
			tmp := (*TradePositionDalianTop)(unsafe.Pointer(v))
			list = append(list, tmp)
		}
		_, err = o.InsertMulti(len(list), list)
		return
	} else if exchange == "zhengzhou" {
		list := make([]*TradePositionZhengzhouTop, 0)
		for _, v := range items {
			tmp := (*TradePositionZhengzhouTop)(unsafe.Pointer(v))
			list = append(list, tmp)
		}
		_, err = o.InsertMulti(len(list), list)
		return
	} else if exchange == "cffex" {
		list := make([]*TradePositionCffexTop, 0)
		for _, v := range items {
			tmp := (*TradePositionCffexTop)(unsafe.Pointer(v))
			list = append(list, tmp)
		}
		_, err = o.InsertMulti(len(list), list)
		return
	} else if exchange == "shanghai" {
		list := make([]*TradePositionShanghaiTop, 0)
		for _, v := range items {
			tmp := (*TradePositionShanghaiTop)(unsafe.Pointer(v))
			list = append(list, tmp)
		}
		_, err = o.InsertMulti(len(list), list)
		return
	} else if exchange == "ine" {
		list := make([]*TradePositionIneTop, 0)
		for _, v := range items {
			tmp := (*TradePositionIneTop)(unsafe.Pointer(v))
			list = append(list, tmp)
		}
		_, err = o.InsertMulti(len(list), list)
		return
	} else if exchange == "guangzhou" {
		list := make([]*TradePositionGuangzhouTop, 0)
		for _, v := range items {
			tmp := (*TradePositionGuangzhouTop)(unsafe.Pointer(v))
			list = append(list, tmp)
		}
		_, err = o.InsertMulti(len(list), list)
		return
	}

	return
}

func GetTradePositionTopByExchangeDataTime(exchange string, startDate, endDate string) (list []*TradePositionTop, err error) {
	o := orm.NewOrm()
	sql := "SELECT * FROM trade_position_" + exchange + "_top where data_time >= ? and data_time <= ? and deal_type in (1,2) ORDER BY classify_name, classify_type, deal_type, data_time, deal_value desc"
	_, err = o.Raw(sql, startDate, endDate).QueryRows(&list)
	return
}

func GetTradePositionTopByExchangeDataTimeByClassify(exchange string, startDate, endDate string, classifyNames, classifyTypes []string) (list []*TradePositionTop, err error) {
	o := orm.NewOrm()
	sql := `SELECT * FROM trade_position_` + exchange + `_top where data_time >= ? and data_time <= ? and deal_type in (1,2) and classify_name in (` + utils.GetOrmInReplace(len(classifyNames)) + `)  and classify_type in (` + utils.GetOrmInReplace(len(classifyTypes)) + `) ORDER BY classify_name, classify_type, deal_type, data_time, deal_value desc`
	_, err = o.Raw(sql, startDate, endDate, classifyNames, classifyTypes).QueryRows(&list)
	return
}

func GetTradePositionTopCountByExchangeDataTime(exchange string, startDate, endDate string) (count int64, err error) {
	o := orm.NewOrm()
	sql := "SELECT count(*) FROM trade_position_" + exchange + "_top where data_time >= ? and data_time <= ? and deal_type in (1,2) ORDER BY classify_name, classify_type, deal_type, data_time, deal_value desc"
	err = o.Raw(sql, startDate, endDate).QueryRow(&count)
	return
}

func GetTradePositionTopByExchangeSourceType(exchange string, dataTime string, sourceType int) (list []*TradePositionTop, err error) {
	o := orm.NewOrm()
	sql := "SELECT * FROM trade_position_" + exchange + "_top where data_time= ? and source_type = ? ORDER BY classify_name, classify_type, deal_type, deal_value desc"
	_, err = o.Raw(sql, dataTime, sourceType).QueryRows(&list)
	return
}

func GetTradePositionTopByExchangeSourceTypeClassify(exchange string, dataTime string, sourceType int, classifyNames, classifyTypes []string) (list []*TradePositionTop, err error) {
	o := orm.NewOrm()
	sql := `SELECT * FROM trade_position_` + exchange + `_top where data_time= ? and source_type = ? and classify_name in (` + utils.GetOrmInReplace(len(classifyNames)) + `)  and classify_type in (` + utils.GetOrmInReplace(len(classifyTypes)) + `) ORDER BY classify_name, classify_type, deal_type, deal_value desc`
	_, err = o.Raw(sql, dataTime, sourceType, classifyNames, classifyTypes).QueryRows(&list)
	return
}

type TradeTopClassify struct {
	ClassifyName string //分类名称
	ClassifyType string //分类名称下的类型
}

type TradePositionSub struct {
	ClassifyName  string //分类名称
	ClassifyType  string //分类名称下的类型
	DataTime      string //数据日期
	DealShortName string //成交量公司简称
	SubValue      int    //差值
	DealType      int
}

type TradePositionSubList []*TradePositionSub

func (v TradePositionSubList) Len() int {
	return len(v)
}

func (v TradePositionSubList) Swap(i, j int) {
	v[i], v[j] = v[j], v[i]
}

func (v TradePositionSubList) Less(i, j int) bool {
	return v[i].SubValue > v[j].SubValue
}

type UpdateDealValueChange struct {
	Id         uint64
	DealValue  int //成交量
	DealChange int
	SourceType int
	ModifyTime time.Time //修改时间
}

type UpdateChangeVal struct {
	Id         uint64
	DealChange int
	ModifyTime time.Time //修改时间
}

func MultiUpdatePositionTop(exchange string, updates []UpdateDealValueChange) (err error) {
	o := orm.NewOrm()
	p, err := o.Raw("UPDATE trade_position_" + exchange + "_top SET deal_value=?, deal_change=?, source_type=?, modify_time=? WHERE id = ?").Prepare()
	if err != nil {
		return
	}
	defer func() {
		_ = p.Close() // 别忘记关闭 statement
	}()
	for _, v := range updates {
		_, err = p.Exec(v.DealValue, v.DealChange, v.SourceType, v.ModifyTime, v.Id)
		if err != nil {
			return
		}
	}
	return
}

func DeletePositionTopByDataTime(exchange string, dataTime string, dealType int) (err error) {
	o := orm.NewOrm()
	sql := "delete from trade_position_" + exchange + "_top WHERE data_time=? and deal_type=?"
	_, err = o.Raw(sql, dataTime, dealType).Exec()
	return
}

func DeletePositionTopByDataTimeClassify(exchange string, dataTime string, dealType int, classifyNames, classifyTypes []string) (err error) {
	o := orm.NewOrm()
	sql := `delete from trade_position_` + exchange + `_top WHERE data_time=? and deal_type=? and classify_name in (` + utils.GetOrmInReplace(len(classifyNames)) + `)  and classify_type in (` + utils.GetOrmInReplace(len(classifyTypes)) + `)`
	_, err = o.Raw(sql, dataTime, dealType, classifyNames, classifyTypes).Exec()
	return
}

func GetTradePositionTopByExchangeDataTimeType(exchange string, dataTime string, dealType int) (list []TradePositionTop, err error) {
	o := orm.NewOrm()
	sql := "select * from trade_position_" + exchange + "_top WHERE data_time=? and deal_type=?"
	_, err = o.Raw(sql, dataTime, dealType).QueryRows(&list)
	return
}

func GetTradePositionTopByExchangeDataTimeTypeClassify(exchange string, dataTime string, dealType int, classifyNames, classifyTypes []string) (list []TradePositionTop, err error) {
	o := orm.NewOrm()
	sql := `select * from trade_position_` + exchange + `_top WHERE data_time=? and deal_type=? and classify_name in (` + utils.GetOrmInReplace(len(classifyNames)) + `)  and classify_type in (` + utils.GetOrmInReplace(len(classifyTypes)) + `)`
	_, err = o.Raw(sql, dataTime, dealType, classifyNames, classifyTypes).QueryRows(&list)
	return
}

func MultiInsertTradeBaseDataToTop(exchange string, startDate, endDate string) (err error) {
	o := orm.NewOrm()
	now := time.Now().Format(utils.FormatDateTime)
	sql1 := "INSERT INTO trade_position_" + exchange + "_top(classify_name,classify_type,deal_short_name,deal_value,deal_change,data_time,deal_type,source_type,`rank`,create_time,modify_time) " +
		"SELECT classify_name,classify_type,buy_short_name,buy_value,buy_change,data_time,1,0,`rank`,?,? FROM base_from_trade_" + exchange + "_index where `rank` <50 and buy_short_name !='' and buy_short_name !=' ' and data_time between ? and ?"
	_, err = o.Raw(sql1, now, now, startDate, endDate).Exec()
	if err != nil {
		return
	}
	sql2 := "INSERT INTO trade_position_" + exchange + "_top(classify_name,classify_type,deal_short_name,deal_value,deal_change,data_time,deal_type,source_type,`rank`,create_time,modify_time) " +
		"SELECT classify_name,classify_type,sold_short_name,sold_value,sold_change,data_time,2,0,`rank`,?,? FROM base_from_trade_" + exchange + "_index where `rank` <50 and sold_short_name !='' and sold_short_name !=' ' and data_time between ? and ?"
	_, err = o.Raw(sql2, now, now, startDate, endDate).Exec()
	return
}

func MultiInsertTradeBaseDataToTopByClassify(exchange string, startDate, endDate string, classifyNames, classifyTypes []string) (err error) {
	o := orm.NewOrm()
	now := time.Now().Format(utils.FormatDateTime)
	sql1 := "INSERT INTO trade_position_" + exchange + "_top(classify_name,classify_type,deal_short_name,deal_value,deal_change,data_time,deal_type,source_type,`rank`,create_time,modify_time)" +
		"SELECT classify_name,classify_type,buy_short_name,buy_value,buy_change,data_time,1,0,`rank`,?,? FROM base_from_trade_" + exchange + "_index where `rank` <50 and buy_short_name !='' and buy_short_name !=' ' and data_time between ? and ? and classify_name in (" + utils.GetOrmInReplace(len(classifyNames)) + ")  and classify_type in (" + utils.GetOrmInReplace(len(classifyTypes)) + ")"
	_, err = o.Raw(sql1, now, now, startDate, endDate, classifyNames, classifyTypes).Exec()
	if err != nil {
		return
	}
	sql2 := "INSERT INTO trade_position_" + exchange + "_top(classify_name,classify_type,deal_short_name,deal_value,deal_change,data_time,deal_type,source_type,`rank`,create_time,modify_time)" +
		"SELECT classify_name,classify_type,sold_short_name,sold_value,sold_change,data_time,2,0,`rank`,?,? FROM base_from_trade_" + exchange + "_index where `rank` <50 and sold_short_name !='' and sold_short_name !=' ' and data_time between ? and ? and classify_name in (" + utils.GetOrmInReplace(len(classifyNames)) + ")  and classify_type in (" + utils.GetOrmInReplace(len(classifyTypes)) + ")"
	_, err = o.Raw(sql2, now, now, startDate, endDate, classifyNames, classifyTypes).Exec()
	return
}

// GetTradePositionTopOriginDataTimes 获取榜单原始数据日期-正序
func GetTradePositionTopOriginDataTimes(exchange string) (dates []string, err error) {
	o := orm.NewOrm()
	sql := `SELECT DISTINCT data_time FROM base_from_trade_%s_index ORDER BY data_time ASC`
	sql = fmt.Sprintf(sql, exchange)
	_, err = o.Raw(sql).QueryRows(&dates)
	return
}

// BaseFromTradeClassify 交易所分类表
type BaseFromTradeClassify struct {
	Id           uint64    `orm:"column(id);pk"`
	ClassifyName string    //分类名称
	ClassifyType string    //分类名称下的类型
	Exchange     string    //交易所
	LatestDate   time.Time //数据最近的日期
	CreateTime   time.Time //插入时间
	ModifyTime   time.Time //修改时间
}

// GetAllBaseFromTradeClassify 获取所有的交易所分类列表
func GetAllBaseFromTradeClassify() (list []*BaseFromTradeClassify, err error) {
	sql := `SELECT * FROM base_from_trade_classify   `

	o := orm.NewOrm()
	_, err = o.Raw(sql).QueryRows(&list)

	return
}

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

// MultiAddBaseFromTradeClassify 批量插入交易所分类
func MultiAddBaseFromTradeClassify(items []*BaseFromTradeClassify) (err error) {
	if len(items) == 0 {
		return
	}
	o := orm.NewOrm()
	_, err = o.InsertMulti(len(items), items)
	return
}

type TradeClassifyName struct {
	ClassifyName string    //分类名称
	ClassifyType string    //分类名称下的类型
	DataTime     time.Time //数据最近的日期
	ModifyTime   time.Time //数据最近的日期
}

// GetExchangeClassify 获取交易所分类列表
func GetExchangeClassify(exchange string) (list []TradeClassifyName, err error) {
	tableName := "trade_position_" + exchange + "_top"
	orderStr := "classify_name DESC, classify_type asc"
	if exchange == "zhengzhou" {
		orderStr = "classify_name asc"
	}
	sql := `SELECT classify_name, classify_type,MAX(data_time) as data_time,MAX(modify_time) as modify_time FROM ` + tableName + ` GROUP BY classify_name, classify_type  `
	sql += ` ORDER BY ` + orderStr

	o := orm.NewOrm()
	_, err = o.Raw(sql).QueryRows(&list)

	return
}

// GetTradePositionTopCleanByExchangeDataTime 根据时间查询净多单和净空单的值
func GetTradePositionTopCleanByExchangeDataTime(exchange string, startDate, endDate string) (list []*TradePositionTop, err error) {
	o := orm.NewOrm()
	sql := "SELECT * FROM trade_position_" + exchange + "_top where data_time >= ? and data_time <= ? and deal_type in (3,4) ORDER BY classify_name, classify_type, deal_type, data_time, deal_value desc"
	_, err = o.Raw(sql, startDate, endDate).QueryRows(&list)
	return
}

// GetTradePositionTopCleanByExchangeDataTimeClassify 根据时间查询净多单和净空单的值
func GetTradePositionTopCleanByExchangeDataTimeClassify(exchange string, startDate, endDate string, classifyNames, classifyTypes []string) (list []*TradePositionTop, err error) {
	o := orm.NewOrm()
	sql := `SELECT * FROM trade_position_` + exchange + `_top where data_time >= ? and data_time <= ? and deal_type in (3,4) and classify_name in (` + utils.GetOrmInReplace(len(classifyNames)) + `)  and classify_type in (` + utils.GetOrmInReplace(len(classifyTypes)) + `) ORDER BY classify_name, classify_type, deal_type, data_time, deal_value desc`
	_, err = o.Raw(sql, startDate, endDate, classifyNames, classifyTypes).QueryRows(&list)
	return
}

// MultiUpdatePositionTopChangeVal 批量更新榜单里变化量的值
func MultiUpdatePositionTopChangeVal(exchange string, updates []UpdateChangeVal) (err error) {
	o := orm.NewOrm()
	p, err := o.Raw("UPDATE trade_position_" + exchange + "_top SET deal_change=?, modify_time=? WHERE id = ?").Prepare()
	if err != nil {
		return
	}
	defer func() {
		_ = p.Close() // 别忘记关闭 statement
	}()
	for _, v := range updates {
		_, err = p.Exec(v.DealChange, v.ModifyTime, v.Id)
		if err != nil {
			return
		}
	}
	return
}

func GetTradePositionOriginClassifyCountByExchangeDataTime(exchange string, startDate, endDate string) (count int64, err error) {
	o := orm.NewOrm()
	sql := "SELECT COUNT(DISTINCT classify_name, classify_type) FROM base_from_trade_" + exchange + "_index where `rank` <50 and (buy_short_name !='' or sold_short_name !='' ) and (buy_short_name !=' ' or sold_short_name !=' ' ) and data_time >= ? and data_time <= ?"
	err = o.Raw(sql, startDate, endDate).QueryRow(&count)
	return
}

func GetTradePositionTopClassifyCountByExchangeDataTime(exchange string, startDate, endDate string) (count int64, err error) {
	o := orm.NewOrm()
	sql := "SELECT COUNT(DISTINCT classify_name, classify_type)  FROM trade_position_" + exchange + "_top where data_time >= ? and data_time <= ? and deal_type in (1,2) "
	err = o.Raw(sql, startDate, endDate).QueryRow(&count)
	return
}

type TradePositionClassifyInfo struct {
	ClassifyName string //分类名称
	ClassifyType string //分类名称下的类型
}

func GetTradePositionOriginClassifyByExchangeDataTime(exchange string, startDate, endDate string) (list []TradePositionClassifyInfo, err error) {
	o := orm.NewOrm()
	sql := "SELECT DISTINCT classify_name, classify_type FROM base_from_trade_" + exchange + "_index where `rank` <50 and (buy_short_name !='' or sold_short_name !='' ) and (buy_short_name !=' ' or sold_short_name !=' ' ) and data_time >= ? and data_time <= ?"
	_, err = o.Raw(sql, startDate, endDate).QueryRows(&list)
	return
}

func GetTradePositionTopClassifyByExchangeDataTime(exchange string, startDate, endDate string) (list []TradePositionClassifyInfo, err error) {
	o := orm.NewOrm()
	sql := "SELECT DISTINCT classify_name, classify_type  FROM trade_position_" + exchange + "_top where data_time >= ? and data_time <= ? and deal_type in (1,2) "
	_, err = o.Raw(sql, startDate, endDate).QueryRows(&list)
	return
}

// DeleteTradePositionTopAllByExchangeDataTime 删除计算数据
func DeleteTradePositionTopAllByExchangeDataTime(exchange string, startDate, endDate string) (err error) {
	o := orm.NewOrm()
	sql := "DELETE FROM trade_position_" + exchange + "_top where data_time >= ? and data_time <= ? "
	_, err = o.Raw(sql, startDate, endDate).Exec()
	return
}

type GetFirstBaseFromTradeIndeDate struct {
	DataTime string
}

func GetFirstBaseFromTradeIndexByDate(exchange string) (item *GetFirstBaseFromTradeIndeDate, err error) {
	o := orm.NewOrm()
	sql := "SELECT * FROM base_from_trade_" + exchange + "_index where `rank` < 50 order by data_time asc"
	err = o.Raw(sql).QueryRow(&item)
	return
}

// 获取持仓分析的最新数据
func GetTradePositionTopLastedDataTime(exchange string) (data_time time.Time, err error) {
	o := orm.NewOrm()
	sql := "SELECT max(data_time) FROM trade_position_" + exchange + "_top"
	err = o.Raw(sql).QueryRow(&data_time)
	return
}