package models

import (
	"errors"
	"mtp2_if/db"
	"time"

	"gopkg.in/mgo.v2/bson"
)

// CycleType 周期类型
type CycleType int

const (
	// CycleTypeSecond 周期类型 - 秒
	CycleTypeSecond CycleType = 0
	// CycleTypeMinutes1 周期类型 - 1分钟
	CycleTypeMinutes1 CycleType = 1
	// CycleTypeMinutes5 周期类型 - 5分钟
	CycleTypeMinutes5 CycleType = 2
	// CycleTypeMinutes30 周期类型 - 30分钟
	CycleTypeMinutes30 CycleType = 3
	// CycleTypeMinutes60 周期类型 - 60分钟
	CycleTypeMinutes60 CycleType = 4
	// CycleTypeMinutes120 周期类型 - 2小时
	CycleTypeMinutes120 CycleType = 120
	// CycleTypeMinutes240 周期类型 - 4小时
	CycleTypeMinutes240 CycleType = 240
	// CycleTypeMinutesDay 周期类型 - 日线
	CycleTypeMinutesDay CycleType = 11
	// CycleTypeTik 周期类型 - Tik
	CycleTypeTik CycleType = 10
)

// CycleData MongoDB中历史数据模型
type CycleData struct {
	ID    bson.ObjectId `json:"-" bson:"_id"` // id
	GC    string        `bson:"GC"`           // 商品代码
	ST    int           `json:"-" bson:"ST"`  // 时间戳
	SST   string        `bson:"SST"`          // 时间文本
	Open  int           `bson:"Open"`         // 开盘价
	High  int           `bson:"High"`         // 最高价
	Low   int           `bson:"Low"`          // 最低价
	Close int           `bson:"Close"`        // 收盘价
	TV    int           `bson:"TV"`           // 总量
	TT    int           `bson:"TT"`           // 总金额
	HV    int           `bson:"HV"`           // 持仓量
	SP    int           `bson:"SP"`           // 结算价，日线周期（包括）以上才有
}

