package models

import (
	"eta/eta_index_lib/utils"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"strconv"
	"strings"
	"time"
)

type BaseFromTradeShfeIndex struct {
	BaseFromTradeShfeIndexId int `orm:"column(base_from_trade_ine_index_id);pk"`
	Rank                     int
	DealShortName            string
	DealName                 string
	DealCode                 string
	DealValue                string
	DealChange               int
	BuyShortName             string
	BuyName                  string
	BuyCode                  string
	BuyValue                 string
	BuyChange                int
	SoldShortName            string
	SoldName                 string
	SoldCode                 string
	SoldValue                string
	SoldChange               int
	Frequency                string
	ClassifyName             string
	ClassifyType             string
	CreateTime               time.Time
	ModifyTime               time.Time
	DataTime                 string
}

func GetBaseFromShfeDataAllByIndexCode(indexCode, suffix string) (list []*BaseFromTradeShfeIndex, err error) {
	o := orm.NewOrm()
	sql := `SELECT * FROM base_from_trade_ine_index WHERE %s_code=? `
	sql = fmt.Sprintf(sql, suffix)
	_, err = o.Raw(sql, indexCode).QueryRows(&list)
	return
}

type BaseFromShfeDataSimple struct {
	Id        int `orm:"column(base_from_trade_ine_index_id);pk"`
	DealCode  string
	BuyCode   string
	SoldCode  string
	DataTime  string
	DealValue string
	BuyValue  string
	SoldValue string
}

func GetShfeDataByTradeCode(condition string, pars []interface{}) (item []*BaseFromShfeDataSimple, err error) {
	sql := ` SELECT * FROM base_from_trade_ine_index WHERE 1=1 `
	o := orm.NewOrm()
	if condition != "" {
		sql += condition
	}
	sql += ` ORDER BY data_time DESC `
	_, err = o.Raw(sql, pars).QueryRows(&item)
	return
}

// 新增上期能源指标数据
func AddEdbDataFromShfe(edbCode string) (err error) {
	var suffix string
	if strings.Contains(edbCode, "deal") {
		suffix = "deal"
	} else if strings.Contains(edbCode, "buy") {
		suffix = "buy"
	} else if strings.Contains(edbCode, "sold") {
		suffix = "sold"
	}
	o := orm.NewOrm()
	ineBaseDataAll, err := GetBaseFromShfeDataAllByIndexCode(edbCode, suffix)
	if err != nil && err.Error() != utils.ErrNoRow() {
		return
	}

	var isAdd bool
	addSql := ` INSERT INTO edb_data_ine(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
	existMap := make(map[string]string)

	for _, sv := range ineBaseDataAll {
		eDate := sv.DataTime
		dataTime, err := time.ParseInLocation(utils.FormatDate, eDate, time.Local)
		if err != nil {
			fmt.Println("time.Parse Err:" + eDate)
			return err
		}
		timestamp := dataTime.UnixNano() / 1e6
		timeStr := fmt.Sprintf("%d", timestamp)
		if _, ok := existMap[eDate]; !ok {
			if suffix == "deal" {
				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.DealValue)
			} else if suffix == "buy" {
				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.BuyValue)
			} else {
				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.SoldValue)
			}
			isAdd = true
		}
		if suffix == "deal" {
			existMap[eDate] = sv.DealValue
		} else if suffix == "buy" {
			existMap[eDate] = sv.BuyValue
		} else {
			existMap[eDate] = sv.SoldValue
		}
	}
	if isAdd {
		addSql = strings.TrimRight(addSql, ",")
		utils.FileLog.Info("addSql:" + addSql)
		_, err = o.Raw(addSql).Exec()
		if err != nil {
			return err
		}
	}
	return
}

// 刷新上期能源指标数据
func RefreshEdbDataFromShfe(edbInfoId int, edbCode, startDate string) (err error) {
	source := utils.DATA_SOURCE_SHFE
	subSource := utils.DATA_SUB_SOURCE_EDB

	o := orm.NewOrm()
	if err != nil {
		return
	}
	var suffix string
	if strings.Contains(edbCode, "deal") {
		suffix = "deal"
	} else if strings.Contains(edbCode, "buy") {
		suffix = "buy"
	} else if strings.Contains(edbCode, "sold") {
		suffix = "sold"
	}
	edbInfoIdStr := strconv.Itoa(edbInfoId)
	//计算数据
	var condition string
	var pars []interface{}

	if edbCode != "" {
		if suffix == "deal" {
			condition += " AND deal_code=? "
		} else if suffix == "buy" {
			condition += " AND buy_code=? "
		} else {
			condition += " AND sold_code=? "
		}
		pars = append(pars, edbCode)
	}

	if startDate != "" {
		condition += " AND data_time>=? "
		pars = append(pars, startDate)
	}

	glDataList, err := GetShfeDataByTradeCode(condition, pars)
	if err != nil {
		return
	}

	// 真实数据的最大日期  , 插入规则配置的日期
	var realDataMaxDate, edbDataInsertConfigDate time.Time
	var edbDataInsertConfig *EdbDataInsertConfig
	var isFindConfigDateRealData bool //是否找到配置日期的实际数据的值
	{
		edbDataInsertConfig, err = GetEdbDataInsertConfigByEdbId(edbInfoId)
		if err != nil && err.Error() != utils.ErrNoRow() {
			return
		}
		if edbDataInsertConfig != nil {
			edbDataInsertConfigDate = edbDataInsertConfig.Date
		}
	}

	//获取指标所有数据
	var existCondition string
	var existPars []interface{}

	existCondition += " AND edb_info_id=? "
	existPars = append(existPars, edbInfoId)
	if startDate != "" {
		existCondition += " AND data_time>=? "
		existPars = append(existPars, startDate)
	}

	existList, err := GetEdbDataByCondition(source, subSource, existCondition, existPars)
	if err != nil {
		return err
	}
	existMap := make(map[string]*EdbInfoSearchData)
	for _, v := range existList {
		existMap[v.DataTime] = v
	}

	addSql := ` INSERT INTO edb_data_ine(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
	var isAdd bool
	for _, v := range glDataList {
		var value string
		if suffix == "deal" {
			value = v.DealValue
		} else if suffix == "buy" {
			value = v.BuyValue
		} else {
			value = v.SoldValue
		}
		item := v
		itemValue := value
		eDate := item.DataTime
		dataTime, err := time.ParseInLocation(utils.FormatDate, eDate, time.Local)
		if err != nil {
			return err
		}
		if _, ok := existMap[v.DataTime]; !ok {
			sValue := itemValue
			if sValue != "" {
				timestamp := dataTime.UnixNano() / 1e6
				timeStr := fmt.Sprintf("%d", timestamp)
				saveValue := sValue

				if findItem, ok := existMap[eDate]; !ok {
					addSql += GetAddSql(edbInfoIdStr, edbCode, eDate, timeStr, saveValue)
					isAdd = true
				} else {
					if findItem != nil && utils.SubFloatToString(findItem.Value, 30) != saveValue {
						err = ModifyEdbDataById(source, subSource, findItem.EdbDataId, saveValue)
						if err != nil {
							return err
						}
					}
				}
			}
		}

		// 下面代码主要目的是处理掉手动插入的数据判断
		{
			if realDataMaxDate.IsZero() || dataTime.After(realDataMaxDate) {
				realDataMaxDate = dataTime
			}
			if edbDataInsertConfigDate.IsZero() || dataTime.Equal(edbDataInsertConfigDate) {
				isFindConfigDateRealData = true
			}
		}
	}

	// 处理手工数据补充的配置
	HandleConfigInsertEdbData(realDataMaxDate, edbDataInsertConfig, edbInfoId, source, subSource, existMap, isFindConfigDateRealData)

	if isAdd {
		addSql = strings.TrimRight(addSql, ",")
		_, err = o.Raw(addSql).Exec()
		if err != nil {
			return err
		}
	}
	return
}

type BaseFromTradeIneIndex struct {
	BaseFromTradeIneIndexId int `orm:"column(base_from_trade_ine_index_id);pk"`
	Rank                    int
	DealShortName           string
	DealName                string
	DealCode                string
	DealValue               int
	DealChange              int
	BuyShortName            string
	BuyName                 string
	BuyCode                 string
	BuyValue                int
	BuyChange               int
	SoldShortName           string
	SoldName                string
	SoldCode                string
	SoldValue               int
	SoldChange              int
	Frequency               string
	ClassifyName            string
	ClassifyType            string
	CreateTime              time.Time
	ModifyTime              time.Time
	DataTime                string
}

type BaseFromTradeMapping struct {
	BaseFromTradeMappingId int `orm:"column(base_from_trade_mapping_id);pk"`
	IndexName              string
	IndexCode              string
	Exchange               string
}

func AddBaseFromTradeIneIndex(item *BaseFromTradeIneIndex) (lastId int64, err error) {
	o := orm.NewOrm()
	lastId, err = o.Insert(item)
	return
}

func GetBaseFromTradeIneIndexAll(dateStr string) (list []*BaseFromTradeIneIndex, err error) {
	o := orm.NewOrm()
	sql := `SELECT * FROM base_from_trade_ine_index where data_time=?`
	_, err = o.Raw(sql, dateStr).QueryRows(&list)
	return
}

func ModifyBaseFromTradeIneIndex(dealValue, buyValue, soldValue int, dataId int) (err error) {
	o := orm.NewOrm()
	sql := `UPDATE base_from_trade_ine_index SET deal_value=?,buy_value=?,sold_value=?,modify_time=NOW() WHERE base_from_trade_ine_index_id=? `
	_, err = o.Raw(sql, dealValue, buyValue, soldValue, dataId).Exec()
	return
}

func GetIndexCodeFromMapping(exchange string) (list []*BaseFromTradeMapping, err error) {
	o := orm.NewOrm()
	sql := `SELECT * FROM base_from_trade_mapping where exchange=?`
	_, err = o.Raw(sql, exchange).QueryRows(&list)
	return
}

func AddBaseFromTradeMapping(indexName, indexCode, exchange string) (err error) {
	o := orm.NewOrm()
	sql := "Insert Into base_from_trade_mapping(index_name,index_code,exchange) Values('" + indexName + "','" + indexCode + "','" + exchange + "')"
	_, err = o.Raw(sql).Exec()
	return
}

type RefreshINEExchangeReq struct {
	Date string `description:"日期"`
	Data IneJSONData
}

type IneJSONData struct {
	OCursor    []OCursor   `json:"o_cursor"`
	OCode      interface{} `json:"o_code"`
	OMsg       string      `json:"o_msg"`
	ReportDate string      `json:"report_date"`
	UpdateDate string      `json:"update_date"`
}
type OCursor struct {
	Instrumentid     string      `json:"INSTRUMENTID"`
	Participantid3   string      `json:"PARTICIPANTID3"`
	Participantid2   string      `json:"PARTICIPANTID2"`
	Participantid1   string      `json:"PARTICIPANTID1"`
	Participantabbr3 string      `json:"PARTICIPANTABBR3"`
	Participantabbr2 string      `json:"PARTICIPANTABBR2"`
	Rank             int         `json:"RANK"`
	Participantabbr1 string      `json:"PARTICIPANTABBR1"`
	BuyIn            interface{} `json:"CJ2"`
	Deal             interface{} `json:"CJ1"`
	Change1          interface{} `json:"CJ1_CHG"`
	Change3          interface{} `json:"CJ3_CHG"`
	Productname      string      `json:"Productname"`
	Productsortno    interface{} `json:"PRODUCTSORTNO"`
	SoldOut          interface{} `json:"CJ3"`
	Change2          interface{} `json:"CJ2_CHG"`
}