package prototool

import (
	"strconv"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/testing/matcher"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/pkg/agentcfg"
	"google.golang.org/protobuf/encoding/protojson"
	"sigs.k8s.io/yaml"
)

func TestEmptyConfig(t *testing.T) {
	t.Run("comments", func(t *testing.T) {
		data := []byte(`
#observability:
#  logging:
#    level: info
`)
		assertEmpty(t, data)
	})
	t.Run("empty", func(t *testing.T) {
		data := []byte("")
		assertEmpty(t, data)
	})
	t.Run("newline", func(t *testing.T) {
		data := []byte("\n")
		assertEmpty(t, data)
	})
	t.Run("missing", func(t *testing.T) {
		var data []byte
		assertEmpty(t, data)
	})
}

func assertEmpty(t *testing.T, data []byte) {
	config := &agentcfg.ConfigurationFile{}
	err := ParseYAMLToProto(data, config)
	require.NoError(t, err)
	matcher.AssertProtoEqual(t, config, &agentcfg.ConfigurationFile{})
}

func TestYAMLToConfigurationAndBack(t *testing.T) {
	testCases := []struct {
		given, expected string
	}{
		{
			given: `{}
`, // empty config
			expected: `{}
`,
		},
		{
			given: `observability: {}
`,
			expected: `observability: {}
`,
		},
		{
			given: `observability:
  logging: {}
`,
			expected: `observability:
  logging: {}
`, // empty slice is omitted
		},
		{
			given: `ci_access: {}
`, // the simplest agent config
			expected: `ci_access: {}
`,
		},
		{
			given: `ci_access:
  groups:
  - access_as:
      ci_job: {}
    id: mygroup
  projects:
  - access_as:
      ci_job: {}
    id: my/proj
`, // this is a simple agent config
			expected: `ci_access:
  groups:
  - access_as:
      ci_job: {}
    id: mygroup
  projects:
  - access_as:
      ci_job: {}
    id: my/proj
`,
		},
		{
			given: `ci_access:
  groups:
  - access_as:
      ci_job: {}
    annotations:
      key1: value1
      key2: value2
    id: mygroup
  projects:
  - access_as:
      ci_job: {}
    annotations:
      key1: value1
      key2: value2
    id: my/proj
`, // agent config with the 'annotations' field
			expected: `ci_access:
  groups:
  - access_as:
      ci_job: {}
    annotations:
      key1: value1
      key2: value2
    id: mygroup
  projects:
  - access_as:
      ci_job: {}
    annotations:
      key1: value1
      key2: value2
    id: my/proj
`,
		},
		{
			expected: `ci_access:
  groups:
  - access_as:
      ci_job: {}
    annotations: {}
    id: mygroup
  projects:
  - access_as:
      ci_job: {}
    annotations: {}
    id: my/proj
`, // agent config with an empty 'annotations' field
			given: `ci_access:
  groups:
  - access_as:
      ci_job: {}
    annotations: {}
    id: mygroup
  projects:
  - access_as:
      ci_job: {}
    annotations: {}
    id: my/proj
`,
		},
	}

	for i, tc := range testCases {
		t.Run(strconv.Itoa(i), func(t *testing.T) {
			config := &agentcfg.ConfigurationFile{}
			err := ParseYAMLToProto([]byte(tc.given), config)
			require.NoError(t, err)
			configJSON, err := protojson.Marshal(config)
			require.NoError(t, err)
			configYAML, err := yaml.JSONToYAML(configJSON)
			require.NoError(t, err)
			diff := cmp.Diff(tc.expected, string(configYAML))
			assert.Empty(t, diff)
		})
	}
}
