#!/bin/bash

# Test script for configuration encryption system
# This script tests the encryption/decryption functionality

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Test configuration
TEST_DIR="$(mktemp -d)"
TEST_VALUES=(
    "simple_password123"
    "complex_password_with_special_chars!@#$%^&*()"
    "database_url_postgresql://user:pass@localhost:5432/db"
    "sendgrid_api_key_SG.1234567890abcdef"
    "session_secret_very_long_random_string_for_sessions"
    "oauth_client_secret_github_oauth_app_secret"
    "redis_url_redis://user:pass@redis.example.com:6379/0"
    "jwt_secret_super_secret_jwt_signing_key"
    "smtp_password_app_specific_password_for_gmail"
    "encryption_test_value_with_unicode_chars_áéíóú"
)

TOTAL_TESTS=0
PASSED_TESTS=0
FAILED_TESTS=0

# Function to print colored output
print_color() {
    printf "${1}${2}${NC}\n"
}

print_success() {
    print_color "$GREEN" "✓ $1"
    ((PASSED_TESTS++))
}

print_error() {
    print_color "$RED" "✗ $1"
    ((FAILED_TESTS++))
}

print_warning() {
    print_color "$YELLOW" "⚠ $1"
}

print_info() {
    print_color "$BLUE" "ℹ $1"
}

# Function to run a test
run_test() {
    local test_name="$1"
    local test_command="$2"

    ((TOTAL_TESTS++))
    print_info "Running test: $test_name"

    if eval "$test_command"; then
        print_success "$test_name"
        return 0
    else
        print_error "$test_name"
        return 1
    fi
}

# Function to cleanup
cleanup() {
    if [ -d "$TEST_DIR" ]; then
        rm -rf "$TEST_DIR"
        print_info "Cleaned up test directory: $TEST_DIR"
    fi
}

# Set up cleanup trap
trap cleanup EXIT

# Test 1: Check if crypto tool is available
test_crypto_tool_available() {
    cargo bin --list | grep -q "config_crypto_tool"
}

# Test 2: Generate encryption key
test_generate_key() {
    cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" generate-key --force > /dev/null 2>&1
}

# Test 3: Verify key exists and has correct permissions
test_key_file_permissions() {
    local key_file="$TEST_DIR/.k"
    [ -f "$key_file" ] && [ "$(stat -c %a "$key_file" 2>/dev/null || stat -f %A "$key_file" 2>/dev/null)" = "600" ]
}

# Test 4: Verify encryption key works
test_verify_key() {
    cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" verify > /dev/null 2>&1
}

# Test 5: Basic encryption/decryption
test_basic_encryption() {
    local test_value="test_encryption_value_123"
    local encrypted=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" encrypt "$test_value" 2>/dev/null)
    local decrypted=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" decrypt "$encrypted" 2>/dev/null)

    [ "$decrypted" = "$test_value" ]
}

# Test 6: Encryption produces different outputs for same input
test_encryption_randomness() {
    local test_value="randomness_test_value"
    local encrypted1=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" encrypt "$test_value" 2>/dev/null)
    local encrypted2=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" encrypt "$test_value" 2>/dev/null)

    [ "$encrypted1" != "$encrypted2" ]
}

# Test 7: Encrypted values start with @
test_encrypted_format() {
    local test_value="format_test_value"
    local encrypted=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" encrypt "$test_value" 2>/dev/null)

    [[ "$encrypted" == @* ]]
}

# Test 8: Multiple values encryption/decryption
test_multiple_values() {
    local all_passed=true

    for value in "${TEST_VALUES[@]}"; do
        local encrypted=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" encrypt "$value" 2>/dev/null)
        local decrypted=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" decrypt "$encrypted" 2>/dev/null)

        if [ "$decrypted" != "$value" ]; then
            print_error "Failed to encrypt/decrypt value: $value"
            all_passed=false
        fi
    done

    $all_passed
}

# Test 9: Invalid encrypted value handling
test_invalid_encrypted_value() {
    local invalid_encrypted="@invalid_base64_value"

    if cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" decrypt "$invalid_encrypted" > /dev/null 2>&1; then
        return 1  # Should fail
    else
        return 0  # Expected failure
    fi
}

# Test 10: Key rotation
test_key_rotation() {
    local test_value="rotation_test_value"

    # Encrypt with original key
    local encrypted_original=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" encrypt "$test_value" 2>/dev/null)

    # Rotate key
    cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" rotate-key --confirm > /dev/null 2>&1

    # Verify old encrypted value can't be decrypted with new key
    if cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" decrypt "$encrypted_original" > /dev/null 2>&1; then
        return 1  # Should fail with new key
    fi

    # Verify new encryption works
    local encrypted_new=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" encrypt "$test_value" 2>/dev/null)
    local decrypted_new=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" decrypt "$encrypted_new" 2>/dev/null)

    [ "$decrypted_new" = "$test_value" ]
}

