// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2025 Datadog, Inc.

package config

import (
	"os"
	"testing"

	"net/url"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"

	"github.com/DataDog/dd-trace-go/v2/internal/telemetry"
	"github.com/DataDog/dd-trace-go/v2/internal/telemetry/telemetrytest"
)

func newTestconfigProvider(sources ...configSource) *configProvider {
	return &configProvider{
		sources: sources,
	}
}

type testConfigSource struct {
	entries     map[string]string
	originValue telemetry.Origin
}

func newTestConfigSource(entries map[string]string, origin telemetry.Origin) *testConfigSource {
	if entries == nil {
		entries = make(map[string]string)
	}
	return &testConfigSource{
		entries:     entries,
		originValue: origin,
	}
}

func (s *testConfigSource) get(key string) string {
	return s.entries[key]
}

func (s *testConfigSource) origin() telemetry.Origin {
	return s.originValue
}

// matchConfig is a helper to create a matcher for telemetry configurations that ignores exact SeqID.
// This is useful since seqId is a global counter and we can't predict its exact value.
// For default origin, use matchDefaultConfig instead to check SeqID=defaultSeqID.
func matchConfig(name, value string, origin telemetry.Origin, id string) func([]telemetry.Configuration) bool {
	return func(configs []telemetry.Configuration) bool {
		if len(configs) != 1 {
			return false
		}
		c := configs[0]
		return c.Name == name && c.Value == value && c.Origin == origin && c.ID == id && c.SeqID > 0
	}
}

// matchDefaultConfig is a helper to create a matcher for default telemetry configurations.
// Default configs should always have SeqID=defaultSeqID (1).
func matchDefaultConfig(name string, value any, origin telemetry.Origin) func([]telemetry.Configuration) bool {
	return func(configs []telemetry.Configuration) bool {
		if len(configs) != 1 {
			return false
		}
		c := configs[0]
		return c.Name == name && c.Value == value && c.Origin == origin && c.ID == telemetry.EmptyID && c.SeqID == defaultSeqID
	}
}

// seqIDCapture is a helper to capture SeqIDs from telemetry calls for verification
type seqIDCapture struct {
	seqIDs map[string]uint64 // key format: "name:value:origin"
}

func newSeqIDCapture() *seqIDCapture {
	return &seqIDCapture{seqIDs: make(map[string]uint64)}
}

func (s *seqIDCapture) key(name, value string, origin telemetry.Origin) string {
	return name + ":" + value + ":" + string(origin)
}

func (s *seqIDCapture) captureMatcher(name, value string, origin telemetry.Origin, id string) func([]telemetry.Configuration) bool {
	return func(configs []telemetry.Configuration) bool {
		if len(configs) != 1 {
			return false
		}
		c := configs[0]
		if c.Name == name && c.Value == value && c.Origin == origin && c.ID == id {
			s.seqIDs[s.key(name, value, origin)] = c.SeqID
			return true
		}
		return false
	}
}

func (s *seqIDCapture) get(name, value string, origin telemetry.Origin) uint64 {
	return s.seqIDs[s.key(name, value, origin)]
}

