package api

import (
	"errors"
	"fmt"
	"queencount/db/model"
	"queencount/db/repo"
	"time"

	"github.com/gin-gonic/gin"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
)

func AssetCount(router *GinRouter) {
	// 统计总信息
	router.GET("/asset/info/types/:dbId", GetAssetCount)
	// 统计总图表
	router.GET("/asset/info", GetInfo)
}

type AssetDefCountInfo struct {
	Mesh     []CountDefItem `json:"mesh"`
	Image    []CountDefItem `json:"image"`
	Material []CountDefItem `json:"material"`
	Env3d    []CountDefItem `json:"env3d"`
}

type CountDefItem struct {
	DefItemNum int    `json:"defItemNum"`
	DefName    string `json:"defName"`
	DefKey     string `json:"defKey"`
}

func GetAssetCount(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	// databases := []string{"mesh", "image", "material", "env3d"}
	// 定义模型数量
	dbId := c.Param("dbId")
	if dbId == "" {
		return nil, errors.New("dbId不能为空")
	}
	query := make(map[string]interface{})
	query["_id"], _ = primitive.ObjectIDFromHex(dbId)
	option := &repo.DocSearchOptions{
		CollectName: repo.CollectionDatabase,
		Query:       query,
		Project:     []string{"_id", "assets", "name"},
	}
	var datbaseDoc model.Database
	found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), option, &datbaseDoc)
	if err != nil || !found {
		return nil, err
	}

	var countDefitem CountDefItem
	var assetDefCountInfo AssetDefCountInfo

	defMeshSet := make([]CountDefItem, 0)
	defImageSet := make([]CountDefItem, 0)
	defMaterialSet := make([]CountDefItem, 0)
	defEnv3dSet := make([]CountDefItem, 0)

	dbName := datbaseDoc.Name

	for _, v := range datbaseDoc.Assets {
		// 模型 mesh
		if v.Type == 10 {
			countDefitem.DefKey = v.Collection
			countDefitem.DefName = v.Label

			count, err := repo.RepoDbCountDoc(apictx.CreateRepoCtx(), dbName, v.Collection, repo.Map{})
			if err != nil {
				return nil, err
			}
			countDefitem.DefItemNum = int(count)
			defMeshSet = append(defMeshSet, countDefitem)
			assetDefCountInfo.Mesh = defMeshSet

		}
		if v.Type == 20 {
			countDefitem.DefKey = v.Collection
			countDefitem.DefName = v.Label

			count, err := repo.RepoDbCountDoc(apictx.CreateRepoCtx(), dbName, v.Collection, repo.Map{})
			if err != nil {
				return nil, err
			}
			countDefitem.DefItemNum = int(count)
			defImageSet = append(defImageSet, countDefitem)
			assetDefCountInfo.Image = defImageSet

		}
		if v.Type == 30 {
			countDefitem.DefKey = v.Collection
			countDefitem.DefName = v.Label

			count, err := repo.RepoDbCountDoc(apictx.CreateRepoCtx(), dbName, v.Collection, repo.Map{})
			if err != nil {
				return nil, err
			}
			countDefitem.DefItemNum = int(count)
			defMaterialSet = append(defMaterialSet, countDefitem)
			assetDefCountInfo.Material = defMaterialSet

		}
		if v.Type == 40 {
			countDefitem.DefKey = v.Collection
			countDefitem.DefName = v.Label

			count, err := repo.RepoDbCountDoc(apictx.CreateRepoCtx(), dbName, v.Collection, repo.Map{})
			if err != nil {
				return nil, err
			}

			countDefitem.DefItemNum = int(count)
			defEnv3dSet = append(defEnv3dSet, countDefitem)
			assetDefCountInfo.Env3d = defEnv3dSet
		}

	}

	return assetDefCountInfo, nil
}

type ReqAssetCount struct {
	DbId      string `json:"dbId"`
	Step      int    `json:"step"`
	StartTime string `json:"startTime"`
	EndTime   string `json:"endTime"`
}

const DateTimeLayout = "2006-01-02 15:04:05"

func (req *ReqAssetCount) GetStartTime() (time.Time, error) {
	return time.Parse(DateTimeLayout, req.StartTime)
}

func (req *ReqAssetCount) GetEndTime() (time.Time, error) {
	return time.Parse(DateTimeLayout, req.EndTime)
}

type TypeCount struct {
	Time    []*model.AssetCountV0 `json:"times"`
	DefName string                `json:"defName"`
	DefType int                   `json:"defType"`
	DefId   string                `json:"defId"`
}

