package supply_analysis

import (
	"errors"
	"eta/eta_index_lib/utils"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/shopspring/decimal"
	"time"
)

// BaseFromStockPlantData base_from_stock_plant_data 存量装置的指标的计算数据
type BaseFromStockPlantData struct {
	StockPlantDataId int       `orm:"column(stock_plant_data_id);pk"`
	VarietyEdbId     int       `description:"指标id"`
	DataTime         time.Time `description:"数据日期"`
	Value            float64   `description:"数据值"`
	ModifyTime       time.Time `description:"修改时间"`
	CreateTime       time.Time `description:"创建时间"`
	DataTimestamp    int64     `description:"数据日期时间戳"`
}

// CalculateVarietyReq 重新计算请求
type CalculateVarietyReq struct {
	VarietyId int    `description:"品种id"`
	AdminId   int    `description:"操作人id"`
	AdminName string `description:"操作人名称"`
}

func Calculate(varietyId int, sysUserId int, sysUserName string) (err error) {
	varietyInfo, err := GetVarietyById(varietyId)
	if err != nil {
		return
	}

	// 获取所有的装置
	plantList, err := GetAllVarietyPlantByVarietyId(varietyId)
	if err != nil {
		return
	}

	// 获取所有的指标
	varietyEdbInfoList, err := GetAllVarietyEdbInfoByVarietyId(varietyId)
	if err != nil {
		return
	}

	// 产生的数据的结束日期
	var lastDate time.Time
	{
		currDate := time.Now()
		currHour := currDate.Hour()
		if currHour < 22 {
			lastDate, _ = time.ParseInLocation(utils.FormatDate, currDate.Format(utils.FormatDate), time.Local)
		} else {
			lastDate, _ = time.ParseInLocation(utils.FormatDate, currDate.AddDate(0, 0, 1).Format(utils.FormatDate), time.Local)
		}
		lastDate = lastDate.AddDate(0, 0, 365) //业务需要计算的数据日期往当前日期后面加上一年
	}

	// 维修数据的开始日期和结束日期
	var startDate time.Time
	//所有设备在该日期的减产数
	maintenanceDataMap := make(map[time.Time][]float64)

	for _, plantInfo := range plantList {
		if plantInfo.IsStop == 1 { // 如果是停产了，那么结束日期就是到 产生的数据的结束日期
			plantInfo.ResumptionDate = lastDate
		}
		// 数据不全
		if plantInfo.MaintenanceDate.IsZero() || plantInfo.ResumptionDate.IsZero() {
			continue
		}
		// 日均产量减量为0，说明数据不全，不参与计算
		if plantInfo.AverageDailyCapacityReduction == 0 {
			continue
		}
		// 开始检修日期
		if startDate.IsZero() || plantInfo.MaintenanceDate.Before(startDate) {
			startDate = plantInfo.MaintenanceDate
		}

		// 结束检修日期
		resumptionDate := plantInfo.ResumptionDate

		for tmpDate := plantInfo.MaintenanceDate; !tmpDate.After(resumptionDate); tmpDate = tmpDate.AddDate(0, 0, 1) {
			dataList, ok := maintenanceDataMap[tmpDate]
			if !ok {
				dataList = make([]float64, 0)
			}
			dataList = append(dataList, plantInfo.AverageDailyCapacityReduction)
			maintenanceDataMap[tmpDate] = dataList
		}
	}

	// 一个有用的装置都没有，那么就不需要计算了
	if len(maintenanceDataMap) <= 0 {
		return
	}

	// 计算出数据
	dataMap := make(map[time.Time]float64)
	for tmpDate := startDate; !tmpDate.After(lastDate); tmpDate = tmpDate.AddDate(0, 0, 1) {
		var calculateVal float64
		tmpDataList, ok := maintenanceDataMap[tmpDate]
		// 如果没有维修数据，那么退出当前循环，进入下一个循环
		if !ok {
			calculateVal = 0
		} else {
			for _, tmpVal := range tmpDataList {
				calculateVal += tmpVal
			}
		}

		dataMap[tmpDate] = calculateVal
	}

	to, err := orm.NewOrm().Begin()
	if err != nil {
		return
	}

	defer func() {
		if err != nil {
			fmt.Println("Calculate,Err:" + err.Error())
			_ = to.Rollback()
		} else {
			_ = to.Commit()
		}
	}()

	// 有数据的话，那就参与计算
	if len(dataMap) > 0 {
		for _, varietyEdbInfo := range varietyEdbInfoList {
			err = calculateEdb(to, varietyEdbInfo, dataMap, startDate, lastDate)
			if err != nil {
				return
			}
		}
	}

	// 更新最后分析的人员信息
	varietyInfo.LastUpdateSysUserId = sysUserId
	varietyInfo.LastUpdateSysUserRealName = sysUserName
	varietyInfo.ModifyTime = time.Now()
	_, err = to.Update(varietyInfo, "LastUpdateSysUserId", "LastUpdateSysUserRealName", "ModifyTime")

	return
}