func TestGetMethods(t *testing.T) {
	t.Run("defaults", func(t *testing.T) {
		// Test that defaults are used when the queried key does not exist
		provider := newTestconfigProvider(newTestConfigSource(nil, telemetry.OriginEnvVar))
		assert.Equal(t, "value", provider.getString("DD_SERVICE", "value"))
		assert.Equal(t, true, provider.getBool("DD_TRACE_DEBUG", true))
		assert.Equal(t, 1, provider.getInt("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", 1))
		assert.Equal(t, 1.0, provider.getFloat("DD_TRACE_SAMPLE_RATE", 1.0))
		assert.Equal(t, &url.URL{Scheme: "http", Host: "localhost:8126"}, provider.getURL("DD_TRACE_AGENT_URL", &url.URL{Scheme: "http", Host: "localhost:8126"}))
	})
	t.Run("non-defaults", func(t *testing.T) {
		// Test that non-defaults are used when the queried key exists
		entries := map[string]string{
			"DD_SERVICE":                       "string",
			"DD_TRACE_DEBUG":                   "true",
			"DD_TRACE_PARTIAL_FLUSH_MIN_SPANS": "1",
			"DD_TRACE_SAMPLE_RATE":             "1.0",
			"DD_TRACE_AGENT_URL":               "https://localhost:8126",
		}
		provider := newTestconfigProvider(newTestConfigSource(entries, telemetry.OriginEnvVar))
		assert.Equal(t, "string", provider.getString("DD_SERVICE", "value"))
		assert.Equal(t, true, provider.getBool("DD_TRACE_DEBUG", false))
		assert.Equal(t, 1, provider.getInt("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", 0))
		assert.Equal(t, 1.0, provider.getFloat("DD_TRACE_SAMPLE_RATE", 0.0))
		assert.Equal(t, &url.URL{Scheme: "https", Host: "localhost:8126"}, provider.getURL("DD_TRACE_AGENT_URL", &url.URL{Scheme: "https", Host: "localhost:8126"}))
	})
	t.Run("getBool accepts various boolean formats", func(t *testing.T) {
		// Test that getBool accepts multiple common boolean representations
		testCases := []struct {
			value    string
			expected bool
		}{
			// Numeric formats (common in environment variables)
			{"1", true},
			{"0", false},
			// Standard true/false
			{"true", true},
			{"false", false},
			// Case variations
			{"TRUE", true},
			{"FALSE", false},
			{"True", true},
			{"False", false},
			// Single character
			{"t", true},
			{"f", false},
			{"T", true},
			{"F", false},
		}

		for _, tc := range testCases {
			entries := map[string]string{"TEST_BOOL": tc.value}
			provider := newTestconfigProvider(newTestConfigSource(entries, telemetry.OriginEnvVar))
			result := provider.getBool("TEST_BOOL", !tc.expected) // Use opposite as default
			assert.Equal(t, tc.expected, result, "Expected %q to parse as %v", tc.value, tc.expected)
		}
	})
	t.Run("getBool returns default for invalid values", func(t *testing.T) {
		// Test that invalid boolean values return the default
		invalidValues := []string{"yes", "no", "2", "-1", "invalid", ""}

		for _, val := range invalidValues {
			entries := map[string]string{"TEST_BOOL": val}
			provider := newTestconfigProvider(newTestConfigSource(entries, telemetry.OriginEnvVar))

			// Should return default for invalid values
			assert.Equal(t, true, provider.getBool("TEST_BOOL", true), "Expected default (true) for invalid value %q", val)
			assert.Equal(t, false, provider.getBool("TEST_BOOL", false), "Expected default (false) for invalid value %q", val)
		}
	})
}

