package token

import (
	"testing"

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

func TestGrantType_ToString(t *testing.T) {
	tests := []struct {
		name      string
		grantType GrantType
		expected  string
	}{
		{
			name:      "password credentials",
			grantType: PasswordCredentials,
			expected:  "password",
		},
		{
			name:      "client credentials",
			grantType: ClientCredentials,
			expected:  "client_credentials",
		},
		{
			name:      "refreshing",
			grantType: Refreshing,
			expected:  "refresh_token",
		},
		{
			name:      "custom grant type",
			grantType: GrantType("custom"),
			expected:  "custom",
		},
		{
			name:      "empty grant type",
			grantType: GrantType(""),
			expected:  "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.grantType.ToString()
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestGrantType_IsValid(t *testing.T) {
	tests := []struct {
		name      string
		grantType GrantType
		expected  bool
	}{
		{
			name:      "password credentials is valid",
			grantType: PasswordCredentials,
			expected:  true,
		},
		{
			name:      "client credentials is valid",
			grantType: ClientCredentials,
			expected:  true,
		},
		{
			name:      "refreshing is valid",
			grantType: Refreshing,
			expected:  true,
		},
		{
			name:      "invalid grant type",
			grantType: GrantType("invalid"),
			expected:  false,
		},
		{
			name:      "empty grant type",
			grantType: GrantType(""),
			expected:  false,
		},
		{
			name:      "authorization code (not implemented)",
			grantType: GrantType("authorization_code"),
			expected:  false,
		},
		{
			name:      "implicit (not implemented)",
			grantType: GrantType("implicit"),
			expected:  false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.grantType.IsValid()
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestGrantType_Constants(t *testing.T) {
	t.Run("verify constant values", func(t *testing.T) {
		assert.Equal(t, "password", PasswordCredentials.ToString())
		assert.Equal(t, "client_credentials", ClientCredentials.ToString())
		assert.Equal(t, "refresh_token", Refreshing.ToString())
	})

	t.Run("verify all constants are valid", func(t *testing.T) {
		assert.True(t, PasswordCredentials.IsValid())
		assert.True(t, ClientCredentials.IsValid())
		assert.True(t, Refreshing.IsValid())
	})
}

func TestGrantType_StringComparison(t *testing.T) {
	tests := []struct {
		name     string
		gt1      GrantType
		gt2      GrantType
		expected bool
	}{
		{
			name:     "same grant type",
			gt1:      PasswordCredentials,
			gt2:      PasswordCredentials,
			expected: true,
		},
		{
			name:     "different grant types",
			gt1:      PasswordCredentials,
			gt2:      ClientCredentials,
			expected: false,
		},
		{
			name:     "string comparison",
			gt1:      GrantType("password"),
			gt2:      PasswordCredentials,
			expected: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.gt1 == tt.gt2
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestGrantType_CaseSensitive(t *testing.T) {
	t.Run("case sensitive comparison", func(t *testing.T) {
		gt1 := GrantType("password")
		gt2 := GrantType("PASSWORD")

		assert.NotEqual(t, gt1, gt2)
		assert.True(t, gt1.IsValid())
		assert.False(t, gt2.IsValid())
	})
}
