#!/bin/bash

# Ginxsom Interactive Setup Wizard
# Creates signed configuration events for first-run server setup

set -e

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
CONFIG_PATH="${1:-}"

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

# Helper functions
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }

# Check dependencies
check_dependencies() {
    log_info "Checking dependencies..."
    local missing_deps=()
    
    for cmd in nak jq; do
        if ! command -v $cmd &> /dev/null; then
            missing_deps+=("$cmd")
        fi
    done
    
    if [ ${#missing_deps[@]} -ne 0 ]; then
        log_error "Missing dependencies: ${missing_deps[*]}"
        echo ""
        echo "Please install the missing dependencies:"
        echo "- nak: https://github.com/fiatjaf/nak"
        echo "- jq: sudo apt install jq (or equivalent for your system)"
        exit 1
    fi
    
    log_success "All dependencies found"
}

# Validate private key format
validate_private_key() {
    local key="$1"
    if [[ ! "$key" =~ ^[a-fA-F0-9]{64}$ ]]; then
        return 1
    fi
    return 0
}

# Setup key pairs with user choice
setup_keys() {
    log_info "Setting up cryptographic key pairs..."
    echo ""
    echo "=== Admin Key Setup ==="
    echo "Choose an option for your admin private key:"
    echo "1. Generate a new random admin key"
    echo "2. Use an existing admin private key"
    echo ""
    
    while true; do
        echo -n "Choice (1/2): "
        read -r ADMIN_KEY_CHOICE
        case "$ADMIN_KEY_CHOICE" in
            1)
                log_info "Generating new admin key pair..."
                ADMIN_PRIVKEY=$(nak key generate)
                ADMIN_PUBKEY=$(echo "$ADMIN_PRIVKEY" | nak key public)
                log_success "New admin key pair generated"
                break
                ;;
            2)
                echo -n "Enter your admin private key (64 hex characters): "
                read -r ADMIN_PRIVKEY
                if validate_private_key "$ADMIN_PRIVKEY"; then
                    ADMIN_PUBKEY=$(echo "$ADMIN_PRIVKEY" | nak key public)
                    if [ $? -eq 0 ]; then
                        log_success "Admin private key validated"
                        break
                    else
                        log_error "Invalid private key format or nak error"
                    fi
                else
                    log_error "Invalid private key format (must be 64 hex characters)"
                fi
                ;;
            *)
                log_error "Please choose 1 or 2"
                ;;
        esac
    done
    
    echo ""
    echo "=== Server Key Setup ==="
    echo "Choose an option for your Ginxsom server private key:"
    echo "1. Generate a new random server key"
    echo "2. Use an existing server private key"
    echo ""
    
    while true; do
        echo -n "Choice (1/2): "
        read -r SERVER_KEY_CHOICE
        case "$SERVER_KEY_CHOICE" in
            1)
                log_info "Generating new server key pair..."
                SERVER_PRIVKEY=$(nak key generate)
                SERVER_PUBKEY=$(echo "$SERVER_PRIVKEY" | nak key public)
                log_success "New server key pair generated"
                break
                ;;
            2)
                echo -n "Enter your server private key (64 hex characters): "
                read -r SERVER_PRIVKEY
                if validate_private_key "$SERVER_PRIVKEY"; then
                    SERVER_PUBKEY=$(echo "$SERVER_PRIVKEY" | nak key public)
                    if [ $? -eq 0 ]; then
                        log_success "Server private key validated"
                        break
                    else
                        log_error "Invalid private key format or nak error"
                    fi
                else
                    log_error "Invalid private key format (must be 64 hex characters)"
                fi
                ;;
            *)
                log_error "Please choose 1 or 2"
                ;;
        esac
    done
    
    echo ""
    log_success "Key pairs configured:"
    echo "  Admin Public Key:  $ADMIN_PUBKEY"
    echo "  Server Public Key: $SERVER_PUBKEY"
    
    # Save keys securely
    echo "ADMIN_PRIVKEY='$ADMIN_PRIVKEY'" > "$PROJECT_ROOT/.admin_keys"
    echo "ADMIN_PUBKEY='$ADMIN_PUBKEY'" >> "$PROJECT_ROOT/.admin_keys"
    echo "SERVER_PRIVKEY='$SERVER_PRIVKEY'" >> "$PROJECT_ROOT/.admin_keys"
    echo "SERVER_PUBKEY='$SERVER_PUBKEY'" >> "$PROJECT_ROOT/.admin_keys"
    chmod 600 "$PROJECT_ROOT/.admin_keys"
    
    log_warning "Keys saved to $PROJECT_ROOT/.admin_keys (keep this file secure!)"
}

