/*

 Copyright (c) [2023] [pcm]
 [pcm-coordinator] is licensed under Mulan PSL v2.
 You can use this software according to the terms and conditions of the Mulan PSL v2.
 You may obtain a copy of Mulan PSL v2 at:
          http://license.coscl.org.cn/MulanPSL2
 THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 EITHER EXPaRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 See the Mulan PSL v2 for more details.

*/

package core

import (
	"context"
	"gitlink.org.cn/JointCloud/pcm-coordinator/pkg/models"
	"gitlink.org.cn/JointCloud/pcm-coordinator/pkg/tracker"
	"gitlink.org.cn/JointCloud/pcm-kubernetes/kubernetesclient"
	"time"

	"gitlink.org.cn/JointCloud/pcm-coordinator/api/internal/svc"
	"gitlink.org.cn/JointCloud/pcm-coordinator/api/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type TaskDetailLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewTaskDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *TaskDetailLogic {
	return &TaskDetailLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *TaskDetailLogic) TaskDetail(req *types.TaskDetailReq) (resp *types.TaskDetailResp, err error) {
	resp = &types.TaskDetailResp{}
	var clouds []models.Cloud
	l.svcCtx.DbEngin.Where("task_id = ?", req.TaskId).Find(&clouds)
	for _, cloud := range clouds {
		if l.svcCtx.K8sRpc == nil {
			continue
		}
		// 查询监控地址
		var metricsUrl string
		l.svcCtx.DbEngin.Raw(" SELECT metrics_url FROM `sc_participant_phy_info` WHERE id = ? ", cloud.ParticipantId).Scan(&metricsUrl)

		//
		var pods []*kubernetesclient.Pod
		switch cloud.Kind {
		case "Job":
			jobResult, err := l.svcCtx.K8sRpc.JobDetail(context.Background(), &kubernetesclient.JobDetailReq{
				Namespace: cloud.Namespace,
				Name:      cloud.Name,
			})
			if err != nil {
				return nil, err
			}
			// 查询出job下关联的pod列表
			uid := jobResult.Job.Metadata.Labels["controller-uid"]
			LabelSelector := "controller-uid=" + uid
			podResp, err := l.svcCtx.K8sRpc.PodList(context.Background(), &kubernetesclient.PodListReq{
				ListOptions: &kubernetesclient.ListOptions{
					LabelSelector: &LabelSelector,
				},
			})
			if err != nil {
				return nil, err
			}
			pods = podResp.PodList.Items

		case "Deployment":
			deploymentResult, err := l.svcCtx.K8sRpc.DeploymentDetail(context.Background(), &kubernetesclient.DeploymentDetailReq{
				Namespace: cloud.Namespace,
				Name:      cloud.Name,
			})
			if err != nil {
				return nil, err
			}
			// 查询出job下关联的pod列表

			uid := deploymentResult.Deployment.Spec.Selector.MatchLabels["app"]
			LabelSelector := "app=" + uid
			podResp, err := l.svcCtx.K8sRpc.PodList(context.Background(), &kubernetesclient.PodListReq{
				ListOptions: &kubernetesclient.ListOptions{
					LabelSelector: &LabelSelector,
				},
			})
			if err != nil {
				return nil, err
			}
			pods = podResp.PodList.Items
		}
		podsMetrics(metricsUrl, pods, resp)

	}
	return resp, nil
}

func podsMetrics(metricsUrl string, pods []*kubernetesclient.Pod, resp *types.TaskDetailResp) {
	// 查询每个pod资源使用情况
	for _, pod := range pods {
		prometheusClient, _ := tracker.NewPrometheus(metricsUrl)
		// cpu需求量
		podCpuLimit := prometheusClient.GetNamedMetrics([]string{"pod_cpu_resource_limits"}, time.Now(), tracker.PodOption{
			PodName:       *pod.Metadata.Name,
			NamespaceName: *pod.Metadata.Namespace,
		})
		resp.CpuLimit = metricAdd(resp.CpuLimit, podCpuLimit)
		// cpu使用量
		podCpuUsage := prometheusClient.GetNamedMetrics([]string{"pod_cpu_usage"}, time.Now(), tracker.PodOption{
			PodName:       *pod.Metadata.Name,
			NamespaceName: *pod.Metadata.Namespace,
		})
		resp.CpuCores = metricAdd(resp.CpuCores, podCpuUsage)
		// 内存使用量
		podMemoryUsage := prometheusClient.GetNamedMetrics([]string{"pod_memory_usage"}, time.Now(), tracker.PodOption{
			PodName:       *pod.Metadata.Name,
			NamespaceName: *pod.Metadata.Namespace,
		})

		resp.MemoryTotal = metricAdd(resp.MemoryTotal, podMemoryUsage)
		// 内存需求量
		podMemoryLimit := prometheusClient.GetNamedMetrics([]string{"pod_memory_resource_limits"}, time.Now(), tracker.PodOption{
			PodName:       *pod.Metadata.Name,
			NamespaceName: *pod.Metadata.Namespace,
		})
		resp.MemoryLimit = metricAdd(resp.MemoryLimit, podMemoryLimit)
	}
	resp.MemoryTotal = resp.MemoryTotal / float64(1073741824)
	resp.MemoryLimit = resp.MemoryLimit / float64(1073741824)
}

func metricAdd(z float64, metric []tracker.Metric) float64 {
	if metric[0].MetricValues != nil {
		z = z + metric[0].MetricValues[0].Sample.Value()
	}
	return z
}
