package trade_analysis

import (
	"eta/eta_index_lib/global"
	"eta/eta_index_lib/utils"
	"fmt"
	"strings"
	"time"
)

const (
	TradeDataTypeNull      = 0 // 无值
	TradeDataTypeOrigin    = 1 // 原始值
	TradeDataTypeCalculate = 2 // 推算值

	WarehouseBuyChartType     = 1 // 多单图
	WarehouseSoldChartType    = 2 // 空单图
	WarehousePureBuyChartType = 3 // 净多单图

	WarehouseDefaultUnit      = "手"
	WarehouseDefaultFrequency = "日度"

	GuangZhouTopCompanyAliasName = "日成交持仓排名" // 广期所TOP20对应的公司名称
	GuangZhouSeatNameBuy         = "持买单量"    // 广期所指标名称中的多单名称
	GuangZhouSeatNameSold        = "持卖单量"    // 广期所指标名称中的空单名称
	GuangZhouTopSeatNameBuy      = "持买单量总计"  // 广期所指标名称中的TOP20多单名称
	GuangZhouTopSeatNameSold     = "持卖单量总计"  // 广期所指标名称中的TOP20空单名称
	GuangZhouTopSeatNameDeal     = "成交量总计"   // 广期所指标名称中的TOP20成交量名称
)

const (
	TradeExchangeDalian    = "dalian"
	TradeExchangeZhengzhou = "zhengzhou"
	TradeExchangeGuangzhou = "guangzhou"
)

var WarehouseTypeSuffixNames = map[int]string{
	WarehouseBuyChartType:     "席位多单",
	WarehouseSoldChartType:    "席位空单",
	WarehousePureBuyChartType: "席位净多单",
}

// GuangzhouSeatNameValType 广期所数据名称对应的席位方向
var GuangzhouSeatNameValType = map[string]int{
	GuangZhouSeatNameBuy:     1,
	GuangZhouSeatNameSold:    2,
	GuangZhouTopSeatNameBuy:  1,
	GuangZhouTopSeatNameSold: 2,
	GuangZhouTopSeatNameDeal: 3,
}

// 合约查询方式
var (
	ContractQueryTypeTop   = 1 // 主力合约
	ContractQueryTypeTop2  = 2 // 成交量前2
	ContractQueryTypeTop3  = 3 // 成交量前3
	ContractQueryTypeAll   = 4 // 所有合约(多个)
	ContractQueryTypeTotal = 5 // 合约加总(1个)
)

// 合约方向
var (
	ContractPositionBuy     = 1 // 多单
	ContractPositionSold    = 2 // 空单
	ContractPositionPureBuy = 3 // 净多单
)

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

type TradeClassifyNameList struct {
	Exchange   string                      `description:"交易所"`
	ExchangeEn string                      `description:"交易所英文"`
	Sort       int                         `description:"排序字段" `
	Num        int                         `description:"品种数量"`
	DataTime   string                      `description:"最新更新时间"`
	CurrDate   string                      `description:"当前日期"`
	Items      []TradeClassifyNameListItem `description:"子类"`
}
type TradeClassifyNameListSort []TradeClassifyNameList

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

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

func (v TradeClassifyNameListSort) Less(i, j int) bool {
	return v[i].Sort < v[j].Sort
}

type TradeClassifyNameListItemSort []TradeClassifyNameListItem

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

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

func (v TradeClassifyNameListItemSort) Less(i, j int) bool {
	return v[i].ClassifyName < v[j].ClassifyName
}

type TradeClassifyNameListItem struct {
	ClassifyName string                          `description:"交易分类"`
	Items        []TradeClassifyNameListItemItem `description:"合约代码"`
}

type TradeClassifyNameListItemItemSort []TradeClassifyNameListItemItem

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

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

func (v TradeClassifyNameListItemItemSort) Less(i, j int) bool {
	return v[i].ClassifyType < v[j].ClassifyType
}

type TradeClassifyNameListItemItem struct {
	ClassifyType string `description:"分类名称下的类型"`
}

type TradeClassifyName struct {
	ClassifyName string //分类名称
	ClassifyType string //分类名称下的类型
	LatestDate   string //分类下最晚日期
}

