package service

import (
	"context"
	"fmt"

	opv2 "github.com/pingcap/tidb-operator/api/v2/core/v1alpha1"
	"github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
	corev1 "k8s.io/api/core/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	apiv1 "github.com/tidbcloud/infra-provider/api/tidbcloud/cluster-agent/v1"
)

func (s *AgentService) GetClusterTopology(ctx context.Context, req *apiv1.GetClusterTopologyReq) (*apiv1.GetClusterTopologyResp, error) {
	if s.tidbOperatorVersion == "v1" {
		tc, err := s.getTiDBClusterV1(ctx, req.ClusterId, tcName)
		if err != nil {
			return nil, err
		}

		return s.buildClusterTopology(tc), nil
	}
	return s.buildClusterTopologyV2(ctx, req.ClusterId)
}

func (s *AgentService) buildClusterTopology(tc *v1alpha1.TidbCluster) *apiv1.GetClusterTopologyResp {
	resp := &apiv1.GetClusterTopologyResp{}

	for _, member := range tc.Status.PD.Members {
		resp.PdNodes = append(resp.PdNodes, &apiv1.GetClusterTopologyResp_PDNodeInfo{
			// db-pd-0
			Name: member.Name,
			// db-pd-0.db-pd-peer.tidb123.svc
			Host: fmt.Sprintf("%s.%s-pd-peer.%s.svc", member.Name, tcName, tc.Namespace),
			Port: uint32(v1alpha1.DefaultPDClientPort),
		})
	}
	for _, store := range tc.Status.TiKV.Stores {
		resp.TikvNodes = append(resp.TikvNodes, &apiv1.GetClusterTopologyResp_TiKVNodeInfo{
			// db-tikv-0
			Name: store.PodName,
			// db-tikv-0.db-tikv-peer.tidb123.svc
			Host: store.IP,
			Port: uint32(v1alpha1.DefaultTiKVServerPort),
		})
	}
	return resp
}

func (s *AgentService) buildClusterTopologyV2(ctx context.Context, clusterID string) (*apiv1.GetClusterTopologyResp, error) {
	resp := &apiv1.GetClusterTopologyResp{}
	ns := buildNamespace(clusterID)

	var pdPodList corev1.PodList
	if err := s.dataplaneCli.List(ctx, &pdPodList, client.InNamespace(ns), getComponentPodLabels(cloudv1.ComponentPD, tcName, tcName)); err != nil {
		return nil, fmt.Errorf("failed to list pd pods: %w", err)
	}
	for _, pd := range pdPodList.Items {
		resp.PdNodes = append(resp.PdNodes, &apiv1.GetClusterTopologyResp_PDNodeInfo{
			Name: pd.Name,
			Host: fmt.Sprintf("%s.%s-pd-peer.%s.svc", pd.Name, tcName, ns),
			Port: uint32(v1alpha1.DefaultPDClientPort),
		})
	}

	var tikvPodList corev1.PodList
	if err := s.dataplaneCli.List(ctx, &tikvPodList, client.InNamespace(ns), getComponentPodLabels(cloudv1.ComponentTiKV, tcName, tcName)); err != nil {
		return nil, fmt.Errorf("failed to list tikv pods: %w", err)
	}
	for _, tikv := range tikvPodList.Items {
		resp.TikvNodes = append(resp.TikvNodes, &apiv1.GetClusterTopologyResp_TiKVNodeInfo{
			Name: tikv.Name,
			Host: fmt.Sprintf("%s.%s-tikv-peer.%s.svc", tikv.Name, tcName, ns),
			Port: uint32(v1alpha1.DefaultTiKVServerPort),
		})
	}
	return resp, nil
}

func getComponentPodLabels(compType cloudv1.ComponentType, tcName, groupName string) client.MatchingLabels {
	return map[string]string{
		opv2.LabelKeyCluster:   tcName,
		opv2.LabelKeyGroup:     groupName,
		opv2.LabelKeyComponent: string(compType),
	}
}
