package repo

import (
	"net/http"
	"strings"
	"time"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/context"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/modules/timeutil"
	cloudbrainService "code.gitea.io/gitea/services/cloudbrain"
)

func CloudbrainDurationStatisticHour() {
	if setting.IsCloudbrainTimingEnabled {
		var statisticTime time.Time
		var count int64
		recordDurationUpdateTime, err := models.GetDurationRecordUpdateTime()
		if err != nil {
			log.Error("Can not get GetDurationRecordBeginTime", err)
		}
		now := time.Now()
		currentTime := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
		if err == nil && len(recordDurationUpdateTime) > 0 {
			statisticTime = time.Unix(int64(recordDurationUpdateTime[0].DateTimeUnix), 0).Add(+1 * time.Hour)
		} else {
			statisticTime = currentTime
		}

		err = models.DeleteCloudbrainDurationStatistic(timeutil.TimeStamp(statisticTime.Unix()), timeutil.TimeStamp(currentTime.Unix()))
		if err != nil {
			log.Error("DeleteCloudbrainDurationStatistic failed", err)
		}
		statisticTime = statisticTime.Add(+1 * time.Hour)
		for statisticTime.Before(currentTime) || statisticTime.Equal(currentTime) {
			countEach := summaryDurationStat(statisticTime)
			count += countEach
			statisticTime = statisticTime.Add(+1 * time.Hour)
		}
	}
}
func UpdateDurationStatisticHistoryData(beginTime time.Time, endTime time.Time) int64 {
	var count int64
	statisticTime := beginTime
	currentTime := endTime
	for statisticTime.Before(currentTime) || statisticTime.Equal(currentTime) {
		countEach := summaryDurationStat(statisticTime)
		count += countEach
		statisticTime = statisticTime.Add(+1 * time.Hour)
	}
	return count
}

//statisticTime是当前的时辰，比如当前是2019-01-01 12:01:01，那么statisticTime就是2019-01-01 12:00:00
func summaryDurationStat(statisticTime time.Time) int64 {
	var count int64
	dateTimeUnix := timeutil.TimeStamp(statisticTime.Add(-1 * time.Hour).Unix())
	beginTime := statisticTime.Add(-1 * time.Hour).Unix()
	dayTime := statisticTime.Add(-1 * time.Hour).Format("2006-01-02")
	hourTime := statisticTime.Add(-1 * time.Hour).Hour()
	endTime := statisticTime.Unix()

	ciTasks, err := models.GetCloudbrainByTime(beginTime, endTime)
	if err != nil {
		log.Error("GetCloudbrainByTime err: %v", err)
		return 0
	}
	err = models.LoadSpecs4CloudbrainInfo(ciTasks)
	if err != nil {
		log.Error("LoadSpecs4CloudbrainInfo err: %v", err)
	}
	cloudBrainCenterCodeAndCardTypeInfo := getcloudBrainCenterCodeAndCardTypeInfo(ciTasks, int(beginTime), int(endTime))

	resourceQueues, err := models.GetCanUseCardInfo()
	if err != nil {
		log.Error("GetCanUseCardInfo err: %v", err)
		return 0
	}

	cardsTotalDurationMap := make(map[string]int)
	for _, resourceQueue := range resourceQueues {
		if _, ok := cardsTotalDurationMap[resourceQueue.Cluster+"/"+resourceQueue.AiCenterCode+"/"+resourceQueue.AccCardType]; !ok {
			cardsTotalDurationMap[resourceQueue.Cluster+"/"+resourceQueue.AiCenterCode+"/"+resourceQueue.AccCardType] = resourceQueue.CardsTotalNum * 1 * 60 * 60
		} else {
			cardsTotalDurationMap[resourceQueue.Cluster+"/"+resourceQueue.AiCenterCode+"/"+resourceQueue.AccCardType] += resourceQueue.CardsTotalNum * 1 * 60 * 60
		}
	}
	for key, cardsTotalDuration := range cardsTotalDurationMap {
		if _, ok := cloudBrainCenterCodeAndCardTypeInfo[strings.Split(key, "/")[0]+"/"+strings.Split(key, "/")[1]][strings.Split(key, "/")[2]]; ok {
			cloudbrainDurationStat := models.CloudbrainDurationStatistic{
				DateTimeUnix:       dateTimeUnix,
				DayTime:            dayTime,
				HourTime:           hourTime,
				Cluster:            strings.Split(key, "/")[0],
				AiCenterName:       GetAiCenterNameByCode(strings.Split(key, "/")[1], "zh-CN"),
				AiCenterCode:       strings.Split(key, "/")[1],
				AccCardType:        strings.Split(key, "/")[2],
				CardsUseDuration:   cloudBrainCenterCodeAndCardTypeInfo[strings.Split(key, "/")[0]+"/"+strings.Split(key, "/")[1]][strings.Split(key, "/")[2]],
				CardsTotalDuration: cardsTotalDuration,
				CardsTotalNum:      cardsTotalDuration / 1 / 60 / 60,
				CreatedUnix:        timeutil.TimeStampNow(),
			}
			if _, err = models.InsertCloudbrainDurationStatistic(&cloudbrainDurationStat); err != nil {
				log.Error("Insert cloudbrainDurationStat failed: %v", err.Error())
			}
			count++
		} else {
			cloudbrainDurationStat := models.CloudbrainDurationStatistic{
				DateTimeUnix:       dateTimeUnix,
				DayTime:            dayTime,
				HourTime:           hourTime,
				Cluster:            strings.Split(key, "/")[0],
				AiCenterName:       GetAiCenterNameByCode(strings.Split(key, "/")[1], "zh-CN"),
				AiCenterCode:       strings.Split(key, "/")[1],
				AccCardType:        strings.Split(key, "/")[2],
				CardsUseDuration:   0,
				CardsTotalDuration: cardsTotalDuration,
				CardsTotalNum:      cardsTotalDuration / 1 / 60 / 60,
				CreatedUnix:        timeutil.TimeStampNow(),
			}
			if _, err = models.InsertCloudbrainDurationStatistic(&cloudbrainDurationStat); err != nil {
				log.Error("Insert cloudbrainDurationStat failed: %v", err.Error())
			}
			count++
		}
	}
	return count
}