// GetExchangeClassify 获取交易所分类列表
func GetExchangeClassify(exchange string) (list []TradeClassifyName, err error) {
	tableName := "base_from_trade_" + exchange + "_index"
	orderStr := "classify_name DESC, classify_type asc"
	if exchange == "zhengzhou" {
		orderStr = "classify_name asc"
	}
	sql := "SELECT classify_name, classify_type FROM " + tableName + " WHERE `rank` <=20 and `rank` > 0 GROUP BY classify_name, classify_type  "
	sql += ` ORDER BY ` + orderStr

	err = global.DEFAULT_DB.Raw(sql).Find(&list).Error

	return
}

type LastTimeItem struct {
	CreateTime time.Time
}

// GetExchangeLastTime 获取交易所数据最晚的时间
func GetExchangeLastTime(exchange string) (item LastTimeItem, err error) {
	tableName := "base_from_trade_" + exchange + "_index"
	sql := `SELECT create_time FROM ` + tableName + ` ORDER BY create_time desc`
	err = global.DEFAULT_DB.Raw(sql).First(&item).Error

	return
}

type GetPositionTopReq struct {
	Exchange     string `json:"exchange" form:"exchange"`           //交易所
	ClassifyName string `json:"classify_name" form:"classify_name"` //分类名称
	ClassifyType string `json:"classify_type" form:"classify_type"` //具体合约名称
	DataTime     string `json:"data_time" form:"data_time"`         //请求日期,如果为空,则返回最新的榜单日期
}

type GetPositionTopResp struct {
	BuyList       GetPositionTopList `description:"多单列表"`
	SoldList      GetPositionTopList `description:"空单列表"`
	CleanBuyList  GetPositionTopList `description:"净多单列表"`
	CleanSoldList GetPositionTopList `description:"净空单列表"`
	DataTime      string             `description:"最新日期或者请求日期"`
	LastDataTime  string             `description:"最新日期"`
}

type GetPositionTopList struct {
	TotalDealValue  int                      `description:"总计成交量"`
	TotalDealChange int                      `description:"校昨日变化"`
	List            []GetPositionTopListItem `description:"榜单详情列表"`
}

type GetPositionTopListItem struct {
	DealShortName   string `description:"成交量公司简称"`
	DealValue       int    `description:"成交量"`
	DealChange      int    `description:"成交变化量"`
	Rank            int    `description:"当前名次"`
	Rate            string `description:"当前占比"`
	BeforeAllRate   string `description:"排在前面的成交量总计占比(包含)"`
	BeforeAllValue  int    `description:"排在前面的成交量总计"`
	BeforeAllChange int    `description:"排在前面的成交量增减总计"`
}

func GetTradePositionTop(exchange string, classifyName, classifyType, dataTime string) (list []TradePositionTop, err error) {
	tableName := "trade_position_" + exchange + "_top"
	sql := `SELECT * FROM ` + tableName + " WHERE classify_name=? and classify_type=? and data_time=? and `rank` <=20 and `rank` > 0 ORDER BY deal_value desc"

	err = global.DEFAULT_DB.Raw(sql, classifyName, classifyType, dataTime).Find(&list).Error

	return
}

type OriginTradeData struct {
	Rank         int       `description:"排名"`
	CompanyName  string    `description:"期货公司名称"`
	Val          int       `description:"持仓量"`
	ValChange    int       `description:"持仓增减"`
	DataTime     time.Time `description:"数据日期"`
	ClassifyName string    `description:"品种名称"`
	ClassifyType string    `description:"合约代码"`
	ValType      int       `description:"数据类型: 1-多单; 2-空单"`
}

// BaseFromTradeCommonIndex 郑商所/大商所/上期所/上期能源指标表通用字段
type BaseFromTradeCommonIndex struct {
	Rank          int       `description:"排名"`
	DealShortName string    `description:"成交量公司简称"`
	DealName      string    `description:"成交量指标名称"`
	DealCode      string    `description:"成交量指标编码"`
	DealValue     int       `description:"成交量"`
	DealChange    int       `description:"成交变化量"`
	BuyShortName  string    `description:"持买单量公司简称"`
	BuyName       string    `description:"持买单量指标名称"`
	BuyCode       string    `description:"持买单量指标编码"`
	BuyValue      int       `description:"持买单量"`
	BuyChange     int       `description:"持买单量变化量"`
	SoldShortName string    `description:"持卖单量公司简称"`
	SoldName      string    `description:"持卖单量指标名称"`
	SoldCode      string    `description:"持卖单量指标编码"`
	SoldValue     int       `description:"持卖单量"`
	SoldChange    int       `description:"持卖单变化量"`
	Frequency     string    `description:"频度"`
	ClassifyName  string    `description:"品种"`
	ClassifyType  string    `description:"合约"`
	CreateTime    time.Time `description:"创建时间"`
	ModifyTime    time.Time `description:"更新时间"`
	DataTime      time.Time `description:"数据日期"`
}