// Quoteday 行情盘面
type Quoteday struct {
	Id                   int64   `xorm:"pk autoincr BIGINT(20)"`
	Exchangedate         int64   `xorm:"not null BIGINT(20)"`
	Goodscode            string  `xorm:"not null unique CHAR(10)"`
	Exchangecode         int     `xorm:"INT(11)"`
	Preclose             int64   `xorm:"default 0 BIGINT(20)"`
	Opentime             int64   `xorm:"BIGINT(20)"`
	Opened               int64   `xorm:"not null default 0 BIGINT(20)"`
	Highest              int64   `xorm:"not null default 0 BIGINT(20)"`
	Lowest               int64   `xorm:"not null default 0 BIGINT(20)"`
	Lasttime             string  `xorm:"VARCHAR(20)"`
	Utclasttime          int64   `xorm:"not null BIGINT(20)"`
	Last                 int64   `xorm:"not null BIGINT(20)"`
	Lastvolume           int64   `xorm:"default 0 BIGINT(20)"`
	Lastturnover         int64   `xorm:"default 0 BIGINT(20)"`
	Totalbidvolume       int64   `xorm:"default 0 BIGINT(20)"`
	Totalaskvolume       int64   `xorm:"default 0 BIGINT(20)"`
	Totalvolume          int64   `xorm:"default 0 BIGINT(20)"`
	Totalturnover        int64   `xorm:"default 0 BIGINT(20)"`
	Bid                  int64   `xorm:"default 0 BIGINT(20)"`
	Bid2                 int64   `xorm:"default 0 BIGINT(20)"`
	Bid3                 int64   `xorm:"default 0 BIGINT(20)"`
	Bid4                 int64   `xorm:"default 0 BIGINT(20)"`
	Bid5                 int64   `xorm:"default 0 BIGINT(20)"`
	Bidvolume            int64   `xorm:"default 0 BIGINT(20)"`
	Bidvolume2           int64   `xorm:"default 0 BIGINT(20)"`
	Bidvolume3           int64   `xorm:"default 0 BIGINT(20)"`
	Bidvolume4           int64   `xorm:"default 0 BIGINT(20)"`
	Bidvolume5           int64   `xorm:"default 0 BIGINT(20)"`
	Ask                  int64   `xorm:"default 0 BIGINT(20)"`
	Ask2                 int64   `xorm:"default 0 BIGINT(20)"`
	Ask3                 int64   `xorm:"default 0 BIGINT(20)"`
	Ask4                 int64   `xorm:"default 0 BIGINT(20)"`
	Ask5                 int64   `xorm:"default 0 BIGINT(20)"`
	Askvolume            int64   `xorm:"default 0 BIGINT(20)"`
	Askvolume2           int64   `xorm:"default 0 BIGINT(20)"`
	Askvolume3           int64   `xorm:"default 0 BIGINT(20)"`
	Askvolume4           int64   `xorm:"default 0 BIGINT(20)"`
	Askvolume5           int64   `xorm:"default 0 BIGINT(20)"`
	Presettle            int64   `xorm:"default 0 BIGINT(20)"`
	Settle               int64   `xorm:"default 0 BIGINT(20)"`
	Preholdvolume        int64   `xorm:"default 0 BIGINT(20)"`
	Holdvolume           int64   `xorm:"default 0 BIGINT(20)"`
	Averageprice         int64   `xorm:"default 0 BIGINT(20)"`
	Orderid              int64   `xorm:"default 0 BIGINT(20)"`
	Limitup              int64   `xorm:"default 0 BIGINT(20)"`
	Limitdown            int64   `xorm:"default 0 BIGINT(20)"`
	Inventory            int64   `xorm:"default 0 BIGINT(20)"`
	Holdincrement        int64   `xorm:"default 0 BIGINT(20)"`
	Iscleared            int     `xorm:"INT(11)"`
	Issettled            int     `xorm:"INT(11)"`
	Hightime             string  `xorm:"VARCHAR(30)"`
	Lowtime              string  `xorm:"VARCHAR(30)"`
	Bidqueueinfo         string  `xorm:"VARCHAR(2000)"`
	Askqueueinfo         string  `xorm:"VARCHAR(2000)"`
	Bidorderid           int64   `xorm:"BIGINT(20)"`
	Bidorderid2          int64   `xorm:"BIGINT(20)"`
	Bidorderid3          int64   `xorm:"BIGINT(20)"`
	Bidorderid4          int64   `xorm:"BIGINT(20)"`
	Bidorderid5          int64   `xorm:"BIGINT(20)"`
	Askorderid           int64   `xorm:"BIGINT(20)"`
	Askorderid2          int64   `xorm:"BIGINT(20)"`
	Askorderid3          int64   `xorm:"BIGINT(20)"`
	Askorderid4          int64   `xorm:"BIGINT(20)"`
	Askorderid5          int64   `xorm:"BIGINT(20)"`
	Originalturnover     float64 `xorm:"default 0 DOUBLE"`
	Lastlot              int64   `xorm:"BIGINT(20)"`
	Totallot             int64   `xorm:"BIGINT(20)"`
	Strikeprice          int64   `xorm:"BIGINT(20)"`
	Cleartime            int64   `xorm:"BIGINT(20)"`
	Calloptionpremiums   int64   `xorm:"default 0 BIGINT(20)"`
	Calloptionpremiums2  int64   `xorm:"default 0 BIGINT(20)"`
	Calloptionpremiums3  int64   `xorm:"default 0 BIGINT(20)"`
	Calloptionpremiums4  int64   `xorm:"default 0 BIGINT(20)"`
	Calloptionpremiums5  int64   `xorm:"default 0 BIGINT(20)"`
	Putoptionpremiums    int64   `xorm:"default 0 BIGINT(20)"`
	Putoptionpremiums2   int64   `xorm:"default 0 BIGINT(20)"`
	Putoptionpremiums3   int64   `xorm:"default 0 BIGINT(20)"`
	Putoptionpremiums4   int64   `xorm:"default 0 BIGINT(20)"`
	Putoptionpremiums5   int64   `xorm:"default 0 BIGINT(20)"`
	Nontotalvolume       int64   `xorm:"default 0 BIGINT(20)"`
	Nontotalholdervolume int64   `xorm:"default 0 BIGINT(20)"`
	Nontotalturnover     int64   `xorm:"default 0 BIGINT(20)"`
	Nontotallot          int64   `xorm:"default 0 BIGINT(20)"`
	Markprice            int64   `xorm:"default 0 BIGINT(20)"`
	Fundsrate            int64   `xorm:"default 0 BIGINT(20)"`
	Publictradetype      string  `xorm:"VARCHAR(2)"`
	Iep                  int64   `xorm:"default 0 BIGINT(20)"`
	Iev                  int64   `xorm:"default 0 BIGINT(20)"`
	Grepmarketprice      int64   `xorm:"default 0 BIGINT(20)"`
	Bid6                 int64   `xorm:"default 0 BIGINT(20)"`
	Bid7                 int64   `xorm:"default 0 BIGINT(20)"`
	Bid8                 int64   `xorm:"default 0 BIGINT(20)"`
	Bid9                 int64   `xorm:"default 0 BIGINT(20)"`
	Bid10                int64   `xorm:"default 0 BIGINT(20)"`
	Bidvolume6           int64   `xorm:"default 0 BIGINT(20)"`
	Bidvolume7           int64   `xorm:"default 0 BIGINT(20)"`
	Bidvolume8           int64   `xorm:"default 0 BIGINT(20)"`
	Bidvolume9           int64   `xorm:"default 0 BIGINT(20)"`
	Bidvolume10          int64   `xorm:"default 0 BIGINT(20)"`
	Ask6                 int64   `xorm:"default 0 BIGINT(20)"`
	Ask7                 int64   `xorm:"default 0 BIGINT(20)"`
	Ask8                 int64   `xorm:"default 0 BIGINT(20)"`
	Ask9                 int64   `xorm:"default 0 BIGINT(20)"`
	Ask10                int64   `xorm:"default 0 BIGINT(20)"`
	Askvolume6           int64   `xorm:"default 0 BIGINT(20)"`
	Askvolume7           int64   `xorm:"default 0 BIGINT(20)"`
	Askvolume8           int64   `xorm:"default 0 BIGINT(20)"`
	Askvolume9           int64   `xorm:"default 0 BIGINT(20)"`
	Askvolume10          int64   `xorm:"default 0 BIGINT(20)"`
	Bidordervolume       int64   `xorm:"default 0 BIGINT(20)"`
	Bidordervolume2      int64   `xorm:"default 0 BIGINT(20)"`
	Bidordervolume3      int64   `xorm:"default 0 BIGINT(20)"`
	Bidordervolume4      int64   `xorm:"default 0 BIGINT(20)"`
	Bidordervolume5      int64   `xorm:"default 0 BIGINT(20)"`
	Bidordervolume6      int64   `xorm:"default 0 BIGINT(20)"`
	Bidordervolume7      int64   `xorm:"default 0 BIGINT(20)"`
	Bidordervolume8      int64   `xorm:"default 0 BIGINT(20)"`
	Bidordervolume9      int64   `xorm:"default 0 BIGINT(20)"`
	Bidordervolume10     int64   `xorm:"default 0 BIGINT(20)"`
	Askordervolume       int64   `xorm:"default 0 BIGINT(20)"`
	Askordervolume2      int64   `xorm:"default 0 BIGINT(20)"`
	Askordervolume3      int64   `xorm:"default 0 BIGINT(20)"`
	Askordervolume4      int64   `xorm:"default 0 BIGINT(20)"`
	Askordervolume5      int64   `xorm:"default 0 BIGINT(20)"`
	Askordervolume6      int64   `xorm:"default 0 BIGINT(20)"`
	Askordervolume7      int64   `xorm:"default 0 BIGINT(20)"`
	Askordervolume8      int64   `xorm:"default 0 BIGINT(20)"`
	Askordervolume9      int64   `xorm:"default 0 BIGINT(20)"`
	Askordervolume10     int64   `xorm:"default 0 BIGINT(20)"`
}