# Collect server configuration
collect_configuration() {
    log_info "Collecting server configuration..."
    
    echo ""
    echo "=== Server Configuration Setup ==="
    
    # CDN Origin
    echo -n "CDN Origin URL (default: http://localhost:9001): "
    read -r CDN_ORIGIN
    CDN_ORIGIN="${CDN_ORIGIN:-http://localhost:9001}"
    
    # Max file size
    echo -n "Maximum file size in MB (default: 100): "
    read -r MAX_SIZE_MB
    MAX_SIZE_MB="${MAX_SIZE_MB:-100}"
    MAX_FILE_SIZE=$((MAX_SIZE_MB * 1024 * 1024))
    
    # NIP-94 support
    echo -n "Enable NIP-94 metadata (y/n, default: y): "
    read -r ENABLE_NIP94
    case "$ENABLE_NIP94" in
        [Nn]*) NIP94_ENABLED="false" ;;
        *) NIP94_ENABLED="true" ;;
    esac
    
    # Authentication rules
    echo -n "Enable authentication rules system (y/n, default: n): "
    read -r ENABLE_AUTH_RULES
    case "$ENABLE_AUTH_RULES" in
        [Yy]*) AUTH_RULES_ENABLED="true" ;;
        *) AUTH_RULES_ENABLED="false" ;;
    esac
    
    # Cache TTL
    echo -n "Authentication cache TTL in seconds (default: 300): "
    read -r CACHE_TTL
    CACHE_TTL="${CACHE_TTL:-300}"
    
    echo ""
    log_success "Configuration collected:"
    echo "  CDN Origin: $CDN_ORIGIN"
    echo "  Max File Size: ${MAX_SIZE_MB}MB"
    echo "  NIP-94 Enabled: $NIP94_ENABLED"
    echo "  Auth Rules Enabled: $AUTH_RULES_ENABLED"
    echo "  Cache TTL: ${CACHE_TTL}s"
}

# Create configuration event
create_config_event() {
    log_info "Creating signed configuration event..."
    
    local expiration=$(($(date +%s) + 31536000))  # 1 year from now
    
    # Create configuration event with all settings
    CONFIG_EVENT=$(nak event -k 33333 -c "Ginxsom server configuration" \
        --tag server_privkey="$SERVER_PRIVKEY" \
        --tag cdn_origin="$CDN_ORIGIN" \
        --tag max_file_size="$MAX_FILE_SIZE" \
        --tag nip94_enabled="$NIP94_ENABLED" \
        --tag auth_rules_enabled="$AUTH_RULES_ENABLED" \
        --tag auth_cache_ttl="$CACHE_TTL" \
        --tag expiration="$expiration" \
        --sec "$ADMIN_PRIVKEY")
    
    if [ $? -ne 0 ]; then
        log_error "Failed to create configuration event"
        exit 1
    fi
    
    log_success "Configuration event created and signed"
}

# Save configuration file
save_config_file() {
    local config_file="$1"
    
    log_info "Saving configuration to $config_file"
    
    # Create directory if it doesn't exist
    local config_dir=$(dirname "$config_file")
    mkdir -p "$config_dir"
    
    # Save configuration event to file
    echo "$CONFIG_EVENT" | jq . > "$config_file"
    
    if [ $? -ne 0 ]; then
        log_error "Failed to save configuration file"
        exit 1
    fi
    
    chmod 600 "$config_file"
    log_success "Configuration saved to $config_file"
}

# Setup database
setup_database() {
    log_info "Setting up database configuration..."
    
    local db_path="$PROJECT_ROOT/db/ginxsom.db"
    
    if [ ! -f "$db_path" ]; then
        log_warning "Database not found at $db_path"
        log_warning "Please ensure the database is initialized before starting the server"
        return
    fi
    
    # Insert admin configuration into database
    sqlite3 "$db_path" << EOF
INSERT OR REPLACE INTO server_config (key, value, description) VALUES
    ('admin_pubkey', '$ADMIN_PUBKEY', 'Admin public key from setup wizard'),
    ('admin_enabled', 'true', 'Enable admin interface');
EOF
    
    if [ $? -eq 0 ]; then
        log_success "Database configuration updated"
    else
        log_warning "Failed to update database (this is OK if database doesn't exist yet)"
    fi
}

# Display setup summary
show_setup_summary() {
    echo ""
    echo "================================================================="
    echo "                   GINXSOM SETUP COMPLETE"
    echo "================================================================="
    echo ""
    log_success "Configuration file created: $CONFIG_PATH"
    log_success "Admin keys saved: $PROJECT_ROOT/.admin_keys"
    echo ""
    echo "Next steps:"
    echo "1. Start the Ginxsom server:"
    echo "   cd $PROJECT_ROOT"
    echo "   make run"
    echo ""
    echo "2. Test admin API access:"
    echo "   source .admin_keys"
    echo "   ./scripts/test_admin.sh"
    echo ""
    echo "3. Access web admin (when implemented):"
    echo "   http://localhost:9001/admin"
    echo ""
    log_warning "Keep the .admin_keys file secure - it contains your admin private key!"
    echo ""
}

# Main setup workflow
main() {
    echo "=== Ginxsom Interactive Setup Wizard ==="
    echo ""
    
    # Validate config path
    if [ -z "$CONFIG_PATH" ]; then
        # Determine default config path
        if [ -n "$XDG_CONFIG_HOME" ]; then
            CONFIG_PATH="$XDG_CONFIG_HOME/ginxsom/ginxsom_config_event.json"
        else
            CONFIG_PATH="$HOME/.config/ginxsom/ginxsom_config_event.json"
        fi
    fi
    
    log_info "Configuration will be saved to: $CONFIG_PATH"
    
    # Check if config already exists
    if [ -f "$CONFIG_PATH" ]; then
        log_warning "Configuration file already exists at $CONFIG_PATH"
        echo -n "Overwrite existing configuration? (y/n): "
        read -r OVERWRITE
        case "$OVERWRITE" in
            [Yy]*) ;;
            *) log_info "Setup cancelled"; exit 0 ;;
        esac
    fi
    
    # Run setup steps
    check_dependencies
    setup_keys
    collect_configuration
    create_config_event
    save_config_file "$CONFIG_PATH"
    setup_database
    show_setup_summary
}

# Allow sourcing for testing individual functions
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi