package trade_analysis

import (
	"encoding/json"
	"eta/eta_api/models/data_manage"
	"eta/eta_api/models/data_manage/chart_theme"
	tradeAnalysisModel "eta/eta_api/models/data_manage/trade_analysis"
	"eta/eta_api/services/data"
	"eta/eta_api/utils"
	"fmt"
	"strconv"
	"strings"
	"time"
)

// CheckWarehouseChartExtraConfig 校验持仓分析图表参数
func CheckWarehouseChartExtraConfig(extraConfig tradeAnalysisModel.WarehouseExtraConfig) (pass bool, tips string) {
	if extraConfig.Exchange == "" {
		tips = "请选择交易所"
		return
	}
	if extraConfig.ClassifyName == "" {
		tips = "请选择品种"
		return
	}
	if len(extraConfig.Contracts) == 0 {
		tips = "请选择合约"
		return
	}
	if len(extraConfig.Companies) == 0 {
		tips = "请选择期货公司"
		return
	}
	if len(extraConfig.Companies) > 5 {
		tips = "最多可选5个期货公司"
		return
	}
	if extraConfig.PredictRatio < 0 || extraConfig.PredictRatio > 1 {
		tips = "请输入正确的估计参数"
		return
	}
	pass = true
	return
}

func GetWarehouseChartResp(chartView *data_manage.ChartInfoView, companyTradeData []*tradeAnalysisModel.ContractCompanyTradeData, multiEdb []*tradeAnalysisModel.WarehouseEdbSaveItem, extraConfig tradeAnalysisModel.WarehouseExtraConfig, chartConfig tradeAnalysisModel.WarehouseChartPars) (chartResp *data_manage.ChartInfoDetailResp, err error) {
	edbMappings, defaultChartName, e := FormatCompanyTradeData2EdbMappings(companyTradeData, chartConfig.WarehouseChartType, chartConfig.DateType, chartConfig.DateTypeNum, chartConfig.StartDate, chartConfig.EndDate, chartConfig.ChartEdbInfoList)
	if e != nil {
		err = fmt.Errorf("多单数据转为指标失败, %v", e)
		return
	}
	// chartView为空表示为预览图, 有则表示为详情图
	var chartThemeId int
	chartType := utils.CHART_TYPE_CURVE // 曲线图
	if chartView == nil {
		// 图表样式/主题
		chartThemeType, e := chart_theme.GetChartThemeTypeByChartTypeAndSource(chartType, utils.CHART_SOURCE_DEFAULT)
		if e != nil {
			err = fmt.Errorf("获取图表类型失败, %v", e)
			return
		}
		chartThemeId = chartThemeType.DefaultChartThemeId

		chartView = new(data_manage.ChartInfoView)
		chartView.ChartType = chartType
		chartView.Source = utils.CHART_SOURCE_TRADE_ANALYSIS_PROCESS
		chartView.ChartName = defaultChartName
		chartView.ChartNameEn = defaultChartName
	} else {
		chartThemeId = chartView.ChartThemeId
	}
	chartView.DateType = chartConfig.DateType
	chartView.DateTypeNum = chartConfig.DateTypeNum
	chartView.StartDate = chartConfig.StartDate
	chartView.EndDate = chartConfig.EndDate
	chartTheme, e := data.GetChartThemeConfig(chartThemeId, utils.CHART_SOURCE_DEFAULT, chartType)
	if e != nil {
		err = fmt.Errorf("获取图表主题失败, %v", e)
		return
	}
	chartView.ChartThemeId = chartTheme.ChartThemeId
	chartView.ChartThemeStyle = chartTheme.Config

	chartResp = new(data_manage.ChartInfoDetailResp)
	chartResp.ChartInfo = chartView
	chartResp.EdbInfoList = edbMappings
	dataResp := tradeAnalysisModel.WarehouseChartDataResp{WarehouseExtraConfig: extraConfig, MultiEdbMappings: multiEdb}
	dataResp.WarehouseChartType = chartConfig.WarehouseChartType
	chartResp.DataResp = dataResp
	return
}