func GetAiCenterNameByCode(centerCode string, language string) string {
	var aiCenterName string
	aiCenterInfo := cloudbrainService.GetAiCenterInfoByCenterCode(centerCode)
	if aiCenterInfo != nil {
		if language == "zh-CN" {
			aiCenterName = aiCenterInfo.Content
		} else {
			aiCenterName = aiCenterInfo.ContentEN
		}
	} else {
		aiCenterName = centerCode
	}
	return aiCenterName
}

func getcloudBrainCenterCodeAndCardTypeInfo(ciTasks []*models.CloudbrainInfo, hourBeginTime int, hourEndTime int) map[string]map[string]int {
	var WorkServerNumber int
	var AccCardsNum int
	cloudBrainCenterCodeAndCardType := make(map[string]map[string]int)
	for _, cloudbrain := range ciTasks {
		cloudbrain = cloudbrainService.UpdateCloudbrainAiCenter(cloudbrain)
		if cloudbrain.Cloudbrain.StartTime == 0 {
			cloudbrain.Cloudbrain.StartTime = cloudbrain.Cloudbrain.CreatedUnix
		}
		if cloudbrain.Cloudbrain.EndTime == 0 {
			if cloudbrain.Cloudbrain.Status == string(models.JobRunning) {
				cloudbrain.Cloudbrain.EndTime = timeutil.TimeStamp(time.Now().Unix())
			} else {
				cloudbrain.Cloudbrain.EndTime = cloudbrain.Cloudbrain.StartTime + timeutil.TimeStamp(cloudbrain.Cloudbrain.Duration)
			}
		}
		if cloudbrain.Cloudbrain.WorkServerNumber >= 1 {
			WorkServerNumber = cloudbrain.Cloudbrain.WorkServerNumber
		} else {
			WorkServerNumber = 1
		}
		if cloudbrain.Cloudbrain.Spec == nil {
			AccCardsNum = 1
		} else {
			AccCardsNum = cloudbrain.Cloudbrain.Spec.AccCardsNum
		}
		if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Cluster+"/"+cloudbrain.Cloudbrain.AiCenter]; !ok {
			cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Cluster+"/"+cloudbrain.Cloudbrain.AiCenter] = make(map[string]int)
		}
		taskStartTime := int(cloudbrain.Cloudbrain.StartTime)
		taskEndTime := int(cloudbrain.Cloudbrain.EndTime)
		if cloudbrain.Cloudbrain.Spec != nil {
			if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Cluster+"/"+cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
				if taskStartTime < hourBeginTime && taskEndTime >= hourBeginTime && taskEndTime <= hourEndTime {
					cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Cluster+"/"+cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (taskEndTime - hourBeginTime)
				} else if taskStartTime < hourBeginTime && taskEndTime > hourEndTime {
					cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Cluster+"/"+cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (hourEndTime - hourBeginTime)
				} else if taskStartTime >= hourBeginTime && taskStartTime <= hourEndTime && taskEndTime >= hourBeginTime && taskEndTime <= hourEndTime {
					cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Cluster+"/"+cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (taskEndTime - taskStartTime)
				} else if taskStartTime >= hourBeginTime && taskStartTime <= hourEndTime && taskEndTime > hourEndTime {
					cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Cluster+"/"+cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (hourEndTime - taskStartTime)
				}
			} else {
				if taskStartTime < hourBeginTime && taskEndTime >= hourBeginTime && taskEndTime <= hourEndTime {
					cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Cluster+"/"+cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (taskEndTime - hourBeginTime)
				} else if taskStartTime < hourBeginTime && taskEndTime > hourEndTime {
					cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Cluster+"/"+cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (hourEndTime - hourBeginTime)
				} else if taskStartTime >= hourBeginTime && taskStartTime <= hourEndTime && taskEndTime >= hourBeginTime && taskEndTime <= hourEndTime {
					cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Cluster+"/"+cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (taskEndTime - taskStartTime)
				} else if taskStartTime >= hourBeginTime && taskStartTime <= hourEndTime && taskEndTime > hourEndTime {
					cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Cluster+"/"+cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (hourEndTime - taskStartTime)
				}
			}
		}
	}
	return cloudBrainCenterCodeAndCardType
}

func CloudbrainUpdateHistoryData(ctx *context.Context) {
	beginTimeStr := ctx.QueryTrim("beginTime")
	endTimeStr := ctx.QueryTrim("endTime")
	var count int64
	var err error
	if beginTimeStr != "" && endTimeStr != "" {
		beginTime, _ := time.ParseInLocation("2006-01-02 15:04:05", beginTimeStr, time.Local)
		endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", endTimeStr, time.Local)
		if time.Now().Before(endTime) {
			endTime = time.Now()
		}
		beginTimeUnix := timeutil.TimeStamp(beginTime.Unix())
		endTimeUnix := timeutil.TimeStamp(endTime.Unix())

		err = models.DeleteCloudbrainDurationStatistic(beginTimeUnix, endTimeUnix)
		count = UpdateDurationStatisticHistoryData(beginTime.Add(+1*time.Hour), endTime.Add(+1*time.Hour))
	}
	ctx.JSON(http.StatusOK, map[string]interface{}{
		"message": 0,
		"count":   count,
		"err":     err,
	})
}
