package rpc

import (
	"testing"

	"buf.build/go/protovalidate"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/testing/testhelpers"
	"google.golang.org/genproto/googleapis/rpc/status"
)

func TestValidation_Valid(t *testing.T) {
	bin := make([]byte, 256)
	for i := range 256 {
		bin[i] = byte(i)
	}
	var vals []byte
	for i := byte(0x20); i <= 0x7E; i++ {
		vals = append(vals, i)
	}
	tests := []testhelpers.ValidTestcase{
		{
			Name: "minimal",
			Valid: &Error{
				Status: &status.Status{},
			},
		},
		{
			Name: "binary value",
			Valid: &MetadataKV{
				Key: []byte("key-bin"),
				Value: &MetadataValues{
					Value: [][]byte{
						bin,
					},
				},
			},
		},
		{
			Name: "empty value",
			Valid: &MetadataKV{
				Key: []byte("key"),
				Value: &MetadataValues{
					Value: [][]byte{
						{},
					},
				},
			},
		},
		{
			Name: "MetadataKV key chars",
			Valid: &MetadataKV{
				Key: []byte("abcdefghijklmnopqrstuvwxyz0123456789._-"),
				Value: &MetadataValues{
					Value: [][]byte{
						{},
					},
				},
			},
		},
		{
			Name: "MetadataKV value chars",
			Valid: &MetadataKV{
				Key: []byte("key"),
				Value: &MetadataValues{
					Value: [][]byte{
						vals,
					},
				},
			},
		},
	}
	testhelpers.AssertValid(t, tests)
}

func TestValidation_Invalid(t *testing.T) {
	tests := []testhelpers.InvalidTestcase{
		{
			ErrString: "validation error:\n - status: value is required [required]",
			Invalid:   &Error{},
		},
		{
			ErrString: "validation error:\n - value: value must contain at least 1 item(s) [repeated.min_items]",
			Invalid:   &MetadataValues{},
		},
	}
	addCase := func(b byte) {
		tests = append(tests, testhelpers.InvalidTestcase{
			ErrString: "validation error:\n - value[0]: value must match regex pattern `^[^\\x00-\\x08\\x0A-\\x1F\\x7F]*$` [bytes.pattern]",
			Invalid: &MetadataKV{
				Key: []byte("key"),
				Value: &MetadataValues{
					Value: [][]byte{
						{b},
					},
				},
			},
		})
	}
	for i := range 0x20 {
		addCase(byte(i))
	}
	for i := 0x7F; i <= 0xFF; i++ {
		addCase(byte(i))
	}

	// TODO: use this helper when we get stable error messages - https://github.com/bufbuild/protovalidate/issues/268.
	//testhelpers.AssertInvalid(t, tests)

	v, err := protovalidate.New()
	require.NoError(t, err)

	for _, tc := range tests {
		t.Run(tc.ErrString, func(t *testing.T) {
			err := v.Validate(tc.Invalid)
			assert.Error(t, err)
		})
	}
}
