package appconfig

import "testing"

func TestParseGiftComboConfigOverlaysDefaultsAndPreservesKillSwitch(t *testing.T) {
	config, err := ParseGiftComboConfig(`{"enabled":false,"rollout_basis_points":2500}`)
	if err != nil {
		t.Fatalf("ParseGiftComboConfig failed: %v", err)
	}
	if config.Enabled || config.RolloutBasisPoints != 2500 || config.APIVersion != 2 || config.WindowMS != 300 || config.MaxGiftCountPerBatch != 999 || config.MaxGiftUnitsPerBatch != 5_000 || config.MaxInFlight != 2 || config.RetryBaseDelayMS != 250 {
		t.Fatalf("partial remote config did not inherit safe defaults: %+v", config)
	}
}

func TestParseGiftComboConfigPromotesStoredV1MarkerWithoutDowngradingClient(t *testing.T) {
	config, err := ParseGiftComboConfig(`{"api_version":1,"enabled":false}`)
	if err != nil {
		t.Fatalf("legacy stored config must remain readable: %v", err)
	}
	if config.APIVersion != 2 || config.Enabled {
		t.Fatalf("stored V1 marker must become a V2 micro-batch kill switch: %+v", config)
	}
}

func TestDefaultGiftComboConfigRequiresExplicitRollout(t *testing.T) {
	config := DefaultGiftComboConfig()
	if config.RolloutBasisPoints != 0 {
		t.Fatalf("code deployment must not enable micro-batching rollout implicitly: %+v", config)
	}
}

func TestNormalizeGiftComboConfigRejectsUnboundedClientPolicy(t *testing.T) {
	tests := []GiftComboConfig{
		{APIVersion: 1, WindowMS: 300, MaxGiftCountPerBatch: 999, MaxGiftUnitsPerBatch: 5_000, MaxInFlight: 2, MaxPendingBatches: 20, RetryMaxAttempts: 5, RetryBaseDelayMS: 250, RolloutBasisPoints: 10_000},
		{APIVersion: 3, WindowMS: 300, MaxGiftCountPerBatch: 999, MaxGiftUnitsPerBatch: 5_000, MaxInFlight: 2, MaxPendingBatches: 20, RetryMaxAttempts: 5, RetryBaseDelayMS: 250, RolloutBasisPoints: 10_000},
		{APIVersion: 2, WindowMS: 99, MaxGiftCountPerBatch: 999, MaxGiftUnitsPerBatch: 5_000, MaxInFlight: 2, MaxPendingBatches: 20, RetryMaxAttempts: 5, RetryBaseDelayMS: 250, RolloutBasisPoints: 10_000},
		{APIVersion: 2, WindowMS: 300, MaxGiftCountPerBatch: 1_000, MaxGiftUnitsPerBatch: 5_000, MaxInFlight: 2, MaxPendingBatches: 20, RetryMaxAttempts: 5, RetryBaseDelayMS: 250, RolloutBasisPoints: 10_000},
		{APIVersion: 2, WindowMS: 300, MaxGiftCountPerBatch: 999, MaxGiftUnitsPerBatch: 5_001, MaxInFlight: 2, MaxPendingBatches: 20, RetryMaxAttempts: 5, RetryBaseDelayMS: 250, RolloutBasisPoints: 10_000},
		{APIVersion: 2, WindowMS: 300, MaxGiftCountPerBatch: 999, MaxGiftUnitsPerBatch: 5_000, MaxInFlight: 3, MaxPendingBatches: 20, RetryMaxAttempts: 5, RetryBaseDelayMS: 250, RolloutBasisPoints: 10_000},
		{APIVersion: 2, WindowMS: 300, MaxGiftCountPerBatch: 999, MaxGiftUnitsPerBatch: 5_000, MaxInFlight: 2, MaxPendingBatches: 0, RetryMaxAttempts: 5, RetryBaseDelayMS: 250, RolloutBasisPoints: 10_000},
		{APIVersion: 2, WindowMS: 300, MaxGiftCountPerBatch: 999, MaxGiftUnitsPerBatch: 5_000, MaxInFlight: 2, MaxPendingBatches: 1, RetryMaxAttempts: 5, RetryBaseDelayMS: 250, RolloutBasisPoints: 10_000},
		{APIVersion: 2, WindowMS: 300, MaxGiftCountPerBatch: 999, MaxGiftUnitsPerBatch: 5_000, MaxInFlight: 2, MaxPendingBatches: 20, RetryMaxAttempts: 5, RetryBaseDelayMS: 99, RolloutBasisPoints: 10_000},
	}
	for _, config := range tests {
		if _, err := NormalizeGiftComboConfig(config); err == nil {
			t.Fatalf("invalid policy was accepted: %+v", config)
		}
	}
}
