package entity

import (
	"testing"
	"time"

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

func TestBlacklistEntry_IsExpired(t *testing.T) {
	tests := []struct {
		name     string
		entry    *BlacklistEntry
		expected bool
	}{
		{
			name: "expired entry",
			entry: &BlacklistEntry{
				JTI:       "test-jti",
				UID:       "test-uid",
				TokenID:   "test-token",
				ExpiresAt: time.Now().Add(-time.Hour).Unix(),
				CreatedAt: time.Now().Unix(),
			},
			expected: true,
		},
		{
			name: "not expired entry",
			entry: &BlacklistEntry{
				JTI:       "test-jti",
				UID:       "test-uid",
				TokenID:   "test-token",
				ExpiresAt: time.Now().Add(time.Hour).Unix(),
				CreatedAt: time.Now().Unix(),
			},
			expected: false,
		},
		{
			name: "exactly at expiry time",
			entry: &BlacklistEntry{
				JTI:       "test-jti",
				UID:       "test-uid",
				TokenID:   "test-token",
				ExpiresAt: time.Now().Unix(),
				CreatedAt: time.Now().Unix(),
			},
			expected: true, // Equal to current time should be considered expired
		},
	}

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

func TestBlacklistEntry_Validate(t *testing.T) {
	tests := []struct {
		name        string
		entry       *BlacklistEntry
		wantErr     bool
		expectedErr error
	}{
		{
			name: "valid entry",
			entry: &BlacklistEntry{
				JTI:       "test-jti",
				UID:       "test-uid",
				TokenID:   "test-token",
				Reason:    "user logout",
				ExpiresAt: time.Now().Add(time.Hour).Unix(),
				CreatedAt: time.Now().Unix(),
			},
			wantErr: false,
		},
		{
			name: "missing JTI",
			entry: &BlacklistEntry{
				JTI:       "",
				UID:       "test-uid",
				TokenID:   "test-token",
				ExpiresAt: time.Now().Add(time.Hour).Unix(),
				CreatedAt: time.Now().Unix(),
			},
			wantErr:     true,
			expectedErr: ErrInvalidJTI,
		},
		{
			name: "missing UID",
			entry: &BlacklistEntry{
				JTI:       "test-jti",
				UID:       "",
				TokenID:   "test-token",
				ExpiresAt: time.Now().Add(time.Hour).Unix(),
				CreatedAt: time.Now().Unix(),
			},
			wantErr:     true,
			expectedErr: ErrInvalidUID,
		},
		{
			name: "missing TokenID",
			entry: &BlacklistEntry{
				JTI:       "test-jti",
				UID:       "test-uid",
				TokenID:   "",
				ExpiresAt: time.Now().Add(time.Hour).Unix(),
				CreatedAt: time.Now().Unix(),
			},
			wantErr:     true,
			expectedErr: ErrInvalidTokenID,
		},
		{
			name: "all fields missing",
			entry: &BlacklistEntry{
				JTI:     "",
				UID:     "",
				TokenID: "",
			},
			wantErr:     true,
			expectedErr: ErrInvalidJTI, // First error encountered
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.entry.Validate()

			if tt.wantErr {
				assert.Error(t, err)
				if tt.expectedErr != nil {
					assert.Equal(t, tt.expectedErr, err)
				}
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestBlacklistEntry_CreatedAt(t *testing.T) {
	now := time.Now().Unix()
	entry := &BlacklistEntry{
		JTI:       "test-jti",
		UID:       "test-uid",
		TokenID:   "test-token",
		Reason:    "security",
		ExpiresAt: time.Now().Add(time.Hour).Unix(),
		CreatedAt: now,
	}

	assert.Equal(t, now, entry.CreatedAt)
}

func TestBlacklistEntry_Reason(t *testing.T) {
	tests := []struct {
		name   string
		reason string
	}{
		{
			name:   "user logout reason",
			reason: "user logout",
		},
		{
			name:   "security breach reason",
			reason: "security breach detected",
		},
		{
			name:   "password reset reason",
			reason: "password reset",
		},
		{
			name:   "empty reason",
			reason: "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			entry := &BlacklistEntry{
				JTI:       "test-jti",
				UID:       "test-uid",
				TokenID:   "test-token",
				Reason:    tt.reason,
				ExpiresAt: time.Now().Add(time.Hour).Unix(),
				CreatedAt: time.Now().Unix(),
			}

			assert.Equal(t, tt.reason, entry.Reason)
		})
	}
}
