// Package target defines Pod selectors shared by metrics discovery, scrapers,
// and providers.
package target

import (
	"fmt"
	"maps"
	"strings"

	"github.com/tidbcloud/cluster-service-ng/internal/capacity-planner/api/v1alpha1"
)

const (
	// LabelGroup and LabelComponent are the canonical labels stored in the TSDB
	// and injected into Pod metric queries.
	LabelGroup     = "group"
	LabelComponent = "component"

	// PodLabelGroup and PodLabelComponent are their Kubernetes Pod label
	// counterparts used when resolving a Target to Pods.
	PodLabelGroup     = "pingcap.com/group"
	PodLabelComponent = "pingcap.com/component"
)

// Target selects Pods in one namespace by equality labels.
type Target interface {
	Namespace() string
	Labels() map[string]string
}

// PodTarget is an immutable Target derived from an Autoscaler targetRef.
type PodTarget struct {
	namespace string
	labels    map[string]string
}

var _ Target = (*PodTarget)(nil)

// NewPodTargetForRef converts a supported targetRef into its Pod selector.
func NewPodTargetForRef(namespace string, ref v1alpha1.CrossVersionObjectReference) (*PodTarget, error) {
	if namespace == "" {
		return nil, fmt.Errorf("metrics target: namespace is required")
	}
	if ref.APIVersion == "" {
		return nil, fmt.Errorf("metrics target: targetRef.apiVersion is required")
	}
	if ref.Name == "" {
		return nil, fmt.Errorf("metrics target: targetRef.name is required")
	}
	component, err := componentForTargetKind(ref.Kind)
	if err != nil {
		return nil, err
	}
	return &PodTarget{
		namespace: namespace,
		labels: map[string]string{
			LabelGroup:     ref.Name,
			LabelComponent: component,
		},
	}, nil
}

// Namespace returns the namespace containing the selected Pods.
func (t *PodTarget) Namespace() string {
	return t.namespace
}

// Labels returns a copy so callers cannot mutate the Target's selector.
func (t *PodTarget) Labels() map[string]string {
	return maps.Clone(t.labels)
}

func componentForTargetKind(kind string) (string, error) {
	switch strings.TrimSuffix(kind, "Group") {
	case "TiDB":
		return "tidb", nil
	case "TiKV":
		return "tikv", nil
	case "TiKVWorker":
		return "tikv-worker", nil
	case "TiFlash":
		return "tiflash", nil
	case "TiProxy":
		return "tiproxy", nil
	case "TiCDC":
		return "ticdc", nil
	case "PD":
		return "pd", nil
	case "TSO":
		return "tso", nil
	case "Scheduling":
		return "scheduling", nil
	case "Scheduler":
		return "scheduler", nil
	case "ResourceManager":
		return "resource-manager", nil
	default:
		return "", fmt.Errorf("metrics target: unsupported target kind %q", kind)
	}
}
