package config

import (
	"encoding/json"
	"testing"

	"github.com/creasty/defaults"
	"github.com/stretchr/testify/require"
)

func TestDataPipelineConfigDefaults(t *testing.T) {
	t.Parallel()

	config := new(CentralConfig)
	require.NoError(t, defaults.Set(config))
	require.Equal(t, uint32(30), config.DataPipeline.ObservationIntervalSeconds)
	require.Equal(t, uint32(120), config.DataPipeline.ObservationStaleSeconds)
	require.Empty(t, config.DataPipeline.LakeBaseURL)
	require.Empty(t, config.DataPipeline.LakeHMACSecret)
	// An unconfigured deployment must start without any Lake settings.
	require.NoError(t, config.DataPipeline.ValidateRuntime())
}

// The whole CentralConfig is written to the debug log with zap.Reflect, which
// encodes it as JSON. The Lake HMAC secret lives in that struct, so the only
// thing keeping it out of the log is its type refusing to marshal itself.
func TestLakeHMACSecretNeverMarshalsIntoTheConfigDump(t *testing.T) {
	t.Parallel()

	const secret = "a-real-looking-hmac-secret"
	config := CentralConfig{DataPipeline: DataPipelineConfig{
		LakeBaseURL:    "https://lake.example.test",
		LakeHMACSecret: secret,
	}}

	encoded, err := json.Marshal(config)
	require.NoError(t, err)
	require.NotContains(t, string(encoded), secret)
	require.Contains(t, string(encoded), "[REDACTED]")

	// Nor through the formatting verbs, which is the other way a value like
	// this reaches a log line.
	require.NotContains(t, config.DataPipeline.LakeHMACSecret.String(), secret)

	// It is still readable by the one caller that needs it.
	require.Equal(t, secret, config.DataPipeline.LakeHMACSecret.Reveal())
}

func TestDataPipelineConfigValidation(t *testing.T) {
	t.Parallel()

	valid := DataPipelineConfig{
		LakeBaseURL:                "https://lake.example.test",
		LakeHMACSecret:             "test-hmac-secret",
		ObservationIntervalSeconds: 30,
		ObservationStaleSeconds:    120,
	}
	tests := map[string]struct {
		mutate func(*DataPipelineConfig)
		want   string
	}{
		"enabled valid": {},

		"URL path rejected": {
			mutate: func(config *DataPipelineConfig) { config.LakeBaseURL = "https://lake.example.test/api" },
			want:   "must be an HTTP(S) origin",
		},
		"missing HMAC": {
			mutate: func(config *DataPipelineConfig) { config.LakeHMACSecret = "" },
			want:   "Lake HMAC secret is required",
		},
		"blank HMAC": {
			mutate: func(config *DataPipelineConfig) { config.LakeHMACSecret = "   " },
			want:   "Lake HMAC secret is required",
		},
		"stale shorter than interval": {
			mutate: func(config *DataPipelineConfig) { config.ObservationStaleSeconds = 20 },
			want:   "stale threshold",
		},
		"an unconfigured deployment needs no Lake settings": {
			mutate: func(config *DataPipelineConfig) {
				config.LakeBaseURL = ""
				config.LakeHMACSecret = ""
			},
		},
	}
	for name, test := range tests {
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			config := valid
			if test.mutate != nil {
				test.mutate(&config)
			}
			err := config.ValidateRuntime()
			if test.want == "" {
				require.NoError(t, err)
				return
			}
			require.ErrorContains(t, err, test.want)
		})
	}
}
