package examples

import (
	"testing"
	"time"

	"github.com/golang-jwt/jwt/v5"
	"github.com/google/uuid"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"erp-mvp/core-service/internal/auth"
)

// TestJWTService_GenerateToken тестирует генерацию JWT токенов
func TestJWTService_GenerateToken(t *testing.T) {
	// Arrange
	secret := "test_secret_key"
	ttl := 24 * time.Hour
	jwtService := auth.NewJWTService(secret, ttl)
	userID := uuid.New()
	orgID := uuid.New()
	email := "test@example.com"
	role := "admin"

	// Act
	token, err := jwtService.GenerateToken(userID, orgID, email, role)

	// Assert
	require.NoError(t, err)
	assert.NotEmpty(t, token)

	// Проверяем, что токен можно декодировать
	parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
		return []byte(secret), nil
	})
	require.NoError(t, err)
	assert.True(t, parsedToken.Valid)

	// Проверяем claims
	claims, ok := parsedToken.Claims.(jwt.MapClaims)
	require.True(t, ok)
	assert.Equal(t, userID.String(), claims["user_id"])
	assert.Equal(t, orgID.String(), claims["organization_id"])
	assert.Equal(t, email, claims["email"])
	assert.Equal(t, role, claims["role"])
}

// TestJWTService_ValidateToken тестирует валидацию JWT токенов
func TestJWTService_ValidateToken(t *testing.T) {
	// Arrange
	secret := "test_secret_key"
	ttl := 24 * time.Hour
	jwtService := auth.NewJWTService(secret, ttl)

	// Создаем валидный токен для тестирования
	userID := uuid.New()
	orgID := uuid.New()
	validToken, err := jwtService.GenerateToken(userID, orgID, "test@example.com", "admin")
	require.NoError(t, err)

	tests := []struct {
		name    string
		secret  string
		token   string
		wantErr bool
	}{
		{
			name:    "valid token",
			secret:  secret,
			token:   validToken,
			wantErr: false,
		},
		{
			name:    "invalid signature",
			secret:  "wrong_secret",
			token:   validToken,
			wantErr: true,
		},
		{
			name:    "invalid token format",
			secret:  secret,
			token:   "invalid_token_format",
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Arrange
			testJWTService := auth.NewJWTService(tt.secret, ttl)

			// Act
			claims, err := testJWTService.ValidateToken(tt.token)

			// Assert
			if tt.wantErr {
				assert.Error(t, err)
				assert.Nil(t, claims)
			} else {
				assert.NoError(t, err)
				assert.NotNil(t, claims)
				assert.Equal(t, userID, claims.UserID)
				assert.Equal(t, orgID, claims.OrganizationID)
			}
		})
	}
}

// TestPasswordHashing тестирует хеширование и проверку паролей
func TestPasswordHashing(t *testing.T) {
	// Arrange
	password := "mySecurePassword123"

	// Act - хешируем пароль
	hashedPassword, err := auth.HashPassword(password)

	// Assert
	require.NoError(t, err)
	assert.NotEmpty(t, hashedPassword)
	assert.NotEqual(t, password, hashedPassword)

	// Act - проверяем правильный пароль
	isValid := auth.CheckPassword(password, hashedPassword)

	// Assert
	assert.True(t, isValid)

	// Act - проверяем неправильный пароль
	isValid = auth.CheckPassword("wrongPassword", hashedPassword)

	// Assert
	assert.False(t, isValid)
}

// TestPasswordHashing_EmptyPassword тестирует обработку пустого пароля
func TestPasswordHashing_EmptyPassword(t *testing.T) {
	// Arrange
	password := ""

	// Act
	hashedPassword, err := auth.HashPassword(password)

	// Assert
	assert.NoError(t, err)
	assert.NotEmpty(t, hashedPassword)

	// Проверяем, что пустой пароль работает
	isValid := auth.CheckPassword(password, hashedPassword)
	assert.True(t, isValid)
}

// BenchmarkPasswordHashing тестирует производительность хеширования
func BenchmarkPasswordHashing(b *testing.B) {
	password := "benchmarkPassword123"

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := auth.HashPassword(password)
		if err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkJWTGeneration тестирует производительность генерации JWT
func BenchmarkJWTGeneration(b *testing.B) {
	secret := "benchmark_secret_key"
	ttl := 24 * time.Hour
	jwtService := auth.NewJWTService(secret, ttl)
	userID := uuid.New()
	orgID := uuid.New()
	email := "benchmark@example.com"
	role := "admin"

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := jwtService.GenerateToken(userID, orgID, email, role)
		if err != nil {
			b.Fatal(err)
		}
	}
}
