package usecase

import (
	"testing"

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

func TestTokenClaims_SetAndGetID(t *testing.T) {
	tests := []struct {
		name string
		id   string
	}{
		{
			name: "normal ID",
			id:   "token123",
		},
		{
			name: "UUID ID",
			id:   "550e8400-e29b-41d4-a716-446655440000",
		},
		{
			name: "empty ID",
			id:   "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tc := make(TokenClaims)
			tc.SetID(tt.id)

			result := tc.ID()
			assert.Equal(t, tt.id, result)
		})
	}
}

func TestTokenClaims_SetAndGetRole(t *testing.T) {
	tests := []struct {
		name string
		role string
	}{
		{
			name: "admin role",
			role: "admin",
		},
		{
			name: "user role",
			role: "user",
		},
		{
			name: "guest role",
			role: "guest",
		},
		{
			name: "empty role",
			role: "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tc := make(TokenClaims)
			tc.SetRole(tt.role)

			result := tc.Role()
			assert.Equal(t, tt.role, result)
		})
	}
}

func TestTokenClaims_SetAndGetDeviceID(t *testing.T) {
	tests := []struct {
		name     string
		deviceID string
	}{
		{
			name:     "normal device ID",
			deviceID: "device123",
		},
		{
			name:     "UUID device ID",
			deviceID: "550e8400-e29b-41d4-a716-446655440000",
		},
		{
			name:     "empty device ID",
			deviceID: "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tc := make(TokenClaims)
			tc.SetDeviceID(tt.deviceID)

			result := tc.DeviceID()
			assert.Equal(t, tt.deviceID, result)
		})
	}
}

func TestTokenClaims_SetAndGetScope(t *testing.T) {
	tests := []struct {
		name  string
		scope string
	}{
		{
			name:  "read write scope",
			scope: "read write",
		},
		{
			name:  "read only scope",
			scope: "read",
		},
		{
			name:  "admin scope",
			scope: "admin",
		},
		{
			name:  "empty scope",
			scope: "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tc := make(TokenClaims)
			tc.SetScope(tt.scope)

			// Note: there's no GetScope method, so we just verify it's set
			assert.Equal(t, tt.scope, tc["scope"])
		})
	}
}

func TestTokenClaims_SetAndGetAccount(t *testing.T) {
	tests := []struct {
		name    string
		account string
	}{
		{
			name:    "email account",
			account: "user@example.com",
		},
		{
			name:    "username account",
			account: "john_doe",
		},
		{
			name:    "phone account",
			account: "+1234567890",
		},
		{
			name:    "empty account",
			account: "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tc := make(TokenClaims)
			tc.SetLoginID(tt.account)

			// 使用 LoginID() 方法獲取
			assert.Equal(t, tt.account, tc.LoginID())
			// 也驗證直接訪問 login_id 欄位
			assert.Equal(t, tt.account, tc["login_id"])
		})
	}
}

func TestTokenClaims_SetAndGetUID(t *testing.T) {
	tests := []struct {
		name string
		uid  string
	}{
		{
			name: "normal UID",
			uid:  "user123",
		},
		{
			name: "UUID UID",
			uid:  "550e8400-e29b-41d4-a716-446655440000",
		},
		{
			name: "empty UID",
			uid:  "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tc := make(TokenClaims)
			tc["uid"] = tt.uid

			result := tc.UID()
			assert.Equal(t, tt.uid, result)
		})
	}
}

func TestTokenClaims_GetNonExistentField(t *testing.T) {
	tc := make(TokenClaims)

	t.Run("get non-existent ID", func(t *testing.T) {
		result := tc.ID()
		assert.Empty(t, result)
	})

	t.Run("get non-existent Role", func(t *testing.T) {
		result := tc.Role()
		assert.Empty(t, result)
	})

	t.Run("get non-existent DeviceID", func(t *testing.T) {
		result := tc.DeviceID()
		assert.Empty(t, result)
	})

	t.Run("get non-existent UID", func(t *testing.T) {
		result := tc.UID()
		assert.Empty(t, result)
	})
}

func TestTokenClaims_MultipleFields(t *testing.T) {
	tc := make(TokenClaims)

	tc.SetID("token123")
	tc.SetRole("admin")
	tc.SetDeviceID("device456")
	tc.SetScope("read write")
	tc.SetLoginID("user@example.com")
	tc["uid"] = "user789"

	t.Run("verify all fields", func(t *testing.T) {
		assert.Equal(t, "token123", tc.ID())
		assert.Equal(t, "admin", tc.Role())
		assert.Equal(t, "device456", tc.DeviceID())
		assert.Equal(t, "read write", tc["scope"])
		assert.Equal(t, "user@example.com", tc.LoginID())
		assert.Equal(t, "user@example.com", tc["login_id"])
		assert.Equal(t, "user789", tc.UID())
	})
}

func TestTokenClaims_Overwrite(t *testing.T) {
	tc := make(TokenClaims)

	t.Run("overwrite ID", func(t *testing.T) {
		tc.SetID("token123")
		assert.Equal(t, "token123", tc.ID())

		tc.SetID("token456")
		assert.Equal(t, "token456", tc.ID())
	})

	t.Run("overwrite Role", func(t *testing.T) {
		tc.SetRole("user")
		assert.Equal(t, "user", tc.Role())

		tc.SetRole("admin")
		assert.Equal(t, "admin", tc.Role())
	})
}

func TestTokenClaims_MapBehavior(t *testing.T) {
	tc := make(TokenClaims)

	t.Run("can set custom fields", func(t *testing.T) {
		tc["custom_field"] = "custom_value"
		assert.Equal(t, "custom_value", tc["custom_field"])
	})

	t.Run("can iterate over fields", func(t *testing.T) {
		tc2 := make(TokenClaims)
		tc2.SetID("token123")
		tc2.SetRole("admin")
		tc2["uid"] = "user123"

		count := 0
		for range tc2 {
			count++
		}
		assert.Equal(t, 3, count)
	})

	t.Run("can check field existence", func(t *testing.T) {
		tc.SetID("token123")

		_, exists := tc["id"]
		assert.True(t, exists)

		_, exists = tc["non_existent"]
		assert.False(t, exists)
	})

	t.Run("can delete fields", func(t *testing.T) {
		tc.SetRole("admin")
		assert.Equal(t, "admin", tc.Role())

		delete(tc, "role")
		assert.Empty(t, tc.Role())
	})
}

func TestTokenClaims_EmptyMap(t *testing.T) {
	tc := make(TokenClaims)

	assert.Empty(t, tc.ID())
	assert.Empty(t, tc.Role())
	assert.Empty(t, tc.DeviceID())
	assert.Empty(t, tc.UID())
	assert.Equal(t, 0, len(tc))
}

func TestTokenClaims_NilMap(t *testing.T) {
	var tc TokenClaims

	t.Run("get from nil map", func(t *testing.T) {
		assert.Empty(t, tc.ID())
		assert.Empty(t, tc.Role())
		assert.Empty(t, tc.DeviceID())
		assert.Empty(t, tc.UID())
	})
}
