package agentcfg

import (
	"testing"

	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/testing/testhelpers"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/testing/testproto"
	"google.golang.org/protobuf/types/known/structpb"
)

func TestValidation_Valid(t *testing.T) {
	tests := []testhelpers.ValidTestcase{
		{
			Name:  "empty",
			Valid: &AgentConfiguration{},
		},
		{
			Name: "empty CiAccessGroupCF.DefaultNamespace",
			Valid: &CiAccessGroupCF{
				Id:               "abc",
				DefaultNamespace: "", // empty is ok
			},
		},
		{
			Name: "empty environments CiAccessGroupCF.Environments",
			Valid: &CiAccessGroupCF{
				Id:           "abc",
				Environments: []string{},
			},
		},
		{
			Name: "multiple environments CiAccessGroupCF.Environments",
			Valid: &CiAccessGroupCF{
				Id:           "abc",
				Environments: []string{"a", "b"},
			},
		},
		{
			Name: "empty CiAccessGroupCF.Annotations",
			Valid: &CiAccessGroupCF{
				Id:          "abc",
				Annotations: &structpb.Struct{},
			},
		},
		{
			Name: "CiAccessGroupCF.Annotations exists",
			Valid: &CiAccessGroupCF{
				Id: "abc",
				Annotations: &structpb.Struct{
					Fields: map[string]*structpb.Value{
						"key1": {
							Kind: &structpb.Value_StringValue{
								StringValue: "value1",
							},
						},
						"key2": {
							Kind: &structpb.Value_StringValue{
								StringValue: "value2",
							},
						},
					},
				},
			},
		},
		{
			Name: "empty environments CiAccessProjectCF.Environments",
			Valid: &CiAccessProjectCF{
				Id:           "abc",
				Environments: []string{},
			},
		},
		{
			Name: "multiple environments CiAccessProjectCF.Environments",
			Valid: &CiAccessProjectCF{
				Id:           "abc",
				Environments: []string{"a", "b"},
			},
		},
		{
			Name: "empty CiAccessProjectCF.Annotations",
			Valid: &CiAccessProjectCF{
				Id:          "abc",
				Annotations: &structpb.Struct{},
			},
		},
		{
			Name: "CiAccessProjectCF.Annotations exists",
			Valid: &CiAccessProjectCF{
				Id: "abc",
				Annotations: &structpb.Struct{
					Fields: map[string]*structpb.Value{
						"key1": {
							Kind: &structpb.Value_StringValue{
								StringValue: "value1",
							},
						},
						"key2": {
							Kind: &structpb.Value_StringValue{
								StringValue: "value2",
							},
						},
					},
				},
			},
		},
		{
			Name:  "empty CiAccessAsAgentCF",
			Valid: &CiAccessAsAgentCF{},
		},
		{
			Name:  "empty CiAccessAsCiJobCF",
			Valid: &CiAccessAsCiJobCF{},
		},
		{
			Name:  "empty CiAccessAsCiJobCF",
			Valid: &CiAccessAsCiJobCF{},
		},
		{
			Name:  "empty CiAccessAsAgentCF",
			Valid: &CiAccessAsAgentCF{},
		},
		{
			Name: "minimal CiAccessAsImpersonateCF",
			Valid: &CiAccessAsImpersonateCF{
				Username: "abc",
			},
		},
		{
			Name: "one group CiAccessAsImpersonateCF",
			Valid: &CiAccessAsImpersonateCF{
				Username: "abc",
				Groups:   []string{"g"},
			},
		},
		{
			Name:  "minimal RemoteDevelopmentCF",
			Valid: &RemoteDevelopmentCF{},
		},
	}
	testhelpers.AssertValid(t, tests)
}

func TestValidation_Invalid(t *testing.T) {
	emptyID := ""
	tests := []testhelpers.InvalidTestcase{
		{
			ErrString: "validation error:\n - id: value length must be at least 1 bytes [string.min_bytes]",
			Invalid: &CiAccessGroupCF{
				Id: emptyID, // empty id is not ok
			},
		},
		{
			ErrString: "validation error:\n - environments[0]: value length must be at least 1 bytes [string.min_bytes]",
			Invalid: &CiAccessGroupCF{
				Id:           "abc",
				Environments: []string{""},
			},
		},
		{
			ErrString: "validation error:\n - environments[0]: value length must be at least 1 bytes [string.min_bytes]",
			Invalid: &CiAccessProjectCF{
				Id:           "abc",
				Environments: []string{""},
			},
		},
		{
			ErrString: "validation error:\n - as: exactly one field is required in oneof [required]",
			Invalid:   &CiAccessAsCF{},
		},
		{
			ErrString: "validation error:\n - impersonate.username: value length must be at least 1 bytes [string.min_bytes]",
			Invalid: &CiAccessAsCF{
				As: &CiAccessAsCF_Impersonate{},
			},
		},
		{
			ErrString: "validation error:\n - username: value length must be at least 1 bytes [string.min_bytes]",
			Invalid:   &CiAccessAsImpersonateCF{},
		},
		{
			ErrString: "validation error:\n - groups[0]: value length must be at least 1 bytes [string.min_bytes]",
			Invalid: &CiAccessAsImpersonateCF{
				Username: "a",
				Groups:   []string{""},
			},
		},
		{
			ErrString: "validation error:\n - key: value length must be at least 1 bytes [string.min_bytes]\n - val: value must contain at least 1 item(s) [repeated.min_items]",
			Invalid:   &ExtraKeyValCF{},
		},
	}
	testhelpers.AssertInvalid(t, tests)
}

func TestJSONNameSet(t *testing.T) {
	cfg := ConfigurationFile{}
	testproto.AssertHasJSONNameSetRecursive(t, cfg.ProtoReflect().Descriptor())
}
