package service

import (
	"context"
	"fmt"

	"github.com/samber/lo"
	apiv1 "github.com/tidbcloud/cluster-service-ng/api/tidbcloud/cluster-agent/v1"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

func (s *AgentService) ListPods(ctx context.Context, req *apiv1.ListPodsReq) (*apiv1.ListPodsResp, error) {
	logger := tilog.WithContextL(ctx).With(zap.String("cluster_id", req.ClusterId))
	logger.Info("list pods")
	pods, err := s.getPodsByClusterId(ctx, req.ClusterId)
	if err != nil {
		return nil, err
	}

	out := lo.MapToSlice(pods, func(k string, v *corev1.Pod) *apiv1.Pod {
		return convertPod(v)
	})
	return &apiv1.ListPodsResp{Pods: out}, nil
}

func (s *AgentService) GetPod(ctx context.Context, req *apiv1.GetPodReq) (*apiv1.Pod, error) {
	logger := tilog.WithContextL(ctx).With(zap.String("cluster_id", req.ClusterId), zap.String("pod_name", req.PodName))
	logger.Info("get pod")
	var pod corev1.Pod
	if err := s.dataplaneCli.Get(ctx, client.ObjectKey{Namespace: buildNamespace(req.ClusterId), Name: req.PodName}, &pod); err != nil {
		return nil, fmt.Errorf("failed to get pod: %w", err)
	}
	return convertPod(&pod), nil
}

func (s *AgentService) getPodsByClusterId(ctx context.Context, clusterId string) (map[string]*corev1.Pod, error) {

	components := []string{}

	for _, compType := range clusterComponents {
		switch compType {
		case TiFlashComputeComponentType:
			components = append(components, "compute-tiflash")
		case TiFlashWriteComponentType:
			components = append(components, "write-tiflash")
		case TiDBWorkerComponentType:
			components = append(components, "worker-tidb")
		default:
			components = append(components, compType)
		}
	}

	// include over provisioned pods which are using by cluster running on GKE to scale up/down
	labelSelector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{
		MatchExpressions: []metav1.LabelSelectorRequirement{
			{
				Key:      K8sComponentLabelKey,
				Operator: metav1.LabelSelectorOpIn,
				Values:   components,
			},
		},
	})
	if err != nil {
		return nil, fmt.Errorf("build label selector: %w", err)
	}
	var pods corev1.PodList
	if err := s.dataplaneCli.List(ctx, &pods, client.InNamespace(buildNamespace(clusterId)), client.MatchingLabelsSelector{Selector: labelSelector}); err != nil {
		return nil, fmt.Errorf("failed to list pods: %w", err)
	}
	out := lo.SliceToMap(pods.Items, func(item corev1.Pod) (string, *corev1.Pod) {
		return item.Name, &item
	})
	return out, nil
}

func convertPod(pod *corev1.Pod) *apiv1.Pod {
	out := &apiv1.Pod{
		K8SMetadata:   buildK8sMetadata(pod),
		ComponentType: pod.Labels[K8sComponentLabelKey],
		PodIp:         pod.Status.PodIP,
		HostIp:        pod.Status.HostIP,
		NodeName:      pod.Spec.NodeName,
		Phase:         string(pod.Status.Phase),
	}
	return out
}