// AddWarehouseChart 添加持仓分析图表
func AddWarehouseChart(req data_manage.AddChartInfoReq, extraConfig tradeAnalysisModel.WarehouseExtraConfig, adminId int, adminRealName string) (chartInfo *data_manage.ChartInfo, err error) {
	// 图表信息
	chartInfo = new(data_manage.ChartInfo)
	chartInfo.ChartName = req.ChartName
	chartInfo.ChartNameEn = req.ChartName
	chartInfo.ChartClassifyId = req.ChartClassifyId
	chartInfo.SysUserId = adminId
	chartInfo.SysUserRealName = adminRealName
	chartInfo.CreateTime = time.Now()
	chartInfo.ModifyTime = time.Now()
	chartInfo.IsSetName = 0
	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
	chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp)
	chartInfo.ChartType = utils.CHART_TYPE_CURVE
	chartInfo.Calendar = "公历"
	chartInfo.DateType = req.DateType
	chartInfo.StartDate = req.StartDate
	chartInfo.EndDate = req.EndDate
	chartInfo.SeasonStartDate = req.StartDate
	chartInfo.SeasonEndDate = req.EndDate
	chartInfo.LeftMin = req.LeftMin
	chartInfo.LeftMax = req.LeftMax
	chartInfo.RightMin = req.RightMin
	chartInfo.RightMax = req.RightMax
	chartInfo.Right2Min = req.Right2Min
	chartInfo.Right2Max = req.Right2Max
	chartInfo.Source = utils.CHART_SOURCE_TRADE_ANALYSIS_PROCESS
	chartInfo.ChartThemeId = req.ChartThemeId
	chartInfo.SourcesFrom = req.SourcesFrom
	chartInfo.Instructions = req.Instructions
	chartInfo.MarkersLines = req.MarkersLines
	chartInfo.MarkersAreas = req.MarkersAreas
	chartInfo.ExtraConfig = req.ExtraConfig
	chartInfo.DateTypeNum = req.DateTypeNum
	chartInfo.MinMaxSave = req.MinMaxSave

	// 图例信息-由于持仓分析图表无指标, 图例信息就不存在chart_edb_mapping里了, 而是chart_series
	seriesList := make([]*data_manage.ChartSeries, 0)
	for _, v := range req.ChartEdbInfoList {
		t := new(data_manage.ChartSeries)
		t.SeriesName = v.EdbAliasName
		t.SeriesNameEn = v.EdbAliasName
		t.IsAxis = v.IsAxis
		t.UniqueFlag = v.UniqueFlag
		t.CreateTime = time.Now().Local()
		t.ModifyTime = time.Now().Local()
		seriesList = append(seriesList, t)
	}

	// 图表关联多图配置
	multiChartMapping := new(data_manage.MultipleGraphConfigChartMapping)
	if extraConfig.MultipleGraphConfigId > 0 {
		multiChartMapping.MultipleGraphConfigId = extraConfig.MultipleGraphConfigId
		multiChartMapping.Source = utils.CHART_SOURCE_TRADE_ANALYSIS_PROCESS
		multiChartMapping.CreateTime = time.Now().Local()
		multiChartMapping.ModifyTime = time.Now().Local()
	}

	// 新增
	if e := tradeAnalysisModel.CreateWarehouseChart(chartInfo, seriesList, multiChartMapping); e != nil {
		err = fmt.Errorf("新增图表失败, %v", e)
		return
	}

	// 添加es数据
	go data.EsAddOrEditChartInfo(chartInfo.ChartInfoId)
	return
}

// EditWarehouseChart 编辑持仓分析图表
func EditWarehouseChart(req data_manage.EditChartInfoReq) (chartItem *data_manage.ChartInfo, err error) {
	// 更新图表
	e := data_manage.EditChartInfoAndMapping(&req, "", "公历", req.DateType, 0, ``, make([]*data_manage.ChartSaveItem, 0), "")
	if e != nil {
		err = fmt.Errorf("更新图表失败, %v", e)
		return
	}
	chartItem, e = data_manage.GetChartInfoById(req.ChartInfoId)
	if e != nil {
		err = fmt.Errorf("获取更新后的图表失败, %v", e)
		return
	}

	// 替换原图例
	if e = data_manage.DeleteChartSeriesAndEdbMapping(req.ChartInfoId); e != nil {
		err = fmt.Errorf("删除原图例失败, %v", e)
		return
	}
	seriesList := make([]*data_manage.ChartSeries, 0)
	for _, v := range req.ChartEdbInfoList {
		t := new(data_manage.ChartSeries)
		t.SeriesName = v.EdbAliasName
		t.SeriesNameEn = v.EdbAliasName
		t.ChartInfoId = chartItem.ChartInfoId
		t.IsAxis = v.IsAxis
		t.UniqueFlag = v.UniqueFlag
		t.CreateTime = time.Now().Local()
		t.ModifyTime = time.Now().Local()
		seriesList = append(seriesList, t)
	}
	if len(seriesList) > 0 {
		seriesOb := new(data_manage.ChartSeries)
		if e = seriesOb.CreateMulti(seriesList); e != nil {
			err = fmt.Errorf("新增图例失败, %v", e)
			return
		}
	}

	// 更新ES
	go func() {
		data.EsAddOrEditChartInfo(chartItem.ChartInfoId)
		data.EsAddOrEditMyChartInfoByChartInfoId(chartItem.ChartInfoId)
	}()
	return
}

