func InheritAllLabelsFrom(parentGroupLabel, relatedMetricKey string) definition.FetchFunc {
	return func(groupLabel, entityID string, groups definition.RawGroups) (definition.FetchedValue, error) {
		return labelsFromMetric(parentGroupLabel, relatedMetricKey, groupLabel, entityID, groups, "label")
	}
}
InheritAllLabelsFrom gets all the label values from from a related metric.
Related metric means any metric you can get with the info that you have in your own metric.
package prometheus
import (
	"errors"
	"fmt"
	"math"
	"sort"
	"strconv"
	"strings"
	model "github.com/prometheus/client_model/go"
	"github.com/newrelic/nri-kubernetes/v2/src/definition"
)
var ControlPlaneComponentTypeGenerator = func(
	groupLabel string,
	_ string,
	_ definition.RawGroups,
	clusterName string,
) (string, error) {
	return fmt.Sprintf("k8s:%s:controlplane:%s", clusterName, groupLabel), nil
}
var FromRawEntityIDGenerator = func(_, rawEntityID string, _ definition.RawGroups) (string, error) {
	return rawEntityID, nil
}
func FromLabelValueEntityTypeGenerator(key string) definition.EntityTypeGeneratorFunc {
	return func(groupLabel string, rawEntityID string, g definition.RawGroups, clusterName string) (string, error) {
		switch groupLabel {
		case "namespace", "node":
			return fmt.Sprintf("k8s:%s:%s", clusterName, groupLabel), nil
		case "container":
			labels, err := getLabels(groupLabel, rawEntityID, key, g, "namespace", "pod")
			if err != nil {
				return "", err
			}
			if len(labels) != 2 {
				return "", fmt.Errorf("cannot retrieve values for composing entity type for %q", groupLabel)
			}
			namespace := labels[0]
			podName := labels[1]
			if namespace == "" || podName == "" {
				return "", fmt.Errorf("empty values for generated entity type for %q", groupLabel)
			}
			return fmt.Sprintf("k8s:%s:%s:%s:%s", clusterName, namespace, podName, groupLabel), nil
		default:
			labels, err := getLabels(groupLabel, rawEntityID, key, g, "namespace")
			if err != nil {
				return "", err
			}
			if len(labels) == 0 {
				return "", fmt.Errorf("cannot retrieve values for composing entity type for %q", groupLabel)
			}
			namespace := labels[0]
			if namespace == "" {
				return "", fmt.Errorf("empty namespace for generated entity type for %q", groupLabel)
			}
			return fmt.Sprintf("k8s:%s:%s:%s", clusterName, namespace, groupLabel), nil
		}
	}
}
func getLabels(groupLabel, rawEntityID, key string, groups definition.RawGroups, labels ...string) ([]string, error) {
	var s []string
	for _, label := range labels {
		v, err := FromLabelValue(key, label)(groupLabel, rawEntityID, groups)
		if err != nil {
			return s, fmt.Errorf("cannot fetch label %q for metric %q: %w", label, key, err)
		}
		if v == nil {
			return s, fmt.Errorf("label %q not found for metric %q", label, key)
		}
		val, ok := v.(string)
		if !ok {
			return s, fmt.Errorf("unexpected type %T of label %q for metric %q", v, label, key)
		}
		s = append(s, val)
	}
	return s, nil
}
func FromLabelValueEntityIDGenerator(key, label string) definition.EntityIDGeneratorFunc {
	return func(groupLabel string, rawEntityID string, g definition.RawGroups) (string, error) {
		v, err := FromLabelValue(key, label)(groupLabel, rawEntityID, g)
		if err != nil {
			return "", fmt.Errorf("cannot fetch label %q for metric %q: %w", label, key, err)
		}
		if v == nil {
			return "", fmt.Errorf("unexpected nil value of fetched data for metric %q", key)
		}
		val, ok := v.(string)
		if !ok {
			return "", fmt.Errorf("incorrect type %T of fetched data for metric %q", v, key)
		}
		return val, err
	}
}
func FromLabelsValueEntityIDGeneratorForPendingPods() definition.EntityIDGeneratorFunc {
	return func(groupLabel string, rawEntityID string, g definition.RawGroups) (string, error) {
		podName, err := FromLabelValueEntityIDGenerator("kube_pod_status_phase", "pod")(groupLabel, rawEntityID, g)
		if err != nil {
			return "", err
		}
		isScheduled, err := FromLabelValueEntityIDGenerator("kube_pod_status_scheduled", "condition")(groupLabel, rawEntityID, g)
		if err != nil {
			return "", err
		}
		if isScheduled != "false" {
			return "", fmt.Errorf("ignoring pending pod, which is scheduled: reported from Kubelet endpoint")
		}
		return podName, nil
	}
}
func GroupEntityMetricsBySpec(
	specs definition.SpecGroups,
	families []MetricFamily,
	rawEntityID string,
) (g definition.RawGroups, errs []error) {
	g = make(definition.RawGroups)
	for groupLabel := range specs {
		for _, f := range families {
			for _, m := range f.Metrics {
				if _, ok := g[groupLabel]; !ok {
					g[groupLabel] = make(map[string]definition.RawMetrics)
				}
				if _, ok := g[groupLabel][rawEntityID]; !ok {
					g[groupLabel][rawEntityID] = make(definition.RawMetrics)
				}
				groupedMetrics, ok := g[groupLabel][rawEntityID][f.Name]
				if !ok {
					groupedMetrics = make([]Metric, 0)
				}
				g[groupLabel][rawEntityID][f.Name] = append(groupedMetrics.([]Metric), m)
			}
		}
		if len(g[groupLabel]) == 0 {
			errs = append(errs, fmt.Errorf("no data found for %s object", groupLabel))
			continue
		}
	}
	return g, errs
}
func GroupMetricsBySpec(specs definition.SpecGroups, families []MetricFamily) (g definition.RawGroups, errs []error) {
	g = make(definition.RawGroups)
	for groupLabel := range specs {
		for _, f := range families {
			for _, m := range f.Metrics {
				if !m.Labels.Has(groupLabel) {
					continue
				}
				rawEntityID := ""
				if groupLabel == "node" && m.Labels.Has("pod") {
					continue
				}
				if groupLabel == "namespace" && (m.Labels.Has("daemonset") ||
					m.Labels.Has("pod") ||
					m.Labels.Has("endpoint") ||
					m.Labels.Has("service") ||
					m.Labels.Has("deployment") || m.Labels.Has("replicaset")) {
					continue
				}
				switch groupLabel {
				case "namespace", "node":
					rawEntityID = m.Labels[groupLabel]
				case "container":
					rawEntityID = fmt.Sprintf("%v_%v_%v", m.Labels["namespace"], m.Labels["pod"], m.Labels[groupLabel])
				default:
					rawEntityID = fmt.Sprintf("%v_%v", m.Labels["namespace"], m.Labels[groupLabel])
				}
				if _, ok := g[groupLabel]; !ok {
					g[groupLabel] = make(map[string]definition.RawMetrics)
				}
				if _, ok := g[groupLabel][rawEntityID]; !ok {
					g[groupLabel][rawEntityID] = make(definition.RawMetrics)
				}
				if v, ok := g[groupLabel][rawEntityID][f.Name]; ok {
					if oldMetric, ok := v.(Metric); ok {
						g[groupLabel][rawEntityID][f.Name] = []Metric{oldMetric}
					}
					g[groupLabel][rawEntityID][f.Name] = append(g[groupLabel][rawEntityID][f.Name].([]Metric), m)
					continue
				}
				g[groupLabel][rawEntityID][f.Name] = m
			}
		}
		if len(g[groupLabel]) == 0 {
			errs = append(errs, fmt.Errorf("no data found for %s object", groupLabel))
			continue
		}
	}
	return g, errs
}
type LabelsFilter func(Labels) Labels
func IgnoreLabelsFilter(labelsToIgnore ...string) func(Labels) Labels {
	return func(labels Labels) Labels {
		filteredLabels := make(Labels)
		for label, value := range labels {
			ignore := false
			for _, labelToIgnore := range labelsToIgnore {
				if labelToIgnore == label {
					ignore = true
					break
				}
			}
			if !ignore {
				filteredLabels[label] = value
			}
		}
		return filteredLabels
	}
}
func IncludeOnlyLabelsFilter(labelsToInclude ...string) func(Labels) Labels {
	return func(labels Labels) Labels {
		filteredLabels := make(Labels)
		for label, value := range labels {
			include := false
			for _, labelToIgnore := range labelsToInclude {
				if labelToIgnore == label {
					include = true
					break
				}
			}
			if include {
				filteredLabels[label] = value
			}
		}
		return filteredLabels
	}
}
func attributeName(metricName, nameOverride string, labels Labels, labelsFilter ...LabelsFilter) string {
	for _, filter := range labelsFilter {
		labels = filter(labels)
	}
	if nameOverride != "" {
		return suffixLabelsInOrder(nameOverride, labels)
	}
	return suffixLabelsInOrder(metricName, labels)
}
func fetchedValuesFromRawMetrics(
	metricName string,
	nameOverride string,
	metrics []Metric,
	labelsFilter ...LabelsFilter,
) (definition.FetchedValues, error) {
	val := make(definition.FetchedValues)
	for _, metric := range metrics {
		attrName := attributeName(metricName, nameOverride, metric.Labels, labelsFilter...)
		aggregatedValue, ok := val[attrName]
		if !ok {
			val[attrName] = metric.Value
			continue
		}
		switch metric.Value.(type) {
		case CounterValue:
			aggregatedCounter, ok := aggregatedValue.(CounterValue)
			if !ok {
				return nil, fmt.Errorf(
					"incompatible metric type for %s aggregation. Expected: CounterValue. Got: %T",
					metricName,
					metric.Value,
				)
			}
			val[attrName] = aggregatedCounter + metric.Value.(CounterValue)
		case GaugeValue:
			aggregatedCounter, ok := aggregatedValue.(GaugeValue)
			if !ok {
				return nil, fmt.Errorf(
					"incompatible metric type for %s aggregation. Expected: GaugeValue. Got: %T",
					metricName,
					metric.Value,
				)
			}
			val[attrName] = aggregatedCounter + metric.Value.(GaugeValue)
		}
	}
	return val, nil
}
func FromValue(metricName string, labelsFilter ...LabelsFilter) definition.FetchFunc {
	return FromValueWithOverriddenName(metricName, "", labelsFilter...)
}
func FromValueWithOverriddenName(metricName string, nameOverride string, labelsFilter ...LabelsFilter) definition.FetchFunc {
	return func(groupLabel, entityID string, groups definition.RawGroups) (definition.FetchedValue, error) {
		value, err := definition.FromRaw(metricName)(groupLabel, entityID, groups)
		if err != nil {
			return nil, err
		}
		switch m := value.(type) {
		case Metric:
			return m.Value, nil
		case []Metric:
			return fetchedValuesFromRawMetrics(metricName, nameOverride, m, labelsFilter...)
		}
		return nil, fmt.Errorf(
			"incompatible metric type for %s. Expected: Metric or []Metric. Got: %T",
			metricName,
			value,
		)
	}
}
func FromLabelValue(key, label string) definition.FetchFunc {
	return func(groupLabel, entityID string, groups definition.RawGroups) (definition.FetchedValue, error) {
		value, err := definition.FromRaw(key)(groupLabel, entityID, groups)
		if err != nil {
			return nil, err
		}
		v, ok := value.(Metric)
		if !ok {
			return nil, fmt.Errorf("incompatible metric type. Expected: Metric. Got: %T", value)
		}
		l, ok := v.Labels[label]
		if !ok {
			return nil, errors.New("label not found in prometheus metric")
		}
		return l, nil
	}
}
func suffixLabelsInOrder(metricName string, labels Labels) string {
	orderedLabels := make([]string, 0, len(labels))
	for labelKey, labelVal := range labels {
		orderedLabels = append(orderedLabels, fmt.Sprintf("%s_%s", labelKey, labelVal))
	}
	sort.Strings(orderedLabels)
	for _, l := range orderedLabels {
		metricName = fmt.Sprintf("%s_%s", metricName, l)
	}
	return metricName
}
func FromSummary(key string) definition.FetchFunc {
	return func(groupLabel, entityID string, groups definition.RawGroups) (definition.FetchedValue, error) {
		value, err := definition.FromRaw(key)(groupLabel, entityID, groups)
		if err != nil {
			return nil, err
		}
		metrics, ok := value.([]Metric)
		if !ok {
			return nil, fmt.Errorf(
				"incompatible metric type for %s. Expected: []Metric. Got: %T",
				key,
				value,
			)
		}
		val := make(definition.FetchedValues)
		for _, metric := range metrics {
			summary, ok := metric.Value.(*model.Summary)
			if !ok {
				return nil, fmt.Errorf(
					"incompatible metric type for %s. Expected: Summary. Got: %T",
					key,
					metric.Value,
				)
			}
			name := suffixLabelsInOrder(key, metric.Labels)
			val[fmt.Sprintf("%s_count", name)] = summary.GetSampleCount()
			sumVal := summary.GetSampleSum()
			if validNRValue(sumVal) {
				val[fmt.Sprintf("%s_sum", name)] = sumVal
			}
			for _, q := range summary.GetQuantile() {
				quantileVal := q.GetValue()
				if validNRValue(quantileVal) {
					nameWithQuantileSuffix := fmt.Sprintf(
						"%s_quantile_%s",
						name,
						strconv.FormatFloat(q.GetQuantile(), 'f', -1, 64),
					)
					val[nameWithQuantileSuffix] = quantileVal
				}
			}
		}
		return val, nil
	}
}
func validNRValue(v float64) bool {
	return !math.IsInf(v, 0) && !math.IsNaN(v)
}
func getRandomMetric(metrics definition.RawMetrics) (metricKey string, value definition.RawValue) {
	for metricKey, value = range metrics {
		if _, ok := value.(Metric); !ok {
			continue
		}
		break
	}
	return
}
func metricContainsLabels(m Metric, labels ...string) bool {
	for _, k := range labels {
		if _, ok := m.Labels[k]; !ok {
			return false
		}
	}
	return true
}
func getRandomMetricWithLabels(metrics definition.RawMetrics, labels ...string) (metricKey string, value definition.RawValue, err error) {
	found := false
	for metricKey, value = range metrics {
		m, ok := value.(Metric)
		if !ok {
			continue
		}
		if metricContainsLabels(m, labels...) {
			found = true
			break
		}
	}
	if !found {
		err = fmt.Errorf("metric with the labels %v not found", labels)
	}
	return
}
func fetchMetric(metricKey string) definition.FetchFunc {
	return func(groupLabel, entityID string, groups definition.RawGroups) (definition.FetchedValue, error) {
		value, err := definition.FromRaw(metricKey)(groupLabel, entityID, groups)
		if err != nil {
			return nil, err
		}
		v, ok := value.(Metric)
		if !ok {
			return nil, fmt.Errorf("incompatible metric type. Expected: Metric. Got: %T", value)
		}
		return v, nil
	}
}
func InheritSpecificLabelValuesFrom(parentGroupLabel, relatedMetricKey string, labelsToRetrieve map[string]string) definition.FetchFunc {
	return func(groupLabel, entityID string, groups definition.RawGroups) (definition.FetchedValue, error) {
		rawEntityID, err := getRawEntityID(parentGroupLabel, groupLabel, entityID, groups)
		if err != nil {
			return nil, fmt.Errorf("cannot retrieve the entity ID of metrics to inherit value from, got error: %v", err)
		}
		parent, err := definition.FromRaw(relatedMetricKey)(parentGroupLabel, rawEntityID, groups)
		if err != nil {
			return nil, fmt.Errorf("related metric not found. Metric: %s %s:%s", relatedMetricKey, parentGroupLabel, rawEntityID)
		}
		multiple := make(definition.FetchedValues)
		for k, v := range parent.(Metric).Labels {
			for n, l := range labelsToRetrieve {
				if l == k {
					multiple[n] = v
				}
			}
		}
		return multiple, nil
	}
}
func labelsFromMetric(
	parentGroupLabel string,
	relatedMetricKey string,
	groupLabel string,
	entityID string,
	groups definition.RawGroups,
	prefix string,
) (definition.FetchedValue, error) {
	rawEntityID, err := getRawEntityID(parentGroupLabel, groupLabel, entityID, groups)
	if err != nil {
		return nil, fmt.Errorf(
			"cannot retrieve the entity ID of metrics to inherit labels from, got error: %v",
			err,
		)
	}
	parent, err := fetchMetric(relatedMetricKey)(parentGroupLabel, rawEntityID, groups)
	if err != nil {
		return nil, fmt.Errorf(
			"related metric not found. Metric: %s %s:%s",
			relatedMetricKey,
			parentGroupLabel,
			rawEntityID,
		)
	}
	multiple := make(definition.FetchedValues)
	for k, v := range parent.(Metric).Labels {
		key := fmt.Sprintf(
			"%s.%s",
			prefix,
			strings.TrimPrefix(k, fmt.Sprintf("%s_", prefix)),
		)
		multiple[key] = v
	}
	return multiple, nil
}