package domain

import (
	"cicv-data-closedloop/amd64/dispatch_server/package/entity"
	"cicv-data-closedloop/amd64/dispatch_server/package/global"
	"cicv-data-closedloop/amd64/dispatch_server/package/infra"
	"cicv-data-closedloop/amd64/dispatch_server/package/util"
	"encoding/json"
	"errors"
	"fmt"
)

func CanRunUser(userId string, userParallelism int64) bool {
	TaskQueueRunningUserNumber, _ := infra.GlobalRedisClient.LLen(global.KeyTaskQueueRunningUserPrefix + ":" + userId).Result()
	if TaskQueueRunningUserNumber < userParallelism {
		return true
	}
	return false
}

// 集群是否有剩余并行度可以运行任务
//   - return 可运行任务的节点，取并行度剩余最大的节点
func CanRunCluster() (bool, infra.GpuNode, error) {
	// 1 获取集群并行度
	gpuNodeJsons, err := infra.GlobalRedisClient.LRange(global.KeyGpuNodeList, 0, -1).Result()
	if err != nil {
		return false, infra.GpuNode{}, errors.New("获取集群并行度列表 " + global.KeyGpuNodeList + " 失败，错误信息为:" + util.ToString(err))
	}
	infra.GlobalLogger.Infof("集群并行度列表为：%v", util.ToString(gpuNodeJsons))
	var maxNode infra.GpuNode
	var maxParallelism int64
	var can bool
	maxParallelism = 0
	for _, gpuNodeJson := range gpuNodeJsons {
		node, err := JsonToGpuNode(gpuNodeJson)
		if err != nil {
			return false, infra.GpuNode{}, err
		}
		if node.Parallelism != 0 && node.Parallelism > maxParallelism {
			maxNode = node
			maxParallelism = node.Parallelism
			can = true
		}
	}
	return can, maxNode, nil
}

func AddWaitingUser(userId string, userParallelism int64, algorithmObjectKey string, task entity.Task) error {
	taskCacheTemp := entity.TaskCache{
		UserId:             userId,
		AlgorithmObjectKey: algorithmObjectKey,
		UserParallelism:    userParallelism,
		Task:               task,
	}
	// 转 json
	taskCacheJson, err := TaskCacheToJson(taskCacheTemp)
	if err != nil {
		return errors.New("任务缓存对象" + util.ToString(taskCacheTemp) + " 转 json 失败，错误信息为: " + util.ToString(err))
	}
	// 添加到用户等待队列
	key := global.KeyTaskQueueWaitingUser
	err = infra.GlobalRedisClient.RPush(key, taskCacheJson).Err()
	if err != nil {
		return errors.New("任务缓存对象json " + taskCacheJson + "  " + key + " 失败，错误信息为: " + util.ToString(err))
	}
	return nil
}

func DeleteWaitingUser(taskCacheJson string) error {
	// 定义要删除的列表和值
	key := global.KeyTaskQueueWaitingUser
	value := taskCacheJson
	// 使用 LREM 命令删除列表中的特定值
	_, err := infra.GlobalRedisClient.LRem(key, 0, value).Result()
	if err != nil {
		return errors.New("删除用户等待队列中的值 " + taskCacheJson + " 失败，错误信息为: " + util.ToString(err))
	}
	return nil
}

func AddWaitingCluster(userId string, userParallelism int64, algorithmObjectKey string, task entity.Task) error {
	taskCacheTemp := entity.TaskCache{
		UserId:             userId,
		AlgorithmObjectKey: algorithmObjectKey,
		UserParallelism:    userParallelism,
		Task:               task,
	}
	// 转 json
	taskCacheJson, err := TaskCacheToJson(taskCacheTemp)
	if err != nil {
		return errors.New("任务缓存对象" + util.ToString(taskCacheTemp) + " 转 json 失败，错误信息为: " + util.ToString(err))
	}
	// 添加到集群等待队列
	err = infra.GlobalRedisClient.RPush(global.KeyTaskQueueWaitingCluster, taskCacheJson).Err()
	if err != nil {
		return errors.New("任务缓存对象json " + taskCacheJson + " 添加到集群等待队列失败，错误信息为: " + util.ToString(err))
	}
	return nil
}

func AddRunningCluster(taskCache entity.TaskCache) error {
	taskCacheTemp := taskCache
	// 转 json
	taskCacheJson, err := TaskCacheToJson(taskCacheTemp)
	if err != nil {
		return errors.New("任务缓存对象" + util.ToString(taskCacheTemp) + " 转 json 失败，错误信息为: " + util.ToString(err))
	}
	// 添加到集群运行队列
	err = infra.GlobalRedisClient.RPush(global.KeyTaskQueueRunningCluster, taskCacheJson).Err()
	if err != nil {
		return errors.New("任务缓存对象json " + taskCacheJson + " 添加到集群等待队列失败，错误信息为: " + util.ToString(err))
	}
	return nil
}

func TaskCacheToJson(taskCache entity.TaskCache) (string, error) {
	jsonData, err := json.MarshalIndent(taskCache, "", "    ")
	if err != nil {
		return "", err
	}
	return string(jsonData), nil
}

func JsonToGpuNode(jsonData string) (infra.GpuNode, error) {
	// 创建一个 Person 类型的变量
	var taskCache infra.GpuNode

	// 使用 json.Unmarshal 解析 JSON 字符串到结构体
	err := json.Unmarshal([]byte(jsonData), &taskCache)
	if err != nil {
		return infra.GpuNode{}, errors.New("对象json " + jsonData + " 转对象失败错误信息为: " + fmt.Sprintf("%v", err))
	}
	return taskCache, nil
}