// CopyWarehouseChart 复制持仓分析图表
func CopyWarehouseChart(classifyId int, chartName string, originChart *data_manage.ChartInfo, adminId int, adminRealName string) (chartInfo *data_manage.ChartInfo, err error) {
	var extraConfig tradeAnalysisModel.WarehouseExtraConfig
	if e := json.Unmarshal([]byte(originChart.ExtraConfig), &extraConfig); e != nil {
		err = fmt.Errorf("图表配置有误, %v", e)
		return
	}

	// 新增配置并绑定图表
	multiConfigCopy := &data_manage.MultipleGraphConfig{
		SysUserId:       adminId,
		SysUserRealName: adminRealName,
		ModifyTime:      time.Now(),
		CreateTime:      time.Now(),
	}
	if e := data_manage.AddMultipleGraphConfig(multiConfigCopy); e != nil {
		err = fmt.Errorf("新增持仓分析多图配置失败, %v", e)
		return
	}
	extraConfig.MultipleGraphConfigId = multiConfigCopy.MultipleGraphConfigId
	configByte, e := json.Marshal(extraConfig)
	if e != nil {
		err = fmt.Errorf("图表配置格式化失败, %v", e)
		return
	}

	// 新增图表
	chartInfo = &data_manage.ChartInfo{
		ChartName:         chartName,
		ChartClassifyId:   classifyId,
		SysUserId:         adminId,
		SysUserRealName:   adminRealName,
		UniqueCode:        utils.MD5(utils.CHART_PREFIX + "_" + strconv.FormatInt(time.Now().UnixNano(), 10)),
		CreateTime:        time.Now(),
		ModifyTime:        time.Now(),
		DateType:          originChart.DateType,
		StartDate:         originChart.StartDate,
		EndDate:           originChart.EndDate,
		IsSetName:         originChart.IsSetName,
		EdbInfoIds:        originChart.EdbInfoIds,
		ChartType:         originChart.ChartType,
		Calendar:          originChart.Calendar,
		SeasonStartDate:   originChart.SeasonStartDate,
		SeasonEndDate:     originChart.SeasonEndDate,
		ChartImage:        originChart.ChartImage,
		BarConfig:         originChart.BarConfig,
		LeftMin:           originChart.LeftMin,
		LeftMax:           originChart.LeftMax,
		RightMin:          originChart.RightMin,
		RightMax:          originChart.RightMax,
		Right2Min:         originChart.Right2Min,
		Right2Max:         originChart.Right2Max,
		Disabled:          originChart.Disabled,
		Source:            originChart.Source,
		ExtraConfig:       string(configByte),
		SeasonExtraConfig: originChart.SeasonExtraConfig,
		StartYear:         originChart.StartYear,
		Unit:              originChart.Unit,
		UnitEn:            originChart.UnitEn,
		ChartThemeId:      originChart.ChartThemeId,
		SourcesFrom:       originChart.SourcesFrom,
		Instructions:      originChart.Instructions,
		MarkersLines:      originChart.MarkersLines,
		MarkersAreas:      originChart.MarkersAreas,
		DateTypeNum:       originChart.DateTypeNum,
	}

	// 图例信息
	seriesList, e := data_manage.GetChartSeriesByChartInfoId(originChart.ChartInfoId)
	if e != nil {
		err = fmt.Errorf("获取图例信息失败, %v", e)
		return
	}
	seriesCopy := make([]*data_manage.ChartSeries, 0)
	for _, v := range seriesList {
		t := new(data_manage.ChartSeries)
		t.SeriesName = v.SeriesName
		t.SeriesNameEn = v.SeriesNameEn
		t.IsAxis = v.IsAxis
		t.UniqueFlag = v.UniqueFlag
		t.CreateTime = time.Now().Local()
		t.ModifyTime = time.Now().Local()
		seriesCopy = append(seriesCopy, t)
	}

	// 新增图表-多图配置关联
	configChartMapping := &data_manage.MultipleGraphConfigChartMapping{
		MultipleGraphConfigId: multiConfigCopy.MultipleGraphConfigId,
		Source:                utils.CHART_SOURCE_TRADE_ANALYSIS_PROCESS,
		ModifyTime:            time.Now().Local(),
		CreateTime:            time.Now().Local(),
	}

	// 新增
	if e = tradeAnalysisModel.CreateWarehouseChart(chartInfo, seriesCopy, configChartMapping); e != nil {
		err = fmt.Errorf("新增图表失败, %v", e)
		return
	}

	// 新增ES
	go data.EsAddOrEditChartInfo(chartInfo.ChartInfoId)
	return
}