// GetTradeDataByContracts 根据合约获取持仓数据
func GetTradeDataByContracts(exchange string, classifyNames, contracts []string, startDate, endDate time.Time) (items []*BaseFromTradeCommonIndex, err error) {
	if exchange == "" {
		err = fmt.Errorf("数据表名称有误")
		return
	}
	var cond string
	var pars []interface{}
	if len(classifyNames) > 0 {
		cond += fmt.Sprintf(` AND classify_name IN (%s)`, utils.GetOrmInReplace(len(classifyNames)))
		pars = append(pars, classifyNames)
	}
	if len(contracts) > 0 {
		cond += fmt.Sprintf(` AND classify_type IN (%s)`, utils.GetOrmInReplace(len(contracts)))
		pars = append(pars, contracts)
	}
	if !startDate.IsZero() && !endDate.IsZero() {
		cond += ` AND (data_time BETWEEN ? AND ?)`
		pars = append(pars, startDate.Format(utils.FormatDate), endDate.Format(utils.FormatDate))
	}
	fields := []string{"rank", "buy_short_name", "buy_value", "buy_change", "sold_short_name", "sold_value", "sold_change", "classify_name", "classify_type", "data_time"}
	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s ORDER BY data_time DESC`, strings.Join(fields, ","), tableName, cond)
	err = global.DEFAULT_DB.Raw(sql, pars...).Find(&items).Error

	return
}

// GetZhengzhouTradeDataByContracts 郑商所-根据合约获取持仓数据
func GetZhengzhouTradeDataByContracts(classifyNames []string, startDate, endDate time.Time) (items []*BaseFromTradeCommonIndex, err error) {
	var cond string
	var pars []interface{}
	if len(classifyNames) > 0 {
		cond += fmt.Sprintf(` AND classify_name IN (%s)`, utils.GetOrmInReplace(len(classifyNames)))
		pars = append(pars, classifyNames)
	}
	if !startDate.IsZero() && !endDate.IsZero() {
		cond += ` AND (data_time BETWEEN ? AND ?)`
		pars = append(pars, startDate.Format(utils.FormatDate), endDate.Format(utils.FormatDate))
	}
	// ps.classify_name实为合约代码
	fields := []string{"rank", "buy_short_name", "buy_value", "buy_change", "sold_short_name", "sold_value", "sold_change", "classify_name AS classify_type", "data_time"}
	sql := fmt.Sprintf(`SELECT %s FROM base_from_trade_zhengzhou_index WHERE 1=1 %s ORDER BY data_time DESC`, strings.Join(fields, ","), cond)
	err = global.DEFAULT_DB.Raw(sql, pars...).Find(&items).Error

	return
}

// ContractCompanyTradeData [合约-期货公司]持仓数据
type ContractCompanyTradeData struct {
	Exchange     string                          `description:"交易所"`
	ClassifyName string                          `description:"品种"`
	ClassifyType string                          `description:"合约代码"`
	CompanyName  string                          `description:"期货公司名称"`
	IsTotal      bool                            `description:"是否为合约加总"`
	StartDate    time.Time                       `description:"数据开始日期"`
	EndDate      time.Time                       `description:"数据结束日期"`
	DataList     []*ContractCompanyTradeDataList `description:"数据序列"`
}

// ContractCompanyTradeDataList [合约-期货公司]持仓数据详情
type ContractCompanyTradeDataList struct {
	Date              time.Time `description:"数据日期"`
	BuyVal            int       `description:"多单持仓量"`
	BuyValType        int       `description:"多单数据类型: 0-无值; 1-原始值; 2-推算值"`
	BuyChange         int       `description:"多单持仓增减"`
	BuyChangeType     int       `description:"多单持仓增减类型: 0-无值; 1-原始值; 2-推算值"`
	SoldVal           int       `description:"空单持仓量"`
	SoldValType       int       `description:"空单数据类型: 0-无值; 1-原始值; 2-推算值"`
	SoldChange        int       `description:"空单持仓增减"`
	SoldChangeType    int       `description:"空单持仓增减类型: 0-无值; 1-原始值; 2-推算值"`
	PureBuyVal        int       `description:"净多单持仓量"`
	PureBuyValType    int       `description:"净多单数据类型: 0-无值; 1-原始值; 2-推算值"`
	PureBuyChange     int       `description:"净多单持仓增减"`
	PureBuyChangeType int       `description:"净多单持仓增减类型: 0-无值; 1-原始值; 2-推算值"`
}

type BaseFromTradeGuangzhouIndex struct {
	BaseFromTradeGuangzhouIndexId    int       `gorm:"column:base_from_trade_guangzhou_index_id;primaryKey"`
	BaseFromTradeGuangzhouClassifyId int       `description:"分类id"`
	IndexCode                        string    `description:"指标编码"`
	IndexName                        string    `description:"指标名称"`
	Frequency                        string    `description:"频率"`
	Unit                             string    `description:"单位"`
	StartDate                        string    `description:"开始日期"`
	EndDate                          string    `description:"结束日期"`
	CreateTime                       time.Time `description:"创建日期"`
	ModifyTime                       time.Time `description:"修改日期"`
}

func GetBaseFromTradeGuangzhouIndex(classifyIds []int, contracts []string, indexKeyword string) (list []*BaseFromTradeGuangzhouIndex, err error) {
	cond := ``
	pars := make([]interface{}, 0)
	if len(classifyIds) > 0 {
		cond += fmt.Sprintf(` AND b.base_from_trade_guangzhou_classify_id IN (%s)`, utils.GetOrmInReplace(len(classifyIds)))
		pars = append(pars, classifyIds)
	}
	if len(contracts) > 0 {
		cond += fmt.Sprintf(` AND b.contract IN (%s)`, utils.GetOrmInReplace(len(contracts)))
		pars = append(pars, contracts)
	}
	if indexKeyword != "" {
		cond += fmt.Sprintf(` AND a.index_name LIKE ?`)
		pars = append(pars, indexKeyword)
	}
	sql := `SELECT a.* FROM base_from_trade_guangzhou_index AS a
		JOIN base_from_trade_guangzhou_contract AS b ON a.base_from_trade_guangzhou_contract_id = b.base_from_trade_guangzhou_contract_id
		WHERE 1=1 %s`
	sql = fmt.Sprintf(sql, cond)
	err = global.DEFAULT_DB.Raw(sql, pars...).Find(&list).Error

	return
}

type BaseFromTradeGuangzhouData struct {
	BaseFromTradeGuangzhouDataId  int       `gorm:"column:base_from_trade_guangzhou_data_id;primaryKey"`
	BaseFromTradeGuangzhouIndexId int       `description:"指标id"`
	IndexCode                     string    `description:"指标编码"`
	DataTime                      time.Time `description:"数据日期"`
	Value                         float64   `description:"数据值"`
	QtySub                        float64   `description:"增减"`
	CreateTime                    time.Time `description:"创建日期"`
	ModifyTime                    time.Time `description:"修改日期"`
}

// GetBaseFromTradeGuangzhouDataByIndexIds 广期所-获取指标数据
func GetBaseFromTradeGuangzhouDataByIndexIds(indexIds []int, startDate, endDate time.Time) (list []*BaseFromTradeGuangzhouData, err error) {
	if len(indexIds) == 0 {
		return
	}
	cond := fmt.Sprintf(` AND base_from_trade_guangzhou_index_id IN (%s)`, utils.GetOrmInReplace(len(indexIds)))
	pars := make([]interface{}, 0)
	pars = append(pars, indexIds)
	if !startDate.IsZero() && !endDate.IsZero() {
		if startDate.Equal(endDate) {
			cond += ` AND data_time = ?`
			pars = append(pars, startDate.Format(utils.FormatDate))
		}
		if !startDate.Equal(endDate) {
			cond += ` AND (data_time BETWEEN ? AND ?)`
			pars = append(pars, startDate.Format(utils.FormatDate), endDate.Format(utils.FormatDate))
		}
	}
	sql := fmt.Sprintf(`SELECT * FROM base_from_trade_guangzhou_data WHERE 1=1 %s ORDER BY base_from_trade_guangzhou_index_id`, cond)
	err = global.DEFAULT_DB.Raw(sql, pars...).Find(&list).Error

	return
}

// ContractTopRankData TOP20合约排名数据
type ContractTopRankData struct {
	Exchange      string    `description:"交易所"`
	DealValue     int       `description:"成交量"`
	BuyValue      int       `description:"多单持仓量"`
	BuyChange     int       `description:"多单变化"`
	SoldValue     int       `description:"空单持仓量"`
	SoldChange    int       `description:"空单变化"`
	PureBuyValue  int       `description:"净多单持仓量"`
	PureBuyChange int       `description:"净多单变化"`
	ClassifyName  string    `description:"品种名称"`
	ClassifyType  string    `description:"合约代码"`
	DataTime      time.Time `description:"数据日期"`
}

// GetContractTopRankData 获取合约TOP20根据当日成交量排名
func GetContractTopRankData(exchange string, classifyNames []string, dataDate time.Time) (items []*ContractTopRankData, err error) {
	if exchange == "" {
		err = fmt.Errorf("数据表名称有误")
		return
	}
	if len(classifyNames) == 0 {
		return
	}
	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
	// 大商所存在TOP20的rank=0
	queryRank := ` rank = 999`
	if exchange == TradeExchangeDalian {
		queryRank = ` (rank = 999 OR rank = 0)`
	}
	sql := `SELECT * FROM %s WHERE data_time = ? AND classify_name IN (%s) AND %s GROUP BY classify_type ORDER BY deal_value DESC`
	sql = fmt.Sprintf(sql, tableName, utils.GetOrmInReplace(len(classifyNames)), queryRank)
	err = global.DEFAULT_DB.Raw(sql, dataDate.Format(utils.FormatDate), classifyNames).Find(&items).Error

	return
}

// GetZhengzhouContractTopRankData 郑商所-获取合约根据当日成交量排名
func GetZhengzhouContractTopRankData(classifyNames []string, dataDate time.Time) (items []*ContractTopRankData, err error) {
	if len(classifyNames) == 0 {
		return
	}
	sql := `SELECT * FROM base_from_trade_zhengzhou_index WHERE data_time = ? AND classify_name IN (%s) AND rank = 999 GROUP BY classify_name ORDER BY deal_value DESC`
	sql = fmt.Sprintf(sql, utils.GetOrmInReplace(len(classifyNames)))
	err = global.DEFAULT_DB.Raw(sql, dataDate.Format(utils.FormatDate), classifyNames).Find(&items).Error

	return
}

// ContractCompanyTradeEdb [合约-期货公司]指标
type ContractCompanyTradeEdb struct {
	Exchange         string                         `description:"交易所"`
	ClassifyName     string                         `description:"品种"`
	ClassifyType     string                         `description:"合约代码"`
	CompanyName      string                         `description:"期货公司名称"`
	IsTotal          bool                           `description:"是否为合约加总"`
	ContractPosition int                            `description:"合约方向"`
	StartDate        time.Time                      `description:"数据开始日期"`
	EndDate          time.Time                      `description:"数据结束日期"`
	DataList         []*ContractCompanyTradeEdbData `description:"数据序列"`
}

// ContractCompanyTradeEdbData [合约-期货公司]指标数据
type ContractCompanyTradeEdbData struct {
	DataTime time.Time `description:"数据日期"`
	Val      int       `description:"数据值"`
}

// GetClassifyNewestDataTime 获取品种最新数据日期
func GetClassifyNewestDataTime(exchange string, classifyNames []string) (dateTime time.Time, err error) {
	if exchange == "" {
		err = fmt.Errorf("数据表名称有误")
		return
	}
	if len(classifyNames) == 0 {
		return
	}
	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
	sql := `SELECT data_time FROM %s WHERE classify_name IN (%s) ORDER BY data_time DESC LIMIT 1`
	sql = fmt.Sprintf(sql, tableName, utils.GetOrmInReplace(len(classifyNames)))
	err = global.DEFAULT_DB.Raw(sql, classifyNames).Scan(&dateTime).Error

	return
}

// GetGuangzhouClassifyNewestDataTime 广期所-获取品种最新数据日期
func GetGuangzhouClassifyNewestDataTime(indexIds []int) (dateTime time.Time, err error) {
	if len(indexIds) == 0 {
		return
	}
	cond := fmt.Sprintf(` AND base_from_trade_guangzhou_index_id IN (%s)`, utils.GetOrmInReplace(len(indexIds)))
	pars := make([]interface{}, 0)
	pars = append(pars, indexIds)
	sql := fmt.Sprintf(`SELECT data_time FROM base_from_trade_guangzhou_data WHERE 1=1 %s ORDER BY data_time DESC LIMIT 1`, cond)
	err = global.DEFAULT_DB.Raw(sql, pars...).Scan(&dateTime).Error

	return
}

type RefreshTableReq struct {
	ExcelInfoId int `description:"表格ID"`
}