func TestDefaultconfigProvider(t *testing.T) {
	t.Run("Settings only exist in EnvConfigSource", func(t *testing.T) {
		// Setup: environment variables of each type
		t.Setenv("DD_SERVICE", "string")
		t.Setenv("DD_TRACE_DEBUG", "true")
		t.Setenv("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", "1")
		t.Setenv("DD_TRACE_SAMPLE_RATE", "1.0")
		t.Setenv("DD_TRACE_AGENT_URL", "https://localhost:8126")
		// TODO: Add more types as we go along

		provider := defaultconfigProvider()

		// Configured values are returned correctly
		assert.Equal(t, "string", provider.getString("DD_SERVICE", "value"))
		assert.Equal(t, true, provider.getBool("DD_TRACE_DEBUG", false))
		assert.Equal(t, 1, provider.getInt("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", 0))
		assert.Equal(t, 1.0, provider.getFloat("DD_TRACE_SAMPLE_RATE", 0.0))
		assert.Equal(t, &url.URL{Scheme: "https", Host: "localhost:8126"}, provider.getURL("DD_TRACE_AGENT_URL", &url.URL{Scheme: "https", Host: "localhost:8126"}))

		// Defaults are returned for settings that are not configured
		assert.Equal(t, "value", provider.getString("DD_ENV", "value"))
	})

	t.Run("Settings only exist in OtelEnvConfigSource", func(t *testing.T) {
		t.Setenv("OTEL_SERVICE_NAME", "string")
		t.Setenv("OTEL_LOG_LEVEL", "debug")
		t.Setenv("OTEL_TRACES_SAMPLER", "parentbased_always_on")
		t.Setenv("OTEL_TRACES_EXPORTER", "1.0")
		t.Setenv("OTEL_PROPAGATORS", "https://localhost:8126")
		t.Setenv("OTEL_RESOURCE_ATTRIBUTES", "key1=value1,key2=value2")

		provider := defaultconfigProvider()

		assert.Equal(t, "string", provider.getString("DD_SERVICE", "value"))
		assert.Equal(t, true, provider.getBool("DD_TRACE_DEBUG", false))
		assert.Equal(t, 1.0, provider.getFloat("DD_TRACE_SAMPLE_RATE", 0))
		assert.Equal(t, 1.0, provider.getFloat("DD_TRACE_SAMPLE_RATE", 0.0))
		assert.Equal(t, &url.URL{Scheme: "https", Host: "localhost:8126"}, provider.getURL("DD_TRACE_AGENT_URL", &url.URL{Scheme: "https", Host: "localhost:8126"}))
		assert.Equal(t, "key1:value1,key2:value2", provider.getString("DD_TAGS", "key:value"))
	})
	t.Run("Settings only exist in localDeclarativeConfigSource", func(t *testing.T) {
		const localYaml = `
apm_configuration_default:
  DD_SERVICE: local
  DD_TRACE_DEBUG: true
  DD_TRACE_PARTIAL_FLUSH_MIN_SPANS: "1"
  DD_TRACE_SAMPLE_RATE: 1.0
  DD_TRACE_AGENT_URL: https://localhost:8126
`

		tempLocalPath := "local.yml"
		err := os.WriteFile(tempLocalPath, []byte(localYaml), 0644)
		assert.NoError(t, err)
		defer os.Remove(tempLocalPath)

		tempLocalSource := newDeclarativeConfigSource(tempLocalPath, telemetry.OriginLocalStableConfig)
		provider := newTestconfigProvider(
			newDeclarativeConfigSource(managedFilePath, telemetry.OriginManagedStableConfig),
			new(envConfigSource),
			new(otelEnvConfigSource),
			tempLocalSource,
		)

		assert.Equal(t, "local", provider.getString("DD_SERVICE", "value"))
		assert.Equal(t, true, provider.getBool("DD_TRACE_DEBUG", false))
		assert.Equal(t, 1, provider.getInt("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", 0))
		assert.Equal(t, 1.0, provider.getFloat("DD_TRACE_SAMPLE_RATE", 0.0))
		assert.Equal(t, &url.URL{Scheme: "https", Host: "localhost:8126"}, provider.getURL("DD_TRACE_AGENT_URL", &url.URL{Scheme: "https", Host: "localhost:8126"}))

		// Defaults are returned for settings that are not configured
		assert.Equal(t, "value", provider.getString("DD_ENV", "value"))
	})

	t.Run("Settings only exist in managed declarativeConfigSource", func(t *testing.T) {
		const managedYaml = `
apm_configuration_default:
  DD_SERVICE: managed
  DD_TRACE_DEBUG: true
  DD_TRACE_PARTIAL_FLUSH_MIN_SPANS: "1"
  DD_TRACE_SAMPLE_RATE: 1.0
  DD_TRACE_AGENT_URL: https://localhost:8126`

		tempManagedPath := "managed.yml"
		err := os.WriteFile(tempManagedPath, []byte(managedYaml), 0644)
		assert.NoError(t, err)
		defer os.Remove(tempManagedPath)

		tempManagedSource := newDeclarativeConfigSource(tempManagedPath, telemetry.OriginManagedStableConfig)
		provider := newTestconfigProvider(
			tempManagedSource,
			new(envConfigSource),
			new(otelEnvConfigSource),
			newDeclarativeConfigSource(localFilePath, telemetry.OriginLocalStableConfig),
		)

		assert.Equal(t, "managed", provider.getString("DD_SERVICE", "value"))
		assert.Equal(t, true, provider.getBool("DD_TRACE_DEBUG", false))
		assert.Equal(t, 1, provider.getInt("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", 0))
		assert.Equal(t, 1.0, provider.getFloat("DD_TRACE_SAMPLE_RATE", 0.0))
		assert.Equal(t, &url.URL{Scheme: "https", Host: "localhost:8126"}, provider.getURL("DD_TRACE_AGENT_URL", &url.URL{Scheme: "https", Host: "localhost:8126"}))

		// Defaults are returned for settings that are not configured
		assert.Equal(t, "value", provider.getString("DD_ENV", "value"))
	})
	t.Run("Settings exist in all ConfigSources", func(t *testing.T) {
		// Priority order (highest to lowest):
		// 1. managed declarativeConfigSource
		// 2. EnvConfigSource (DD_* env vars)
		// 3. OtelEnvConfigSource (OTEL_* env vars)
		// 4. local declarativeConfigSource

		// Setup: Configure the same keys across multiple sources with different values
		// to verify that the correct precedence is applied

		localYaml := `
apm_configuration_default:
  DD_SERVICE: local_service           # Set in all 4 sources - should lose to Managed
  DD_TRACE_DEBUG: false                # Set in all 4 sources - should lose to Managed
  DD_ENV: local_env                    # Set in 3 sources (Local, DD Env, OTEL) - should lose to DD Env
  DD_VERSION: 0.1.0                    # Set in 2 sources (Local, Managed) - should lose to Managed
  DD_TRACE_SAMPLE_RATE: 0.1            # Set in 2 sources (Local, OTEL) - should lose to OTEL
  DD_TRACE_STARTUP_LOGS: true          # Only in Local - should WIN (lowest priority available)
`

		managedYaml := `
apm_configuration_default:
  DD_SERVICE: managed_service          # Set in all 4 sources - should WIN (highest priority)
  DD_TRACE_DEBUG: true                 # Set in all 4 sources - should WIN (highest priority)
  DD_VERSION: 1.0.0                    # Set in 2 sources (Local, Managed) - should WIN
  DD_TRACE_PARTIAL_FLUSH_ENABLED: true # Set in 2 sources (Managed, DD Env) - should WIN
`

		// DD Env vars - priority level 2
		t.Setenv("DD_SERVICE", "env_service")               // Set in all 4 sources - should lose to Managed
		t.Setenv("DD_TRACE_DEBUG", "false")                 // Set in all 4 sources - should lose to Managed
		t.Setenv("DD_ENV", "env_environment")               // Set in 3 sources - should WIN (higher than OTEL and Local)
		t.Setenv("DD_TRACE_PARTIAL_FLUSH_ENABLED", "false") // Set in 2 sources - should lose to Managed
		t.Setenv("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", "100") // Only in DD Env - should WIN

		// OTEL Env vars - priority level 3
		t.Setenv("OTEL_SERVICE_NAME", "otel_service")                                                 // Set in all 4 sources (maps to DD_SERVICE) - should lose to Managed
		t.Setenv("OTEL_LOG_LEVEL", "debug")                                                           // Set in all 4 sources (maps to DD_TRACE_DEBUG) - should lose to Managed
		t.Setenv("OTEL_RESOURCE_ATTRIBUTES", "deployment.environment=otel_env,service.version=0.5.0") // Set in 3 sources - should lose to DD Env for DD_ENV, but provide version if not in higher sources
		t.Setenv("OTEL_TRACES_SAMPLER", "traceidratio")                                               // Set in 2 sources (OTEL, Local) - should WIN over Local (maps to DD_TRACE_SAMPLE_RATE)
		t.Setenv("OTEL_TRACES_SAMPLER_ARG", "0.8")                                                    // Provides sample rate value of 0.8

		// Create config files
		tempLocalPath := "local.yml"
		err := os.WriteFile(tempLocalPath, []byte(localYaml), 0644)
		assert.NoError(t, err)
		defer os.Remove(tempLocalPath)

		tempLocalSource := newDeclarativeConfigSource(tempLocalPath, telemetry.OriginLocalStableConfig)

		tempManagedPath := "managed.yml"
		err = os.WriteFile(tempManagedPath, []byte(managedYaml), 0644)
		assert.NoError(t, err)
		defer os.Remove(tempManagedPath)

		tempManagedSource := newDeclarativeConfigSource(tempManagedPath, telemetry.OriginManagedStableConfig)

		provider := newTestconfigProvider(
			tempManagedSource,
			new(envConfigSource),
			new(otelEnvConfigSource),
			tempLocalSource,
		)

		// Assertions grouped by which source should win

		// Managed Config wins (set in all 4 sources)
		assert.Equal(t, "managed_service", provider.getString("DD_SERVICE", "default"),
			"DD_SERVICE: Managed should win over DD Env, OTEL, and Local")
		assert.Equal(t, true, provider.getBool("DD_TRACE_DEBUG", false),
			"DD_TRACE_DEBUG: Managed should win over DD Env, OTEL, and Local")

		// Managed Config wins (set in 2 sources: Managed + one other)
		assert.Equal(t, "1.0.0", provider.getString("DD_VERSION", "default"),
			"DD_VERSION: Managed should win over Local")
		assert.Equal(t, true, provider.getBool("DD_TRACE_PARTIAL_FLUSH_ENABLED", false),
			"DD_TRACE_PARTIAL_FLUSH_ENABLED: Managed should win over DD Env")

		// DD Env wins (set in 3 sources: DD Env, OTEL, Local)
		assert.Equal(t, "env_environment", provider.getString("DD_ENV", "default"),
			"DD_ENV: DD Env should win over OTEL and Local")

		// DD Env wins (only in DD Env)
		assert.Equal(t, 100, provider.getInt("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", 0),
			"DD_TRACE_PARTIAL_FLUSH_MIN_SPANS: DD Env should win (only source)")

		// OTEL Env wins (set in 2 sources: OTEL, Local)
		assert.Equal(t, 0.8, provider.getFloat("DD_TRACE_SAMPLE_RATE", 0.0),
			"DD_TRACE_SAMPLE_RATE: OTEL should win over Local")

		// Local Config wins (only in Local)
		assert.Equal(t, true, provider.getBool("DD_TRACE_STARTUP_LOGS", false),
			"DD_TRACE_STARTUP_LOGS: Local should win (only source)")

		// Defaults are returned for settings not configured anywhere
		assert.Equal(t, "default", provider.getString("DD_TRACE_AGENT_URL", "default"),
			"Unconfigured setting should return default")
	})
}