// CheckEdbSave 校验指标新增
func CheckEdbSave(extraConfig tradeAnalysisModel.WarehouseExtraConfig, multiEdbList []*data_manage.MultipleGraphConfigEdbMapping, IsSaveAs bool) (newEdbList []*tradeAnalysisModel.WarehouseEdbSaveItem, removeEdbIds []int, err error) {
	// 另存为或无关联指标时, 返回应当新增的全部指标列表
	newEdbList = make([]*tradeAnalysisModel.WarehouseEdbSaveItem, 0)
	suffixNames := tradeAnalysisModel.WarehouseTypeSuffixNames
	prefix := strings.Join(extraConfig.Contracts, "")
	if len(multiEdbList) == 0 || IsSaveAs {
		for _, v := range extraConfig.Companies {
			edb := new(tradeAnalysisModel.WarehouseEdbSaveItem)
			edb.EdbName = fmt.Sprintf("%s%s%s", prefix, v, suffixNames[extraConfig.WarehouseChartType])
			edb.Unit = tradeAnalysisModel.WarehouseDefaultUnit
			edb.Frequency = tradeAnalysisModel.WarehouseDefaultFrequency
			edb.UniqueFlag = v

			//conf := extraConfig
			//conf.Companies = []string{v}
			//b, e := json.Marshal(conf)
			//if e != nil {
			//	err = fmt.Errorf("指标配置JSON格式化异常, %v", e)
			//	return
			//}
			//edb.ExtraConfig = string(b)
			newEdbList = append(newEdbList, edb)
		}
		return
	}

	// 已有关联指标
	var edbIds []int
	for _, v := range multiEdbList {
		edbIds = append(edbIds, v.EdbInfoId)
	}
	if len(edbIds) == 0 {
		err = fmt.Errorf("关联指标IDs异常")
		return
	}
	warehouseType := extraConfig.WarehouseChartType

	// 获取已关联的指标信息
	edbList, e := data_manage.GetEdbInfoByIdList(edbIds)
	if e != nil {
		err = fmt.Errorf("获取指标信息失败, %v", e)
		return
	}

	// 只需要匹配期货公司即可, 合约数不匹配那么是不需要新增指标的
	existsMap := make(map[string]int) // [期货公司]:[指标ID]
	for _, v := range edbList {
		// 解析计算公式中的配置信息, 计算公式为空、解析失败的为异常需要移除绑定关系
		if v.CalculateFormula == "" {
			removeEdbIds = append(removeEdbIds, v.EdbInfoId)
			continue
		}
		var conf tradeAnalysisModel.WarehouseExtraConfig
		if e = json.Unmarshal([]byte(v.CalculateFormula), &conf); e != nil {
			utils.FileLog.Info("持仓分析图表-解析指标计算公式失败, EdbInfoId: %d, Conf: %s", v.EdbInfoId, v.CalculateFormula)
			removeEdbIds = append(removeEdbIds, v.EdbInfoId)
			continue
		}
		if len(conf.Companies) != 1 {
			utils.FileLog.Info("持仓分析图表-指标计算公式异常, EdbInfoId: %d, Conf: %s", v.EdbInfoId, v.CalculateFormula)
			removeEdbIds = append(removeEdbIds, v.EdbInfoId)
			continue
		}
		// 方向与配置中的方向不一致, 那么忽略
		if conf.WarehouseChartType != warehouseType {
			continue
		}
		existsMap[conf.Companies[0]] = v.EdbInfoId
	}

	// 配置中的, 不在已绑定中的需要新增
	confMap := make(map[string]bool) // [期货公司]:True
	for _, v := range extraConfig.Companies {
		confMap[v] = true
		if _, ok := existsMap[v]; !ok {
			// 需要新增的指标
			edb := new(tradeAnalysisModel.WarehouseEdbSaveItem)
			edb.EdbName = fmt.Sprintf("%s%s%s", prefix, v, suffixNames[extraConfig.WarehouseChartType])
			edb.Unit = tradeAnalysisModel.WarehouseDefaultUnit
			edb.Frequency = tradeAnalysisModel.WarehouseDefaultFrequency
			edb.UniqueFlag = v

			//conf := extraConfig
			//conf.Companies = []string{v}
			//b, e := json.Marshal(conf)
			//if e != nil {
			//	err = fmt.Errorf("指标配置JSON格式化异常, %v", e)
			//	return
			//}
			//edb.ExtraConfig = string(b)
			newEdbList = append(newEdbList, edb)
			continue
		}
	}

	// 已绑定的, 不在配置中的需要移除绑定
	for k, v := range existsMap {
		if _, ok := existsMap[k]; !ok {
			removeEdbIds = append(removeEdbIds, v)
			continue
		}
	}
	return
}