package test

import (
	"context"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/zap"

	"github.com/kms/api-key-service/internal/auth"
	"github.com/kms/api-key-service/internal/domain"
	"github.com/kms/api-key-service/internal/services"
)



func TestAuthenticationService_ValidateJWTToken(t *testing.T) {
	config := NewMockConfig()
	logger := zap.NewNop()
	authService := services.NewAuthenticationService(config, logger)

	userToken := &domain.UserToken{
		AppID:       "test-app",
		UserID:      "test-user",
		Permissions: []string{"read", "write"},
		IssuedAt:    time.Now(),
		ExpiresAt:   time.Now().Add(time.Hour),
		MaxValidAt:  time.Now().Add(24 * time.Hour),
		TokenType:   domain.TokenTypeUser,
		Claims: map[string]string{
			"email": "test@example.com",
		},
	}

	// Generate token
	tokenString, err := authService.GenerateJWTToken(context.Background(), userToken)
	require.NoError(t, err)

	// Validate token
	authContext, err := authService.ValidateJWTToken(context.Background(), tokenString)
	require.NoError(t, err)
	assert.Equal(t, userToken.UserID, authContext.UserID)
	assert.Equal(t, userToken.AppID, authContext.AppID)
	assert.Equal(t, userToken.Permissions, authContext.Permissions)
	assert.Equal(t, userToken.TokenType, authContext.TokenType)
	assert.Equal(t, userToken.Claims, authContext.Claims)
}

func TestAuthenticationService_GenerateJWTToken(t *testing.T) {
	config := NewMockConfig()
	logger := zap.NewNop()
	authService := services.NewAuthenticationService(config, logger)

	userToken := &domain.UserToken{
		AppID:       "test-app",
		UserID:      "test-user",
		Permissions: []string{"read"},
		IssuedAt:    time.Now(),
		ExpiresAt:   time.Now().Add(time.Hour),
		MaxValidAt:  time.Now().Add(24 * time.Hour),
		TokenType:   domain.TokenTypeUser,
	}

	tokenString, err := authService.GenerateJWTToken(context.Background(), userToken)
	require.NoError(t, err)
	assert.NotEmpty(t, tokenString)

	// Verify token can be validated
	authContext, err := authService.ValidateJWTToken(context.Background(), tokenString)
	require.NoError(t, err)
	assert.Equal(t, userToken.UserID, authContext.UserID)
}

func TestAuthenticationService_RefreshJWTToken(t *testing.T) {
	config := NewMockConfig()
	logger := zap.NewNop()
	authService := services.NewAuthenticationService(config, logger)

	userToken := &domain.UserToken{
		AppID:       "test-app",
		UserID:      "test-user",
		Permissions: []string{"read"},
		IssuedAt:    time.Now(),
		ExpiresAt:   time.Now().Add(time.Hour),
		MaxValidAt:  time.Now().Add(24 * time.Hour),
		TokenType:   domain.TokenTypeUser,
	}

	originalToken, err := authService.GenerateJWTToken(context.Background(), userToken)
	require.NoError(t, err)

	// Refresh token
	newExpiration := time.Now().Add(2 * time.Hour)
	refreshedToken, err := authService.RefreshJWTToken(context.Background(), originalToken, newExpiration)
	require.NoError(t, err)
	assert.NotEmpty(t, refreshedToken)
	assert.NotEqual(t, originalToken, refreshedToken)

	// Validate refreshed token
	authContext, err := authService.ValidateJWTToken(context.Background(), refreshedToken)
	require.NoError(t, err)
	assert.Equal(t, userToken.UserID, authContext.UserID)
}

func TestJWTManager_InvalidSecret(t *testing.T) {
	// Test with empty JWT secret
	config := NewTestConfig()
	config.values["JWT_SECRET"] = ""
	logger := zap.NewNop()
	jwtManager := auth.NewJWTManager(config, logger)

	userToken := &domain.UserToken{
		AppID:       "test-app",
		UserID:      "test-user",
		Permissions: []string{"read"},
		IssuedAt:    time.Now(),
		ExpiresAt:   time.Now().Add(time.Hour),
		MaxValidAt:  time.Now().Add(24 * time.Hour),
		TokenType:   domain.TokenTypeUser,
	}

	_, err := jwtManager.GenerateToken(userToken)
	assert.Error(t, err)
}

func TestJWTManager_TokenRevocation(t *testing.T) {
	config := NewMockConfig()
	logger := zap.NewNop()
	jwtManager := auth.NewJWTManager(config, logger)

	userToken := &domain.UserToken{
		AppID:       "test-app",
		UserID:      "test-user",
		Permissions: []string{"read"},
		IssuedAt:    time.Now(),
		ExpiresAt:   time.Now().Add(time.Hour),
		MaxValidAt:  time.Now().Add(24 * time.Hour),
		TokenType:   domain.TokenTypeUser,
	}

	tokenString, err := jwtManager.GenerateToken(userToken)
	require.NoError(t, err)

	// Check revocation status (should be false initially)
	revoked, err := jwtManager.IsTokenRevoked(tokenString)
	require.NoError(t, err)
	assert.False(t, revoked)

	// Revoke token (currently just logs, doesn't actually revoke)
	err = jwtManager.RevokeToken(tokenString)
	require.NoError(t, err)

	// Note: Current implementation doesn't actually implement blacklisting,
	// so this test just verifies the methods don't error
}
