package models

import (
	"encoding/json"
	"errors"
	"eta/eta_index_lib/models/excel"
	"eta/eta_index_lib/utils"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/shopspring/decimal"
	"reflect"
	"strconv"
	"strings"
	"time"
)

// CustomAnalysis 自定义分析
type CustomAnalysis struct{}

// CustomAnalysisData 自定义分析的数据
type CustomAnalysisData struct {
	ExcelInfoId int `description:"excel的id"`
	DateList    []string
	DataList    []float64
}

// Add 添加
func (obj CustomAnalysis) Add(params AddCalculateBatchParams) (edbInfo *EdbInfo, err error, errMsg string) {
	req := params.Req
	edbCode := params.EdbCode

	// 自定义分析的数据集
	jsonByte, err := json.Marshal(req.Data)
	if err != nil {
		return
	}
	var customAnalysisData CustomAnalysisData
	err = json.Unmarshal(jsonByte, &customAnalysisData)
	if err != nil {
		return
	}

	o := orm.NewOrm()
	to, err := o.Begin()
	if err != nil {
		return
	}
	defer func() {
		if err != nil {
			_ = to.Rollback()
			fmt.Println(reflect.TypeOf(obj).Name(), "；Add,Err:"+err.Error())
		} else {
			_ = to.Commit()
		}
	}()

	edbInfo = new(EdbInfo)
	edbInfo.Source = obj.GetSource()
	edbInfo.SourceName = obj.GetSourceName()
	edbInfo.EdbCode = edbCode
	edbInfo.EdbName = req.EdbName
	edbInfo.EdbNameSource = req.EdbName
	edbInfo.Frequency = req.Frequency
	edbInfo.Unit = req.Unit
	edbInfo.ClassifyId = req.ClassifyId
	edbInfo.SysUserId = params.SysUserId
	edbInfo.SysUserRealName = params.SysUserRealName
	edbInfo.CreateTime = time.Now()
	edbInfo.ModifyTime = time.Now()
	edbInfo.UniqueCode = params.UniqueCode
	edbInfo.CalculateFormula = req.Formula
	edbInfo.EdbNameEn = req.EdbName
	edbInfo.UnitEn = req.Unit
	edbInfo.EdbType = 2
	newEdbInfoId, tmpErr := to.Insert(edbInfo)
	if tmpErr != nil {
		err = tmpErr
		return
	}
	edbInfo.EdbInfoId = int(newEdbInfoId)

	//关联关系
	{
		excelEdbMappingItem := new(excel.ExcelEdbMapping)
		excelEdbMappingItem.CreateTime = time.Now()
		excelEdbMappingItem.ModifyTime = time.Now()
		excelEdbMappingItem.ExcelInfoId = customAnalysisData.ExcelInfoId
		excelEdbMappingItem.Source = 4
		excelEdbMappingItem.EdbInfoId = edbInfo.EdbInfoId
		_, err = to.Insert(excelEdbMappingItem)
		if err != nil {
			return
		}
	}

	//计算数据
	err = obj.refresh(to, edbInfo, customAnalysisData.DateList, customAnalysisData.DataList)

	return
}

// Edit 编辑
func (obj CustomAnalysis) Edit(params EditCalculateBatchParams) (err error, errMsg string) {
	req := params.Req
	edbInfo := params.EdbInfo

	// 自定义分析的数据集
	jsonByte, err := json.Marshal(req.Data)
	if err != nil {
		return
	}
	var customAnalysisData CustomAnalysisData
	err = json.Unmarshal(jsonByte, &customAnalysisData)
	if err != nil {
		return
	}

	o := orm.NewOrm()
	to, err := o.Begin()
	if err != nil {
		return
	}
	defer func() {
		if err != nil {
			_ = to.Rollback()
			fmt.Println(reflect.TypeOf(obj).Name(), "；Edit,Err:"+err.Error())
		} else {
			_ = to.Commit()
		}
	}()

	//修改指标信息
	edbInfo.EdbName = req.EdbName
	edbInfo.EdbNameSource = req.EdbName
	edbInfo.Frequency = req.Frequency
	edbInfo.Unit = req.Unit
	edbInfo.ClassifyId = req.ClassifyId
	edbInfo.CalculateFormula = req.Formula
	edbInfo.EdbNameEn = req.EdbNameEn
	edbInfo.UnitEn = req.UnitEn
	edbInfo.ModifyTime = time.Now()
	_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime", "EdbNameEn", "UnitEn")
	if err != nil {
		return
	}

	// 只有excel的id有传递，同时有数据的情况下，才去做处理
	if customAnalysisData.ExcelInfoId > 0 && len(customAnalysisData.DateList) > 0 && len(customAnalysisData.DataList) > 0 {
		//判断计算指标是否被更换
		excelEdbMapping, tmpErr := excel.GetExcelEdbMappingByEdbInfoId(edbInfo.EdbInfoId)
		if tmpErr != nil {
			err = errors.New("获取excel与指标的关系失败,Err:" + tmpErr.Error())
			return
		}
		if excelEdbMapping.ExcelInfoId != customAnalysisData.ExcelInfoId {
			errMsg = `excel与指标关系异常`
			err = errors.New(errMsg)
			return
		}

		//计算数据
		err = obj.refresh(to, edbInfo, customAnalysisData.DateList, customAnalysisData.DataList)
	}

	return
}

// Refresh 刷新
func (obj CustomAnalysis) Refresh(params RefreshParams) (err error, errMsg string) {

	return
}

// GetSource 获取来源编码id
func (obj CustomAnalysis) GetSource() int {
	return utils.DATA_SOURCE_CALCULATE_ZDYFX
}

