#!/bin/bash

# Configuration Encryption Setup Script
# This script helps set up the encryption system for configuration values

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

# Default values
ROOT_PATH="."
CONFIG_FILE=""
INTERACTIVE=false
FORCE=false
BACKUP=true
ENVIRONMENT="production"

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

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

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

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

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

# Function to show help
show_help() {
    cat << EOF
Configuration Encryption Setup Script

This script helps you set up and manage the configuration encryption system
for securing sensitive configuration values.

Usage: $0 [OPTIONS]

Options:
    -h, --help              Show this help message
    -r, --root-path PATH    Set root path for encryption key (default: .)
    -c, --config FILE       Configuration file to encrypt values in
    -i, --interactive       Run in interactive mode
    -f, --force             Force overwrite existing encryption key
    -e, --environment ENV   Environment (dev, staging, prod) (default: production)
    --no-backup             Don't create backups when modifying files
    --verify-only           Only verify existing encryption setup

Examples:
    $0                                    # Basic setup with interactive prompts
    $0 -i                                 # Full interactive setup
    $0 -c config.prod.toml                # Encrypt values in specific config file
    $0 -r /app --environment prod         # Setup for production in /app directory
    $0 --verify-only                      # Just verify current setup

The script will:
1. Generate encryption key if it doesn't exist
2. Help you encrypt sensitive configuration values
3. Update configuration files with encrypted values
4. Verify the encryption setup works correctly

Security Notes:
- Never commit the .k file to version control
- Use different keys for different environments
- Backup encryption keys securely
- Rotate keys regularly in production
EOF
}

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_help
            exit 0
            ;;
        -r|--root-path)
            ROOT_PATH="$2"
            shift 2
            ;;
        -c|--config)
            CONFIG_FILE="$2"
            shift 2
            ;;
        -i|--interactive)
            INTERACTIVE=true
            shift
            ;;
        -f|--force)
            FORCE=true
            shift
            ;;
        -e|--environment)
            ENVIRONMENT="$2"
            shift 2
            ;;
        --no-backup)
            BACKUP=false
            shift
            ;;
        --verify-only)
            VERIFY_ONLY=true
            shift
            ;;
        *)
            print_error "Unknown option: $1"
            show_help
            exit 1
            ;;
    esac
done

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

# Check if the crypto tool is available
if ! cargo bin --list | grep -q "config_crypto_tool"; then
    print_error "config_crypto_tool binary not found. Please ensure it's built:"
    print_info "cargo build --bin config_crypto_tool"
    exit 1
fi

# Function to check if encryption key exists
check_encryption_key() {
    if [ -f "$ROOT_PATH/.k" ]; then
        return 0
    else
        return 1
    fi
}

# Function to generate encryption key
generate_encryption_key() {
    print_info "Generating encryption key..."

    if check_encryption_key && [ "$FORCE" = false ]; then
        print_warning "Encryption key already exists at $ROOT_PATH/.k"
        read -p "Do you want to overwrite it? (y/N): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            print_info "Keeping existing encryption key"
            return 0
        fi
    fi

    local force_flag=""
    if [ "$FORCE" = true ]; then
        force_flag="--force"
    fi

    if cargo run --bin config_crypto_tool -- --root-path "$ROOT_PATH" generate-key $force_flag; then
        print_success "Encryption key generated at $ROOT_PATH/.k"

        # Set proper permissions
        chmod 600 "$ROOT_PATH/.k"
        print_success "Set secure permissions on encryption key file"

        # Verify the key works
        if cargo run --bin config_crypto_tool -- --root-path "$ROOT_PATH" verify; then
            print_success "Encryption key verification successful"
        else
            print_error "Encryption key verification failed"
            return 1
        fi
    else
        print_error "Failed to generate encryption key"
        return 1
    fi
}

# Function to encrypt a value
encrypt_value() {
    local value="$1"
    local description="$2"

    print_info "Encrypting $description..."

    if encrypted_value=$(cargo run --bin config_crypto_tool -- --root-path "$ROOT_PATH" encrypt "$value" 2>/dev/null); then
        echo "$encrypted_value"
        return 0
    else
        print_error "Failed to encrypt $description"
        return 1
    fi
}