func TestConfigProviderTelemetryRegistration(t *testing.T) {
	t.Run("env source reports telemetry for all getters", func(t *testing.T) {
		telemetryClient := new(telemetrytest.MockClient)
		// Allow any telemetry calls without failing
		telemetryClient.On("RegisterAppConfigs", mock.Anything).Return().Maybe()
		defer telemetry.MockClient(telemetryClient)()

		source := newTestConfigSource(map[string]string{
			"DD_SERVICE":                       "service",
			"DD_TRACE_DEBUG":                   "true",
			"DD_TRACE_PARTIAL_FLUSH_MIN_SPANS": "100",
			"DD_TRACE_SAMPLE_RATE":             "0.5",
			"DD_TRACE_AGENT_URL":               "http://localhost:8126",
			"DD_SERVICE_MAPPING":               "old:new",
			"DD_TRACE_ABANDONED_SPAN_TIMEOUT":  "10s",
		}, telemetry.OriginEnvVar)
		provider := newTestconfigProvider(source)

		_ = provider.getString("DD_SERVICE", "default")
		_ = provider.getBool("DD_TRACE_DEBUG", false)
		_ = provider.getInt("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", 0)
		_ = provider.getFloat("DD_TRACE_SAMPLE_RATE", 0.0)
		_ = provider.getURL("DD_TRACE_AGENT_URL", nil)
		_ = provider.getMap("DD_SERVICE_MAPPING", nil)
		_ = provider.getDuration("DD_TRACE_ABANDONED_SPAN_TIMEOUT", 0)

		// Assert that the env_var values were reported (don't care about defaults or exact SeqID)
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_SERVICE", "service", telemetry.OriginEnvVar, telemetry.EmptyID)))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_TRACE_DEBUG", "true", telemetry.OriginEnvVar, telemetry.EmptyID)))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", "100", telemetry.OriginEnvVar, telemetry.EmptyID)))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_TRACE_SAMPLE_RATE", "0.5", telemetry.OriginEnvVar, telemetry.EmptyID)))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_TRACE_AGENT_URL", "http://localhost:8126", telemetry.OriginEnvVar, telemetry.EmptyID)))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_SERVICE_MAPPING", "old:new", telemetry.OriginEnvVar, telemetry.EmptyID)))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_TRACE_ABANDONED_SPAN_TIMEOUT", "10s", telemetry.OriginEnvVar, telemetry.EmptyID)))
	})

	t.Run("declarative source reports telemetry with ID", func(t *testing.T) {
		telemetryClient := new(telemetrytest.MockClient)
		// Allow any telemetry calls without failing
		telemetryClient.On("RegisterAppConfigs", mock.Anything).Return().Maybe()
		defer telemetry.MockClient(telemetryClient)()

		// Values expected as raw strings, with OriginLocalStableConfig and ID from file
		yaml := `config_id: 123
apm_configuration_default:
  DD_SERVICE: svc
  DD_TRACE_DEBUG: true
  DD_TRACE_PARTIAL_FLUSH_MIN_SPANS: "7"
  DD_TRACE_SAMPLE_RATE: 0.9
  DD_TRACE_AGENT_URL: http://127.0.0.1:8126
  DD_SERVICE_MAPPING: a:b
  DD_TRACE_ABANDONED_SPAN_TIMEOUT: 2s
`
		temp := "decl.yml"
		require.NoError(t, os.WriteFile(temp, []byte(yaml), 0644))
		defer os.Remove(temp)

		decl := newDeclarativeConfigSource(temp, telemetry.OriginLocalStableConfig)
		provider := newTestconfigProvider(decl)

		_ = provider.getString("DD_SERVICE", "default")
		_ = provider.getBool("DD_TRACE_DEBUG", false)
		_ = provider.getInt("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", 0)
		_ = provider.getFloat("DD_TRACE_SAMPLE_RATE", 0.0)
		_ = provider.getURL("DD_TRACE_AGENT_URL", nil)
		_ = provider.getMap("DD_SERVICE_MAPPING", nil)
		_ = provider.getDuration("DD_TRACE_ABANDONED_SPAN_TIMEOUT", 0)

		// Assert that the declarative source values were reported with the correct ID (don't care about exact SeqID)
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_SERVICE", "svc", telemetry.OriginLocalStableConfig, "123")))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_TRACE_DEBUG", "true", telemetry.OriginLocalStableConfig, "123")))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", "7", telemetry.OriginLocalStableConfig, "123")))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_TRACE_SAMPLE_RATE", "0.9", telemetry.OriginLocalStableConfig, "123")))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_TRACE_AGENT_URL", "http://127.0.0.1:8126", telemetry.OriginLocalStableConfig, "123")))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_SERVICE_MAPPING", "a:b", telemetry.OriginLocalStableConfig, "123")))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_TRACE_ABANDONED_SPAN_TIMEOUT", "2s", telemetry.OriginLocalStableConfig, "123")))
	})

	t.Run("source priority with config IDs and SeqID", func(t *testing.T) {
		// Comprehensive test that verifies:
		// 1. ALL sources with non-empty values report telemetry (not just the winning one)
		// 2. The first (highest priority) source's value is returned
		// 3. SeqID increases with source priority (higher priority = higher SeqID)
		// 4. Config IDs are preserved in telemetry reports
		// 5. Only sources with values for a given key report for that key
		// 6. Default configs always have SeqID=defaultSeqID (1)

		yamlManaged := `config_id: managed-123
apm_configuration_default:
  DD_SERVICE: managed-service
`
		yamlLocal := `config_id: local-456
apm_configuration_default:
  DD_SERVICE: local-service
  DD_ENV: local-env
`
		tempManaged := "test_managed.yml"
		tempLocal := "test_local.yml"

		require.NoError(t, os.WriteFile(tempManaged, []byte(yamlManaged), 0644))
		require.NoError(t, os.WriteFile(tempLocal, []byte(yamlLocal), 0644))
		defer os.Remove(tempManaged)
		defer os.Remove(tempLocal)

		capture := newSeqIDCapture()
		telemetryClient := new(telemetrytest.MockClient)
		// Allow any telemetry calls without failing
		telemetryClient.On("RegisterAppConfigs", mock.Anything).Return().Maybe()
		defer telemetry.MockClient(telemetryClient)()

		tempManagedSource := newDeclarativeConfigSource(tempManaged, telemetry.OriginManagedStableConfig)
		envSource := newTestConfigSource(map[string]string{"DD_SERVICE": "env-service"}, telemetry.OriginEnvVar)
		tempLocalSource := newDeclarativeConfigSource(tempLocal, telemetry.OriginLocalStableConfig)

		// Priority order: Managed (highest) -> Env -> Local (lowest) = 3 sources total
		provider := newTestconfigProvider(tempManagedSource, envSource, tempLocalSource)

		// Test DD_SERVICE: all 3 sources have values, managed wins
		result := provider.getString("DD_SERVICE", "default-service")
		assert.Equal(t, "managed-service", result, "Managed (highest priority) should win")

		// Verify ALL 3 sources reported telemetry for DD_SERVICE and capture their SeqIDs
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(capture.captureMatcher("DD_SERVICE", "managed-service", telemetry.OriginManagedStableConfig, "managed-123")))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(capture.captureMatcher("DD_SERVICE", "env-service", telemetry.OriginEnvVar, telemetry.EmptyID)))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(capture.captureMatcher("DD_SERVICE", "local-service", telemetry.OriginLocalStableConfig, "local-456")))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchDefaultConfig("DD_SERVICE", "default-service", telemetry.OriginDefault)))

		// Verify SeqID ordering: Managed (highest priority) > Env > Local (lowest priority)
		managedSeq := capture.get("DD_SERVICE", "managed-service", telemetry.OriginManagedStableConfig)
		envSeq := capture.get("DD_SERVICE", "env-service", telemetry.OriginEnvVar)
		localSeq := capture.get("DD_SERVICE", "local-service", telemetry.OriginLocalStableConfig)
		assert.Greater(t, managedSeq, envSeq, "Managed (highest priority) should have higher SeqID than Env")
		assert.Greater(t, envSeq, localSeq, "Env should have higher SeqID than Local (lowest priority)")
		assert.Greater(t, localSeq, defaultSeqID, "All non-default configs should have SeqID > defaultSeqID")

		// Test DD_ENV: only local has a value
		env := provider.getString("DD_ENV", "default-env")
		assert.Equal(t, "local-env", env)

		// Verify only local reported telemetry for DD_ENV (others don't have it)
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchConfig("DD_ENV", "local-env", telemetry.OriginLocalStableConfig, "local-456")))
		telemetryClient.AssertCalled(t, "RegisterAppConfigs", mock.MatchedBy(matchDefaultConfig("DD_ENV", "default-env", telemetry.OriginDefault)))
	})

	t.Run("still reports defaults via telemetry when key missing or invalid", func(t *testing.T) {
		telemetryClient := new(telemetrytest.MockClient)

		strKey, strDef := "DD_SERVICE", "default_service"
		boolKey, boolDef := "DD_TRACE_DEBUG", true
		intKey, intDef := "DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", 7
		floatKey, floatDef := "DD_TRACE_SAMPLE_RATE", 0.25
		durKey, durDef := "DD_TRACE_ABANDONED_SPAN_TIMEOUT", 42*time.Second
		urlKey, urlDef := "DD_TRACE_AGENT_URL", &url.URL{Scheme: "http", Host: "localhost:9000"}
		mapKey, mapDef := "DD_SERVICE_MAPPING", map[string]string{"a": "b"}

		// Set up strict expectations - ONLY defaults should be reported with SeqID=defaultSeqID
		telemetryClient.On("RegisterAppConfigs", []telemetry.Configuration{{Name: strKey, Value: strDef, Origin: telemetry.OriginDefault, ID: telemetry.EmptyID, SeqID: defaultSeqID}}).Return()
		telemetryClient.On("RegisterAppConfigs", []telemetry.Configuration{{Name: boolKey, Value: boolDef, Origin: telemetry.OriginDefault, ID: telemetry.EmptyID, SeqID: defaultSeqID}}).Return()
		telemetryClient.On("RegisterAppConfigs", []telemetry.Configuration{{Name: intKey, Value: intDef, Origin: telemetry.OriginDefault, ID: telemetry.EmptyID, SeqID: defaultSeqID}}).Return()
		telemetryClient.On("RegisterAppConfigs", []telemetry.Configuration{{Name: floatKey, Value: floatDef, Origin: telemetry.OriginDefault, ID: telemetry.EmptyID, SeqID: defaultSeqID}}).Return()
		telemetryClient.On("RegisterAppConfigs", []telemetry.Configuration{{Name: durKey, Value: durDef, Origin: telemetry.OriginDefault, ID: telemetry.EmptyID, SeqID: defaultSeqID}}).Return()
		telemetryClient.On("RegisterAppConfigs", []telemetry.Configuration{{Name: urlKey, Value: urlDef, Origin: telemetry.OriginDefault, ID: telemetry.EmptyID, SeqID: defaultSeqID}}).Return()
		telemetryClient.On("RegisterAppConfigs", []telemetry.Configuration{{Name: mapKey, Value: mapDef, Origin: telemetry.OriginDefault, ID: telemetry.EmptyID, SeqID: defaultSeqID}}).Return()
		defer telemetry.MockClient(telemetryClient)()

		// Use an empty test source to force defaults
		provider := newTestconfigProvider(newTestConfigSource(map[string]string{}, telemetry.OriginEnvVar))

		// Defaults should be used and reported
		assert.Equal(t, strDef, provider.getString(strKey, strDef))
		assert.Equal(t, boolDef, provider.getBool(boolKey, boolDef))
		assert.Equal(t, intDef, provider.getInt(intKey, intDef))
		assert.Equal(t, floatDef, provider.getFloat(floatKey, floatDef))
		assert.Equal(t, durDef, provider.getDuration(durKey, durDef))
		assert.Equal(t, urlDef, provider.getURL(urlKey, urlDef))
		assert.Equal(t, mapDef, provider.getMap(mapKey, mapDef))

		// Verify that ONLY the expected defaults were reported (strict)
		telemetryClient.AssertExpectations(t)
	})
}