func calculateEdb(to orm.TxOrmer, varietyEdbInfo *VarietyEdbInfo, dataMap map[time.Time]float64, startDate, lastDate time.Time) (err error) {
	sql := `SELECT * FROM base_from_stock_plant_data WHERE variety_edb_id = ? `
	var list []*BaseFromStockPlantData
	_, err = to.Raw(sql, varietyEdbInfo.VarietyEdbId).QueryRows(&list)
	if err != nil {
		return
	}

	addList := make([]*BaseFromStockPlantData, 0)
	deleteIdMap := make(map[int]int, 0)

	existData := make(map[time.Time]*BaseFromStockPlantData)
	for _, v := range list {
		existData[v.DataTime] = v
		deleteIdMap[v.StockPlantDataId] = v.StockPlantDataId
	}

	endDate := lastDate     // 实际数据最后结束的日期
	var latestValue float64 // 最新值

	// 影响周度产量：当前日期往前（更早日期）统计7天的影响日度产量（减产量）合计 ---- 七个数据和
	// 周度产量变动：往前（更早日期）推第8天的日期对应的影响周度产量值 - 当前日期对应的影响周度产量值
	// 影响月度产量：日期序列为最早检修日期所在月份开始 至 当前日期+365天的日期所在月份，每月最后一天当月的所有影响日度产量（减产量）合计
	// 月度产量变动：上期影响月度产量值 - 当期影响月度产量值
	switch varietyEdbInfo.Source {
	//1：影响周度产量；2：周度产量变动；3：影响月度产量；4：月度产量变动
	case 1, 2:
		// 周度产量数据map
		weekDataMap := make(map[time.Time]float64)

		for currDate := startDate; !currDate.After(lastDate); currDate = currDate.AddDate(0, 0, 1) {
			var weekVal, currVal float64
			for i := 0; i <= 6; i++ {
				tmpDate := currDate.AddDate(0, 0, -i)
				tmpData, ok := dataMap[tmpDate]
				if !ok {
					continue
				}
				weekVal = weekVal + tmpData
			}
			weekDataMap[currDate] = weekVal // 周度产量数据

			if varietyEdbInfo.Source == 1 {
				currVal = weekVal
			} else {
				preVal, ok := weekDataMap[currDate.AddDate(0, 0, -7)]
				if !ok {
					preVal = 0
				}
				currVal = preVal - weekVal
			}

			currVal, _ = decimal.NewFromFloat(currVal).Round(4).Float64()
			latestValue = currVal
			timestamp := currDate.UnixNano() / 1e6
			existItem, ok := existData[currDate]
			if !ok {
				addList = append(addList, &BaseFromStockPlantData{
					//StockPlantDataId: 0,
					VarietyEdbId:  varietyEdbInfo.VarietyEdbId,
					DataTime:      currDate,
					Value:         currVal,
					ModifyTime:    time.Now(),
					CreateTime:    time.Now(),
					DataTimestamp: timestamp,
				})
			} else {
				if existItem.Value != currVal {
					existItem.Value = currVal
					existItem.ModifyTime = time.Now()
					_, err = to.Update(existItem, "Value", "ModifyTime")
					if err != nil {
						return
					}
				}

				delete(deleteIdMap, existItem.StockPlantDataId)
			}
		}
	case 3, 4:
		tmpDataList := make([]float64, 0)        // 每天的值
		preSumValDeci := decimal.NewFromFloat(0) // 上一期的值

		// 期间月度数据
		for tmpDate := startDate; !tmpDate.After(lastDate); tmpDate = tmpDate.AddDate(0, 0, 1) {
			tmpData, ok := dataMap[tmpDate]
			if !ok {
				continue
			}
			tmpDataList = append(tmpDataList, tmpData)

			if tmpDate.AddDate(0, 0, 1).Day() != 1 {
				// 如果不是每个月的最后一日，那么就退出当前循环
				continue
			}

			timestamp := tmpDate.UnixNano() / 1e6

			// 日期期间汇总数据
			var sumVal float64
			for _, tmpVal := range tmpDataList {
				sumVal += tmpVal
			}
			sumValDeci := decimal.NewFromFloat(sumVal)

			var currVal float64
			if varietyEdbInfo.Source == 3 { // 月度影响产量
				currVal, _ = sumValDeci.Round(4).Float64()
			} else { // 如果是月度产量变动的话
				currVal, _ = (preSumValDeci.Sub(decimal.NewFromFloat(sumVal))).Round(4).Float64()
			}
			latestValue = currVal

			preSumValDeci = sumValDeci       // 赋值给上一个周期的截止值
			tmpDataList = make([]float64, 0) //重置值列表，便于下一个周期计算

			existItem, ok := existData[tmpDate]
			if !ok {
				addList = append(addList, &BaseFromStockPlantData{
					//StockPlantDataId: 0,
					VarietyEdbId:  varietyEdbInfo.VarietyEdbId,
					DataTime:      tmpDate,
					Value:         currVal,
					ModifyTime:    time.Now(),
					CreateTime:    time.Now(),
					DataTimestamp: timestamp,
				})
			} else {
				if existItem.Value != currVal {
					existItem.Value = currVal
					existItem.ModifyTime = time.Now()
					_, err = to.Update(existItem, "Value", "ModifyTime")
					if err != nil {
						return
					}
				}

				delete(deleteIdMap, existItem.StockPlantDataId)
			}
		}

		// 最后一月，不满一月时的计算
		currMonthEndDay := time.Date(lastDate.Year(), lastDate.Month(), 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, -1)
		if !lastDate.Equal(currMonthEndDay) {
			// 如果最后一天不是当月的最后一天，那么需要把日期调整到当月的最后一天
			tmpDate := currMonthEndDay
			endDate = tmpDate //数据实际结束的日期

			existItem, ok := existData[tmpDate]

			timestamp := tmpDate.UnixNano() / 1e6
			// 日期期间汇总数据
			var sumVal float64
			for _, tmpVal := range tmpDataList {
				sumVal += tmpVal
			}
			sumValDeci := decimal.NewFromFloat(sumVal)

			var currVal float64
			if varietyEdbInfo.Source == 3 { // 月度影响产量
				currVal, _ = sumValDeci.Round(4).Float64()
			} else { // 如果是月度产量变动的话
				currVal, _ = (preSumValDeci.Sub(decimal.NewFromFloat(sumVal))).Round(4).Float64()
			}
			currVal, _ = decimal.NewFromFloat(currVal).Round(4).Float64()
			latestValue = currVal

			if !ok {
				addList = append(addList, &BaseFromStockPlantData{
					//StockPlantDataId: 0,
					VarietyEdbId:  varietyEdbInfo.VarietyEdbId,
					DataTime:      tmpDate,
					Value:         currVal,
					ModifyTime:    time.Now(),
					CreateTime:    time.Now(),
					DataTimestamp: timestamp,
				})
			} else {
				if existItem.Value != currVal {
					existItem.Value = currVal
					existItem.ModifyTime = time.Now()
					_, err = to.Update(existItem, "Value", "ModifyTime")
					if err != nil {
						return
					}
				}

				delete(deleteIdMap, existItem.StockPlantDataId)
			}
		}

	default:
		err = errors.New("错误的指标类型")
		return
	}

	// 需要添加的指标数据
	lenAddList := len(addList)
	if lenAddList > 0 {
		_, err = to.InsertMulti(lenAddList, addList)
		if err != nil {
			return
		}
	}

	// 删除不存在的数据
	lenDeleteIdMap := len(deleteIdMap)
	if len(deleteIdMap) > 0 {
		deleteIdList := make([]int, 0)
		for _, v := range deleteIdMap {
			deleteIdList = append(deleteIdList, v)
		}
		sql = ` DELETE FROM base_from_stock_plant_data WHERE stock_plant_data_id in (` + utils.GetOrmInReplace(lenDeleteIdMap) + `) `
		_, err = to.Raw(sql, deleteIdList).Exec()
		if err != nil {
			return
		}
	}

	varietyEdbInfo.StartDate = startDate
	varietyEdbInfo.EndDate = endDate
	varietyEdbInfo.LatestValue = latestValue
	varietyEdbInfo.ModifyTime = time.Now()
	_, err = to.Update(varietyEdbInfo, "StartDate", "EndDate", "LatestValue", "ModifyTime")

	return
}