func GetStepIndex(t time.Time, endTime time.Time, step int) int64 {
	return int64(endTime.Sub(t).Seconds()) / int64(step)
}

// 获取统计信息图表需要的信息
func GetInfo(c *gin.Context, apictx *ApiSession) (interface{}, error) {

	var form ReqAssetCount
	err := c.ShouldBindJSON(&form)
	if err != nil {
		return nil, errors.New("参数错误")
	}

	if form.Step == 0 {
		return nil, errors.New("时间步距不能为空")
	}
	if form.StartTime == "" {
		return nil, errors.New("开始时间不能为空")
	}
	if form.EndTime == "" {
		return nil, errors.New("结束时间不能为空")
	}
	if form.DbId == "" {
		return nil, errors.New("数据库id不为空")
	}
	startTime, err := form.GetStartTime()
	if err != nil {
		return nil, err
	}
	endTime, err := form.GetEndTime()
	if err != nil {
		return nil, err
	}

	ctx := apictx.CreateRepoCtx()

	dbId, _ := primitive.ObjectIDFromHex(form.DbId)

	// 根据id查询数据库名
	var databaseDoc model.Database
	dbParam := &repo.DocSearchOptions{
		CollectName: repo.CollectionDatabase,
		Query:       map[string]interface{}{"_id": dbId},
		Project:     []string{"_id", "name", "assets"},
	}
	is, err := repo.RepoSeachDoc(ctx, dbParam, &databaseDoc)
	if !is || err != nil {
		return nil, errors.New("资产数据为空")
	}

	searchTime := time.Now()

	listCounts := []*model.AssetCount{}
	err = repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
		Db:          databaseDoc.Name,          // 对应资产数据库
		CollectName: repo.CollectionAssetCount, // 统计表
		Query: repo.Map{"$and": []bson.M{
			bson.M{"createTime": bson.M{"$lte": endTime}},
			bson.M{"createTime": bson.M{"$gte": startTime}},
		}},
		Project: []string{"defId", "createTime", "count"},
		// Sort:    bson.M{"createTime": -1}, // 降序 小于等于createTime中取时间最近的 第一条

	}, &listCounts)
	if err != nil {
		return nil, err
	}

	defCountsMap := map[string]*TypeCount{}
	listCountIndex := len(listCounts)
	for {
		if listCountIndex == 0 {
			break
		}
		listCountIndex -= 1

		item := listCounts[listCountIndex]
		defId := item.DefId

		if defCountsMap[defId] == nil {
			defCountsMap[defId] = &TypeCount{Time: []*model.AssetCountV0{
				{
					DefId:      item.DefId,
					CreateTime: item.CreateTime,
					Count:      item.Count,
					StepIndex:  int(GetStepIndex(item.CreateTime, endTime, form.Step)),
				},
			}}
			continue
		}

		typeList := defCountsMap[defId]
		lastType := typeList.Time[len(typeList.Time)-1]

		b, _ := time.ParseDuration(fmt.Sprintf("%ds", form.Step))
		if item.CreateTime.Unix() <= lastType.CreateTime.Add(b*-1).Unix() {
			typeList.Time = append(typeList.Time, &model.AssetCountV0{
				DefId:      item.DefId,
				CreateTime: item.CreateTime,
				Count:      item.Count,
				StepIndex:  int(GetStepIndex(item.CreateTime, endTime, form.Step)),
			})
		}
	}

	out := []*TypeCount{}

	for defId, _ := range defCountsMap {
		for _, v := range databaseDoc.Assets {
			if v.Id == defId {
				defCountsMap[defId].DefType = v.Type
				defCountsMap[defId].DefName = v.Label
				defCountsMap[defId].DefId = v.Id
				break
			}
		}
		out = append(out, defCountsMap[defId])
	}

	return map[string]interface{}{
		"types": out,
		"time":  time.Now().Sub(searchTime).Seconds(),
	}, nil

}

// 获取需要查询数据的时间点
func GetCountTimeSet(form ReqAssetCount) (timeSet []time.Time) {
	// 计算有多少个时间段
	startTime, _ := time.Parse(DateTimeLayout, form.StartTime)
	endTime, _ := time.Parse(DateTimeLayout, form.EndTime)
	duration := endTime.Unix() - startTime.Unix()
	counts := int(duration / int64(form.Step)) // 取整

	for i := 0; i <= counts; i++ {
		b, _ := time.ParseDuration(fmt.Sprintf("%ds", i*form.Step))
		start := startTime.Add(b)
		// 第一个元素为开始时间
		timeSet = append(timeSet, start)
	}
	return
}