// GetSourceName 获取来源名称
func (obj CustomAnalysis) GetSourceName() string {
	return utils.DATA_SOURCE_NAME_CALCULATE_ZDYFX
}

// GetEdbType 获取指标类型
func (obj CustomAnalysis) GetEdbType() int {
	return utils.CALCULATE_EDB_TYPE
}

// UpdateEdbDataStr 数据更新结构体
type UpdateEdbDataStr struct {
	Value    string `description:"数据对应的最新值"`
	DataTime string `description:"数据对应的日期"`
}

func (obj CustomAnalysis) refresh(to orm.TxOrmer, edbInfo *EdbInfo, dateList []string, dataList []float64) (err error) {
	edbInfoId := edbInfo.EdbInfoId
	dataTableName := GetEdbDataTableName(edbInfo.Source, edbInfo.SubSource)
	edbInfoIdStr := strconv.Itoa(edbInfoId)

	if len(dateList) != len(dataList) {
		err = errors.New("数据集与日期集不匹配")
		return
	}

	//获取指标所有数据
	existDataList := make([]*EdbData, 0)
	sql := `SELECT * FROM %s WHERE edb_info_id=? `
	sql = fmt.Sprintf(sql, dataTableName)
	_, err = to.Raw(sql, edbInfoId).QueryRows(&existDataList)
	if err != nil {
		return err
	}
	existDataMap := make(map[string]string)
	removeDataTimeMap := make(map[string]int) //需要移除的日期数据
	for _, v := range existDataList {
		existDataMap[v.DataTime] = v.Value
		removeDataTimeMap[v.DataTime] = 1
	}
	needAddDateMap := make(map[time.Time]int)

	var isAdd, isUpdate bool
	addSql := ` INSERT INTO ` + dataTableName + `(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `

	updateEdbDataStrList := make([]UpdateEdbDataStr, 0)
	updateSql := ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
	updateSql = fmt.Sprintf(updateSql, dataTableName)
	p, err := to.Raw(updateSql).Prepare()
	if err != nil {
		return
	}
	defer func() {
		_ = p.Close()
	}()

	for i, currDateStr := range dateList {
		currVal := dataList[i] // 当前日期对应的值

		currTime, tmpErr := time.ParseInLocation(utils.FormatDate, currDateStr, time.Local)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		// 当前的实际值
		saveValue := decimal.NewFromFloat(currVal).Round(4).String()

		existVal, ok := existDataMap[currDateStr]
		// 如果库中已经存在该数据的话，那么就进行值的变更操作
		if ok {
			//校验待删除日期数据里面是否存在该元素，如果存在的话，那么移除该日期
			delete(removeDataTimeMap, currDateStr)
			existValDec, _ := decimal.NewFromString(existVal)
			existVal = existValDec.Round(4).String()

			if existVal != saveValue {
				isUpdate = true
				updateEdbDataStrList = append(updateEdbDataStrList, UpdateEdbDataStr{
					Value:    saveValue,
					DataTime: currDateStr,
				})
				//sql := ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
				//sql = fmt.Sprintf(sql, dataTableName)
				//_, err = to.Raw(sql, saveValue, edbInfoId, currDateStr).Exec()
				//if err != nil {
				//	return
				//}
			}

			continue
		}

		// 库中不存在该日期的数据
		timestamp := currTime.UnixNano() / 1e6
		timeStr := fmt.Sprintf("%d", timestamp)
		if _, existOk := needAddDateMap[currTime]; !existOk {
			addSql += GetAddSql(edbInfoIdStr, edbInfo.EdbCode, currDateStr, timeStr, saveValue)
			isAdd = true
		}
		needAddDateMap[currTime] = 1
	}

	//删除已经不存在的指标数据（由于该指标当日的数据删除了）
	{
		removeDateList := make([]string, 0)
		for dateTime := range removeDataTimeMap {
			removeDateList = append(removeDateList, dateTime)
		}
		removeNum := len(removeDateList)
		if removeNum > 0 {
			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (`+utils.GetOrmInReplace(removeNum)+`) `, dataTableName)
			_, err = to.Raw(sql, edbInfo.EdbInfoId, removeDateList).Exec()
			if err != nil {
				fmt.Println(reflect.TypeOf(obj).Name(), " add data ;delete Err", err.Error())
				err = fmt.Errorf("删除不存在的指标数据失败,Err:" + err.Error())
				return
			}
		}
	}

	// 添加指标数据
	if isAdd {
		addSql = strings.TrimRight(addSql, ",")
		_, err = to.Raw(addSql).Exec()
		if err != nil {
			fmt.Println(reflect.TypeOf(obj).Name(), " add data Err", err.Error())
			return
		}
	}

	// 更新指标数据
	if isUpdate {
		for _, v := range updateEdbDataStrList {
			if v.Value == "" || v.DataTime == "" {
				continue
			}
			_, err = p.Exec(v.Value, edbInfoId, v.DataTime)
			if err != nil {
				fmt.Println(reflect.TypeOf(obj).Name(), " update data Err", err.Error())
				return
			}
		}
	}

	return
}

// ResetData 数据重置
func (obj CustomAnalysis) ResetData(edbInfo *EdbInfo, dateList []string, dataList []float64) (err error, errMsg string) {
	o := orm.NewOrm()
	to, err := o.Begin()
	if err != nil {
		return
	}
	defer func() {
		if err != nil {
			_ = to.Rollback()
			fmt.Println(reflect.TypeOf(obj).Name(), "；ResetData,Err:"+err.Error())
		} else {
			_ = to.Commit()
		}
	}()

	err = obj.refresh(to, edbInfo, dateList, dataList)

	return
}

// ResetCustomAnalysisData 数据重置的结构体
type ResetCustomAnalysisData struct {
	EdbInfoId int
	DateList  []string
	DataList  []float64
}