# Test 11: Configuration file operations
test_config_operations() {
    local config_file="$TEST_DIR/test_config.toml"

    # Create test configuration
    cat > "$config_file" << EOF
[session]
secret = "plain_session_secret"

[database]
url = "postgresql://user:plain_password@localhost:5432/db"

[oauth.google]
client_secret = "plain_google_secret"

[email]
sendgrid_api_key = "@already_encrypted_value"
EOF

    # Test finding encrypted values
    local encrypted_count=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" find-encrypted -c "$config_file" 2>/dev/null | grep -c "@already_encrypted_value" || echo "0")

    [ "$encrypted_count" = "1" ]
}

# Test 12: Interactive mode simulation (basic test)
test_interactive_mode_basic() {
    # Test that interactive mode starts without error
    echo "6" | timeout 5 cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" interactive > /dev/null 2>&1
    return $?
}

# Test 13: Empty value handling
test_empty_value() {
    local empty_value=""
    local encrypted=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" encrypt "$empty_value" 2>/dev/null)
    local decrypted=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" decrypt "$encrypted" 2>/dev/null)

    [ "$decrypted" = "$empty_value" ]
}

# Test 14: Large value handling
test_large_value() {
    local large_value=$(printf 'a%.0s' {1..1000})  # 1000 character string
    local encrypted=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" encrypt "$large_value" 2>/dev/null)
    local decrypted=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" decrypt "$encrypted" 2>/dev/null)

    [ "$decrypted" = "$large_value" ]
}

# Test 15: Key info command
test_key_info() {
    cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" key-info > /dev/null 2>&1
}

# Main test execution
main() {
    print_info "Starting encryption system tests..."
    print_info "Test directory: $TEST_DIR"
    echo

    # Check if we're in the right directory
    if [ ! -f "Cargo.toml" ]; then
        print_error "This script must be run from the root of a Rust project"
        exit 1
    fi

    # Run all tests
    echo "=== Basic Functionality Tests ==="
    run_test "Crypto tool availability" test_crypto_tool_available
    run_test "Generate encryption key" test_generate_key
    run_test "Key file permissions" test_key_file_permissions
    run_test "Verify encryption key" test_verify_key
    run_test "Basic encryption/decryption" test_basic_encryption
    run_test "Encryption randomness" test_encryption_randomness
    run_test "Encrypted value format" test_encrypted_format

    echo
    echo "=== Advanced Functionality Tests ==="
    run_test "Multiple values encryption" test_multiple_values
    run_test "Invalid encrypted value handling" test_invalid_encrypted_value
    run_test "Key rotation" test_key_rotation
    run_test "Configuration file operations" test_config_operations
    run_test "Interactive mode basic" test_interactive_mode_basic

    echo
    echo "=== Edge Cases Tests ==="
    run_test "Empty value handling" test_empty_value
    run_test "Large value handling" test_large_value
    run_test "Key info command" test_key_info

    echo
    echo "=== Test Results ==="
    print_info "Total tests: $TOTAL_TESTS"
    print_success "Passed: $PASSED_TESTS"

    if [ $FAILED_TESTS -gt 0 ]; then
        print_error "Failed: $FAILED_TESTS"
        echo
        print_error "Some tests failed. Please check the encryption system implementation."
        exit 1
    else
        echo
        print_success "All tests passed! The encryption system is working correctly."

        echo
        print_info "Performance test with real values:"

        # Performance test
        local start_time=$(date +%s.%N)
        for i in {1..10}; do
            local test_value="performance_test_value_$i"
            local encrypted=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" encrypt "$test_value" 2>/dev/null)
            local decrypted=$(cargo run --bin config_crypto_tool -- --root-path "$TEST_DIR" decrypt "$encrypted" 2>/dev/null)

            if [ "$decrypted" != "$test_value" ]; then
                print_error "Performance test failed for value $i"
            fi
        done
        local end_time=$(date +%s.%N)
        local duration=$(echo "$end_time - $start_time" | bc 2>/dev/null || echo "N/A")

        if [ "$duration" != "N/A" ]; then
            print_info "10 encrypt/decrypt cycles completed in ${duration}s"
        else
            print_info "10 encrypt/decrypt cycles completed"
        fi

        echo
        print_success "Encryption system test completed successfully!"

        echo
        print_info "You can now safely use the encryption system in your configuration files."
        print_info "Remember to:"
        print_info "1. Keep the .k file secure and never commit it to version control"
        print_info "2. Backup your encryption keys"
        print_info "3. Use different keys for different environments"
        print_info "4. Rotate keys regularly in production"

        exit 0
    fi
}

# Run main function
main "$@"