# Function to show common values to encrypt
show_common_values() {
    cat << EOF

Common configuration values that should be encrypted:
- Database passwords
- Session secrets
- API keys (SendGrid, OAuth providers, etc.)
- SMTP passwords
- Redis URLs with credentials
- JWT secrets
- Third-party service credentials

EOF
}

# Function to encrypt values in configuration file
encrypt_config_values() {
    local config_file="$1"

    if [ ! -f "$config_file" ]; then
        print_error "Configuration file not found: $config_file"
        return 1
    fi

    print_info "Analyzing configuration file: $config_file"

    # Create backup if requested
    if [ "$BACKUP" = true ]; then
        local backup_file="${config_file}.backup.$(date +%Y%m%d_%H%M%S)"
        cp "$config_file" "$backup_file"
        print_success "Created backup: $backup_file"
    fi

    # Common sensitive keys that should be encrypted
    local sensitive_keys=(
        "session.secret"
        "database.url"
        "oauth.google.client_secret"
        "oauth.github.client_secret"
        "email.smtp_password"
        "email.sendgrid_api_key"
        "redis.url"
    )

    print_info "Checking for sensitive values to encrypt..."

    for key in "${sensitive_keys[@]}"; do
        # Check if this key exists in the config and is not already encrypted
        if grep -q "^${key//./\\.}" "$config_file" 2>/dev/null; then
            # Extract the current value
            local current_value=$(grep "^${key//./\\.}" "$config_file" | cut -d'"' -f2)

            if [[ "$current_value" =~ ^\$\{.*\}$ ]]; then
                print_info "Skipping $key (uses environment variable)"
                continue
            elif [[ "$current_value" == @* ]]; then
                print_info "Skipping $key (already encrypted)"
                continue
            elif [ -n "$current_value" ] && [ "$current_value" != "your-secret-here" ]; then
                print_warning "Found potentially sensitive value for $key"

                if [ "$INTERACTIVE" = true ]; then
                    read -p "Encrypt this value? (y/N): " -n 1 -r
                    echo
                    if [[ $REPLY =~ ^[Yy]$ ]]; then
                        if encrypted_value=$(encrypt_value "$current_value" "$key"); then
                            # Update the configuration file
                            sed -i.tmp "s|^${key//./\\.}.*|${key} = \"$encrypted_value\"|" "$config_file"
                            rm -f "$config_file.tmp"
                            print_success "Encrypted $key"
                        fi
                    fi
                fi
            fi
        fi
    done
}

# Function to verify encryption setup
verify_encryption_setup() {
    print_info "Verifying encryption setup..."

    # Check if key exists
    if ! check_encryption_key; then
        print_error "Encryption key not found at $ROOT_PATH/.k"
        return 1
    fi

    # Check key permissions
    if [ "$(stat -c %a "$ROOT_PATH/.k" 2>/dev/null)" != "600" ]; then
        print_warning "Encryption key file permissions are not secure"
        print_info "Setting secure permissions..."
        chmod 600 "$ROOT_PATH/.k"
    fi

    # Verify key works
    if cargo run --bin config_crypto_tool -- --root-path "$ROOT_PATH" verify; then
        print_success "Encryption key verification successful"
    else
        print_error "Encryption key verification failed"
        return 1
    fi

    # Check if .k is in .gitignore
    if [ -f ".gitignore" ]; then
        if grep -q "^\.k$" ".gitignore" || grep -q "^\.k " ".gitignore"; then
            print_success "Encryption key is properly ignored in .gitignore"
        else
            print_error "Encryption key is NOT in .gitignore - this is a security risk!"
            read -p "Add .k to .gitignore? (Y/n): " -n 1 -r
            echo
            if [[ ! $REPLY =~ ^[Nn]$ ]]; then
                echo ".k" >> .gitignore
                print_success "Added .k to .gitignore"
            fi
        fi
    else
        print_warning ".gitignore file not found"
    fi

    return 0
}

