package featureflag

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/testing/matcher"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/testing/mock_otel"
	otelmetric "go.opentelemetry.io/otel/metric"
	"go.uber.org/mock/gomock"
)

func TestFeatureFlag_NewFeatureFlag(t *testing.T) {
	// WHEN
	ff := NewFeatureFlag("valid_name", false)

	// THEN
	assert.NotNil(t, ff)
}

func TestFeatureFlag_NewFeatureFlag_InvalidName(t *testing.T) {
	// THEN
	assert.PanicsWithError(t, "invalid feature flag name \"invalid-name\", check the featureflag package for guidance on the feature flag names", func() {
		// WHEN
		NewFeatureFlag("invalid-name", false)
	})
}

func TestSet_IsEnabled(t *testing.T) {
	// GIVEN
	tests := []struct {
		name                string
		setFactory          func(counter otelmetric.Int64Counter) Set
		ff                  *FeatureFlag
		expectedIsEnabled   bool
		expectedFromDefault bool
	}{
		{
			name:                "empty set, feature flag missing returns default",
			setFactory:          func(counter otelmetric.Int64Counter) Set { return NewSet(nil, counter) },
			ff:                  NewFeatureFlag("dummy", true),
			expectedIsEnabled:   true,
			expectedFromDefault: true,
		},
		{
			name: "feature flag missing returns default",
			setFactory: func(counter otelmetric.Int64Counter) Set {
				return NewSet(map[string]bool{
					"another": false,
				}, counter)
			},
			ff:                  NewFeatureFlag("dummy", true),
			expectedIsEnabled:   true,
			expectedFromDefault: true,
		},
		{
			name: "feature flag enabled",
			setFactory: func(counter otelmetric.Int64Counter) Set {
				return NewSet(map[string]bool{
					"dummy": true,
				}, counter)
			},
			ff:                  NewFeatureFlag("dummy", false),
			expectedIsEnabled:   true,
			expectedFromDefault: false,
		},
		{
			name: "feature flag disabled",
			setFactory: func(counter otelmetric.Int64Counter) Set {
				return NewSet(map[string]bool{
					"dummy": false,
				}, counter)
			},
			ff:                  NewFeatureFlag("dummy", true),
			expectedIsEnabled:   false,
			expectedFromDefault: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctrl := gomock.NewController(t)
			counter := mock_otel.NewMockInt64Counter(ctrl)

			expectedAttrs := map[string]any{
				"name":    tt.ff.Name,
				"enabled": tt.expectedIsEnabled,
			}
			if tt.expectedFromDefault {
				expectedAttrs["from_default"] = true
			}
			counter.EXPECT().Add(gomock.Any(), int64(1), matcher.MatchOtelAttributes(expectedAttrs)).Times(2)

			// WHEN
			set := tt.setFactory(counter)
			actualIsEnabled := set.IsEnabled(tt.ff)
			actualIsDisabled := set.IsDisabled(tt.ff)

			// THEN
			assert.Equal(t, tt.expectedIsEnabled, actualIsEnabled)
			assert.Equal(t, actualIsEnabled, !actualIsDisabled)
		})
	}
}