// TableName is Quoteday
func (*Quoteday) TableName() string {
	return "Quoteday"
}

// GetHistoryCycleDatas 获取历史数据
// 参数 cycleType CycleType 周期类型
// 参数 goodsCode string 商品代码
// 参数 startTime time.Time 开始时间（闭区间）
// 参数 endTime time.Time 结束时间（闭区间）
// 参数 count int 条数
// 参数 isAscForST bool 是否按时间顺序排序，默认为时间倒序排序
// 返回值 []CycleData 历史数据
// 返回值 error 错误
func GetHistoryCycleDatas(cycleType CycleType, goodsCode string, startTime, endTime *time.Time, count int, isAscForST bool) ([]CycleData, error) {
	db := db.GetMongoDB()

	// 获取目标Collection
	collection := "mincycle"
	switch cycleType {
	case CycleTypeSecond:
		collection = "quotetik"
	case CycleTypeMinutes1:
		collection = "mincycle"
	case CycleTypeMinutes5:
		collection = "min5cycle"
	case CycleTypeMinutes30:
		collection = "min30cycle"
	case CycleTypeMinutesDay:
		collection = "daycycle"
	default:
		return nil, errors.New("不支持的周期类型")
	}
	c := db.C(collection)

	// 按时间排序
	sort := "-ST"
	if isAscForST {
		sort = "ST"
	}

	// 查询数据
	var cycleDatas []CycleData
	m := bson.M{"GC": goodsCode}
	if startTime != nil && endTime == nil {
		m["ST"] = bson.M{"$gte": startTime.Unix()}
	} else if startTime == nil && endTime != nil {
		m["ST"] = bson.M{"$lte": endTime.Unix()}
	} else if startTime != nil && endTime != nil {
		m["ST"] = bson.M{"$gte": startTime.Unix(), "$lte": endTime.Unix()}
	}
	query := c.Find(m)
	if count > 0 {
		query = query.Limit(count)
	}
	if err := query.Sort(sort).All(&cycleDatas); err != nil {
		return nil, err
	}

	return cycleDatas, nil
}

// GetQuoteDays 获取目标商品的盘面数据
// 参数 goodsCodes string 商品代码字串，以“,”分隔
// 返回 []Quoteday 盘面数据
// 返回 error error
func GetQuoteDays(goodsCodes string) ([]Quoteday, error) {
	engine := db.GetMySQLEngine()

	datas := make([]Quoteday, 0)
	// if err := engine.Where(fmt.Sprintf("goodscode in ('%s')", goodsCodes)).Find(&datas); err != nil {
	if err := engine.Find(&datas); err != nil {
		return nil, err
	}

	return datas, nil
}