# Function to run interactive setup
run_interactive_setup() {
    print_info "Starting interactive encryption setup..."
    echo

    # Step 1: Generate or verify encryption key
    if check_encryption_key; then
        print_success "Encryption key already exists"
        read -p "Do you want to verify it? (Y/n): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Nn]$ ]]; then
            verify_encryption_setup
        fi
    else
        print_info "No encryption key found"
        read -p "Generate new encryption key? (Y/n): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Nn]$ ]]; then
            generate_encryption_key
        fi
    fi

    echo

    # Step 2: Encrypt individual values
    print_info "You can now encrypt individual values:"
    while true; do
        read -p "Enter a value to encrypt (or 'skip' to continue): " value
        if [ "$value" = "skip" ] || [ -z "$value" ]; then
            break
        fi

        if encrypted_value=$(encrypt_value "$value" "custom value"); then
            print_success "Encrypted value: $encrypted_value"
            echo "Use this in your configuration file:"
            echo "some_key = \"$encrypted_value\""
        fi
        echo
    done

    # Step 3: Encrypt configuration file values
    if [ -n "$CONFIG_FILE" ]; then
        print_info "Encrypting values in configuration file: $CONFIG_FILE"
        encrypt_config_values "$CONFIG_FILE"
    else
        echo
        print_info "Available configuration files:"
        for file in config*.toml; do
            if [ -f "$file" ]; then
                echo "  - $file"
            fi
        done

        read -p "Enter configuration file to encrypt values in (or 'skip'): " config_file
        if [ "$config_file" != "skip" ] && [ -n "$config_file" ]; then
            encrypt_config_values "$config_file"
        fi
    fi

    echo
    print_success "Interactive setup completed!"
}

# Function to show security recommendations
show_security_recommendations() {
    cat << EOF

${GREEN}Security Recommendations:${NC}

1. ${YELLOW}Never commit the .k file to version control${NC}
   - The .k file contains your encryption key
   - Add it to .gitignore immediately
   - Use different keys for different environments

2. ${YELLOW}Backup your encryption keys securely${NC}
   - Store backups in a secure, separate location
   - Consider using encrypted backup storage
   - Document your backup procedures

3. ${YELLOW}Use proper file permissions${NC}
   - Key files should be readable only by the application user
   - Use chmod 600 for the .k file
   - Monitor file access regularly

4. ${YELLOW}Rotate keys regularly${NC}
   - Consider quarterly or yearly key rotation
   - Have a key rotation procedure documented
   - Test key rotation in staging first

5. ${YELLOW}Monitor and audit${NC}
   - Log encryption/decryption operations
   - Monitor key file access
   - Regular security audits

6. ${YELLOW}Environment separation${NC}
   - Use different encryption keys for dev/staging/prod
   - Never use production keys in development
   - Secure key distribution procedures

EOF
}

# Main execution
main() {
    echo
    print_info "Configuration Encryption Setup Script"
    print_info "Environment: $ENVIRONMENT"
    print_info "Root Path: $ROOT_PATH"
    echo

    # Change to root path
    cd "$ROOT_PATH"

    # Verify-only mode
    if [ "$VERIFY_ONLY" = true ]; then
        verify_encryption_setup
        exit $?
    fi

    # Interactive mode
    if [ "$INTERACTIVE" = true ]; then
        run_interactive_setup
        echo
        show_security_recommendations
        exit 0
    fi

    # Non-interactive mode
    print_info "Running automated setup..."

    # Generate encryption key if it doesn't exist
    if ! check_encryption_key; then
        generate_encryption_key
    else
        print_success "Encryption key already exists"
        verify_encryption_setup
    fi

    # Encrypt configuration file if specified
    if [ -n "$CONFIG_FILE" ]; then
        encrypt_config_values "$CONFIG_FILE"
    fi

    echo
    print_success "Encryption setup completed!"

    # Show next steps
    cat << EOF

${GREEN}Next Steps:${NC}
1. Test your configuration: cargo run --bin config_crypto_tool verify
2. Encrypt sensitive values: cargo run --bin config_crypto_tool encrypt "your-secret"
3. Update your configuration files with encrypted values
4. Ensure .k file is in .gitignore
5. Backup your encryption key securely

${BLUE}Useful Commands:${NC}
- Encrypt value: cargo run --bin config_crypto_tool encrypt "value"
- Decrypt value: cargo run --bin config_crypto_tool decrypt "@encrypted"
- Find encrypted values: cargo run --bin config_crypto_tool find-encrypted -c config.toml
- Interactive mode: cargo run --bin config_crypto_tool interactive

EOF

    show_security_recommendations
}

# Run main function
main "$@"
