// Code generated by mdatagen. DO NOT EDIT.

package metadata

import (
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/zap"
	"go.uber.org/zap/zaptest/observer"

	"go.opentelemetry.io/collector/featuregate"
	"go.opentelemetry.io/collector/pdata/pcommon"
	"go.opentelemetry.io/collector/pdata/pmetric"
	"go.opentelemetry.io/collector/scraper/scrapertest"
)

type testDataSet int

const (
	testDataSetDefault testDataSet = iota
	testDataSetAll
	testDataSetNone
	testDataSetReag
)

func TestMetricsBuilder(t *testing.T) {
	tests := []struct {
		name        string
		metricsSet  testDataSet
		resAttrsSet testDataSet
		expectEmpty bool
	}{
		{
			name: "default",
		},
		{
			name:        "all_set",
			metricsSet:  testDataSetAll,
			resAttrsSet: testDataSetAll,
		},
		{
			name:        "reaggregate_set",
			metricsSet:  testDataSetReag,
			resAttrsSet: testDataSetReag,
		},
		{
			name:        "none_set",
			metricsSet:  testDataSetNone,
			resAttrsSet: testDataSetNone,
			expectEmpty: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			start := pcommon.Timestamp(1_000_000_000)
			ts := pcommon.Timestamp(1_000_001_000)
			observedZapCore, observedLogs := observer.New(zap.WarnLevel)
			settings := scrapertest.NewNopSettings(scrapertest.NopType)
			settings.Logger = zap.New(observedZapCore)
			if tt.name == "all_set" {
				require.NoError(t, featuregate.GlobalRegistry().Set(
					"scraper.samplemigration.EmitV1SystemConventions", true))
				t.Cleanup(func() {
					featuregate.GlobalRegistry().Set("scraper.samplemigration.EmitV1SystemConventions", false)
				})
				require.NoError(t, featuregate.GlobalRegistry().Set(
					"scraper.samplemigration.EmitV1SystemConventions", true))
				t.Cleanup(func() {
					featuregate.GlobalRegistry().Set("scraper.samplemigration.EmitV1SystemConventions", false)
				})
			}
			mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start))
			aggMap := make(map[string]string) // contains the aggregation strategies for each metric name
			aggMap["system.cpu.utilization"] = mb.metricSystemCPUUtilization.config.AggregationStrategy
			aggMap["system.cpu.utilization@v1"] = mb.metricSystemCPUUtilizationV1.config.AggregationStrategy

			expectedWarnings := 0
			if tt.name == "all_set" {
				expectedWarnings++ // type differs
				expectedWarnings++ // attributes differ
			}
			if tt.metricsSet != testDataSetReag {
				assert.Equal(t, expectedWarnings, observedLogs.Len())
			}

			defaultMetricsCount := 0
			allMetricsCount := 0
			if tt.name != "all_set" {

				allMetricsCount++
				mb.RecordLinuxMemoryAvailableDataPoint(ts, 1)
			}

			allMetricsCount++
			mb.RecordSystemCPUFooDataPoint(ts, 1)
			if tt.name != "all_set" {
				defaultMetricsCount++
				allMetricsCount++
				mb.RecordSystemCPUUtilizationDataPoint(ts, 1, "cpu-val", AttributeStateIdle, 18, AttributeCPUModeSystem)
			}

			res := pcommon.NewResource()
			metrics := mb.Emit(WithResource(res))
			if tt.name == "reaggregate_set" {
				assert.Empty(t, mb.metricSystemCPUUtilization.aggDataPoints)
				assert.Empty(t, mb.metricSystemCPUUtilizationV1.aggDataPoints)
			}

			if tt.expectEmpty {
				assert.Equal(t, 0, metrics.ResourceMetrics().Len())
				return
			}

			var allMetricsList []pmetric.Metric
			totalMetricsCount := 0
			for ri := 0; ri < metrics.ResourceMetrics().Len(); ri++ {
				rm := metrics.ResourceMetrics().At(ri)
				assert.Equal(t, 1, rm.ScopeMetrics().Len())
				ms := rm.ScopeMetrics().At(0).Metrics()
				totalMetricsCount += ms.Len()
				for mi := 0; mi < ms.Len(); mi++ {
					allMetricsList = append(allMetricsList, ms.At(mi))
				}
			}
			if tt.metricsSet == testDataSetDefault {
				assert.Equal(t, defaultMetricsCount, totalMetricsCount)
			}
			if tt.metricsSet == testDataSetAll {
				assert.Equal(t, allMetricsCount, totalMetricsCount)
			}
			validatedMetrics := make(map[string]bool)
			for _, mi := range allMetricsList {
				switch mi.Name() {
				case "system.cpu.foo":
					assert.False(t, validatedMetrics["system.cpu.foo"], "Found a duplicate in the metrics slice: system.cpu.foo")
					validatedMetrics["system.cpu.foo"] = true
					assert.Equal(t, pmetric.MetricTypeGauge, mi.Type())
					assert.Equal(t, 1, mi.Gauge().DataPoints().Len())
					assert.Equal(t, "Example v1-only metric, disabled by default.", mi.Description())
					assert.Equal(t, "1", mi.Unit())
					dp := mi.Gauge().DataPoints().At(0)
					assert.Equal(t, start, dp.StartTimestamp())
					assert.Equal(t, ts, dp.Timestamp())
					assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType())
					assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01)
				}
			}
		})
	}
}
func TestVersionedMetrics(t *testing.T) {
	t.Run("linux.memory.available", func(t *testing.T) {
		tests := []struct {
			name               string
			disableOld         bool
			enableNew          bool
			expectLegacyMetric bool
			expectNewMetric    bool
		}{
			{
				name:               "legacy_only",
				disableOld:         false,
				enableNew:          false,
				expectLegacyMetric: true,
				expectNewMetric:    false,
			},
			{
				name:               "dual_emission",
				disableOld:         false,
				enableNew:          true,
				expectLegacyMetric: true,
				expectNewMetric:    true,
			},

			{
				name:               "new_only",
				disableOld:         true,
				enableNew:          true,
				expectLegacyMetric: false,
				expectNewMetric:    true,
			},
		}

		for _, tt := range tests {
			t.Run(tt.name, func(t *testing.T) {
				require.NoError(t, featuregate.GlobalRegistry().Set(
					"scraper.samplemigration.DontEmitV0SystemConventions", tt.disableOld))
				require.NoError(t, featuregate.GlobalRegistry().Set(
					"scraper.samplemigration.EmitV1SystemConventions", tt.enableNew))
				t.Cleanup(func() {
					featuregate.GlobalRegistry().Set("scraper.samplemigration.DontEmitV0SystemConventions", false)
					featuregate.GlobalRegistry().Set("scraper.samplemigration.EmitV1SystemConventions", false)
				})

				start := pcommon.Timestamp(1_000_000_000)
				ts := pcommon.Timestamp(1_000_001_000)
				observedZapCore, observedLogs := observer.New(zap.WarnLevel)
				settings := scrapertest.NewNopSettings(scrapertest.NopType)
				settings.Logger = zap.New(observedZapCore)
				mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, "all_set"), settings, WithStartTime(start))

				mb.RecordLinuxMemoryAvailableDataPoint(ts, 1)

				metrics := mb.Emit(WithResource(pcommon.NewResource()))

				// Count metrics by name and type
				var legacyFound, newFound bool
				for ri := 0; ri < metrics.ResourceMetrics().Len(); ri++ {
					ms := metrics.ResourceMetrics().At(ri).ScopeMetrics().At(0).Metrics()
					for mi := 0; mi < ms.Len(); mi++ {
						m := ms.At(mi)
						// Different emitted names - distinguish by name
						if m.Name() == "linux.memory.available" {
							legacyFound = true
						}
						if m.Name() == "system.memory.linux.available" {
							newFound = true
						}
					}
				}
				assert.Equal(t, tt.expectLegacyMetric, legacyFound)
				assert.Equal(t, tt.expectNewMetric, newFound)
				// For metrics with different emitted names, no collison warning shoulds be logged
				// This guards against the regression where same name collision logic was
				// incorrectly applied to renamed metrics.
				if tt.enableNew {
					for _, log := range observedLogs.All() {
						if strings.Contains(log.Message, "linux.memory.available") {
							assert.NotContains(t, log.Message, "same emitted name",
								"should not log same name collision warning for metrics with different names")
						}
					}
				}
			})
		}
	})
	t.Run("system.cpu.utilization", func(t *testing.T) {
		tests := []struct {
			name               string
			disableOld         bool
			enableNew          bool
			expectLegacyMetric bool
			expectNewMetric    bool
			expectLegacyAttrs  bool
		}{
			{
				name:               "legacy_only",
				disableOld:         false,
				enableNew:          false,
				expectLegacyMetric: true,
				expectNewMetric:    false,
			},
			{
				name:               "dual_emission",
				disableOld:         false,
				enableNew:          true,
				expectLegacyMetric: false,
				expectNewMetric:    true,
				expectLegacyAttrs:  true,
			},

			{
				name:               "new_only",
				disableOld:         true,
				enableNew:          true,
				expectLegacyMetric: false,
				expectNewMetric:    true,
				expectLegacyAttrs:  false,
			},
		}

		for _, tt := range tests {
			t.Run(tt.name, func(t *testing.T) {
				require.NoError(t, featuregate.GlobalRegistry().Set(
					"scraper.samplemigration.DontEmitV0SystemConventions", tt.disableOld))
				require.NoError(t, featuregate.GlobalRegistry().Set(
					"scraper.samplemigration.EmitV1SystemConventions", tt.enableNew))
				t.Cleanup(func() {
					featuregate.GlobalRegistry().Set("scraper.samplemigration.DontEmitV0SystemConventions", false)
					featuregate.GlobalRegistry().Set("scraper.samplemigration.EmitV1SystemConventions", false)
				})

				start := pcommon.Timestamp(1_000_000_000)
				ts := pcommon.Timestamp(1_000_001_000)
				settings := scrapertest.NewNopSettings(scrapertest.NopType)
				mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, "all_set"), settings, WithStartTime(start))

				mb.RecordSystemCPUUtilizationDataPoint(ts, 1, "cpu-val", AttributeStateIdle, 18, AttributeCPUModeSystem)

				metrics := mb.Emit(WithResource(pcommon.NewResource()))

				// Count metrics by name and type
				var legacyFound, newFound bool
				for ri := 0; ri < metrics.ResourceMetrics().Len(); ri++ {
					ms := metrics.ResourceMetrics().At(ri).ScopeMetrics().At(0).Metrics()
					for mi := 0; mi < ms.Len(); mi++ {
						m := ms.At(mi)
						// Same emitted name, different types - distinguish by type
						if m.Name() == "system.cpu.utilization" {
							if m.Type() == pmetric.MetricTypeGauge {
								legacyFound = true
							}
							if m.Type() == pmetric.MetricTypeSum {
								newFound = true
								if tt.expectLegacyAttrs {
									dp := m.Sum().DataPoints().At(0)
									_, hasCPU := dp.Attributes().Get("cpu")
									assert.True(t, hasCPU, "expected legacy attr cpu")
									_, hasState := dp.Attributes().Get("state")
									assert.True(t, hasState, "expected legacy attr state")
								}
							}
						}
					}
				}
				assert.Equal(t, tt.expectLegacyMetric, legacyFound)
				assert.Equal(t, tt.expectNewMetric, newFound)
			})
		}
	})
}
