package model

import (
	"strings"
	"testing"

	"github.com/stretchr/testify/require"
)

func TestExtensionCapabilityConfigStrictDecode(t *testing.T) {
	t.Parallel()

	config, err := DecodeExtensionCapabilityConfig([]byte(`{
		"extensions": [{
			"domain": "github",
			"version": 1,
			"definitionDigest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
			"defaultName": "github",
			"defaultEnabled": true
		}]
	}`))
	require.NoError(t, err)
	require.Equal(t, ExtensionCapabilityConfig{
		Extensions: []ExtensionCapabilityEntry{{
			Domain:           "github",
			Version:          1,
			DefinitionDigest: "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
			DefaultName:      "github",
			DefaultEnabled:   true,
		}},
	}, config)

	encoded, err := EncodeExtensionCapabilityConfig(config)
	require.NoError(t, err)
	require.JSONEq(t, `{
		"extensions": [{
			"domain": "github",
			"version": 1,
			"definitionDigest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
			"defaultName": "github",
			"defaultEnabled": true
		}]
	}`, string(encoded))

	for name, payload := range map[string]string{
		"unknown top level field": `{"extensions":[],"extra":true}`,
		"unknown entry field":     `{"extensions":[{"domain":"github","version":1,"definitionDigest":"sha256:` + strings.Repeat("a", 64) + `","defaultName":"github","defaultEnabled":true,"extra":true}]}`,
		"missing extensions":      `{}`,
		"missing default enabled": `{"extensions":[{"domain":"github","version":1,"definitionDigest":"sha256:` + strings.Repeat("a", 64) + `","defaultName":"github"}]}`,
		"trailing document":       `{"extensions":[]} {}`,
	} {
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			_, err := DecodeExtensionCapabilityConfig([]byte(payload))
			require.Error(t, err)
		})
	}
}

func TestExtensionCapabilityConfigRejectsDuplicateDomain(t *testing.T) {
	t.Parallel()

	digest := "sha256:" + strings.Repeat("a", 64)
	_, err := DecodeExtensionCapabilityConfig([]byte(`{
		"extensions": [
			{"domain":"github","version":1,"definitionDigest":"` + digest + `","defaultName":"github","defaultEnabled":true},
			{"domain":"github","version":2,"definitionDigest":"` + digest + `","defaultName":"github-v2","defaultEnabled":false}
		]
	}`))
	require.ErrorContains(t, err, "duplicate")
}

func TestExtensionCapabilityConfigRejectsInvalidDefaultNames(t *testing.T) {
	t.Parallel()

	for _, defaultName := range []string{"", "GitHub", "github_watch", "-github", "github-", "github--watch", " github"} {
		t.Run(defaultName, func(t *testing.T) {
			t.Parallel()
			config := validExtensionCapabilityConfig()
			config.Extensions[0].DefaultName = defaultName
			require.Error(t, ValidateExtensionCapabilityConfig(config))
		})
	}
}

func TestExtensionCapabilityConfigRejectsNonPositiveVersions(t *testing.T) {
	t.Parallel()

	for _, version := range []int{-1, 0} {
		config := validExtensionCapabilityConfig()
		config.Extensions[0].Version = version
		require.Error(t, ValidateExtensionCapabilityConfig(config))
	}
}

func TestExtensionCapabilityConfigRejectsInvalidDefinitionDigests(t *testing.T) {
	t.Parallel()

	for _, digest := range []string{
		"",
		"sha256:deadbeef",
		"sha256:" + strings.Repeat("A", 64),
		"sha512:" + strings.Repeat("a", 64),
		"sha256:" + strings.Repeat("a", 65),
	} {
		t.Run(digest, func(t *testing.T) {
			t.Parallel()
			config := validExtensionCapabilityConfig()
			config.Extensions[0].DefinitionDigest = digest
			require.Error(t, ValidateExtensionCapabilityConfig(config))
		})
	}
}

func validExtensionCapabilityConfig() ExtensionCapabilityConfig {
	return ExtensionCapabilityConfig{
		Extensions: []ExtensionCapabilityEntry{{
			Domain:           "github",
			Version:          1,
			DefinitionDigest: "sha256:" + strings.Repeat("a", 64),
			DefaultName:      "github",
			DefaultEnabled:   true,
		}},
	}
}
