#!/bin/bash

# Ginxsom Manual Configuration Generator
# Creates signed configuration events for server setup

set -e

# Default values
ADMIN_KEY=""
SERVER_KEY=""
CDN_ORIGIN="http://localhost:9001"
MAX_FILE_SIZE="104857600"  # 100MB
NIP94_ENABLED="true"
AUTH_RULES_ENABLED="false"
AUTH_CACHE_TTL="300"
OUTPUT_FILE=""
EXPIRATION_HOURS="8760"  # 1 year

# 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"; }

# Display usage
usage() {
    cat << EOF
Usage: $0 [OPTIONS]

Generate a signed Ginxsom configuration event.

OPTIONS:
    --admin-key KEY         Admin private key (hex, 64 chars)
    --server-key KEY        Server private key (hex, 64 chars) 
    --cdn-origin URL        CDN origin URL (default: http://localhost:9001)
    --max-size BYTES        Maximum file size in bytes (default: 104857600)
    --enable-nip94          Enable NIP-94 metadata (default: true)
    --disable-nip94         Disable NIP-94 metadata
    --enable-auth-rules     Enable authentication rules system
    --disable-auth-rules    Disable authentication rules system (default)
    --cache-ttl SECONDS     Auth cache TTL in seconds (default: 300)
    --expiration HOURS      Config expiration in hours (default: 8760)
    --output FILE           Output file path
    --generate-keys         Generate new admin and server keys
    --help                  Show this help

EXAMPLES:
    # Generate keys and create config interactively
    $0 --generate-keys --output config.json

    # Create config with existing keys
    $0 --admin-key abc123... --server-key def456... --output config.json

    # Create config for production server
    $0 --admin-key abc123... --server-key def456... \\
       --cdn-origin https://cdn.example.com \\
       --max-size 209715200 \\
       --enable-auth-rules \\
       --output /etc/ginxsom/config.json

EOF
}

# Parse command line arguments
parse_args() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            --admin-key)
                ADMIN_KEY="$2"
                shift 2
                ;;
            --server-key)
                SERVER_KEY="$2"
                shift 2
                ;;
            --cdn-origin)
                CDN_ORIGIN="$2"
                shift 2
                ;;
            --max-size)
                MAX_FILE_SIZE="$2"
                shift 2
                ;;
            --enable-nip94)
                NIP94_ENABLED="true"
                shift
                ;;
            --disable-nip94)
                NIP94_ENABLED="false"
                shift
                ;;
            --enable-auth-rules)
                AUTH_RULES_ENABLED="true"
                shift
                ;;
            --disable-auth-rules)
                AUTH_RULES_ENABLED="false"
                shift
                ;;
            --cache-ttl)
                AUTH_CACHE_TTL="$2"
                shift 2
                ;;
            --expiration)
                EXPIRATION_HOURS="$2"
                shift 2
                ;;
            --output)
                OUTPUT_FILE="$2"
                shift 2
                ;;
            --generate-keys)
                GENERATE_KEYS="true"
                shift
                ;;
            --help)
                usage
                exit 0
                ;;
            *)
                log_error "Unknown option: $1"
                usage
                exit 1
                ;;
        esac
    done
}

# 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"
}

# Generate new key pairs
generate_keys() {
    log_info "Generating new key pairs..."
    
    ADMIN_KEY=$(nak key generate)
    SERVER_KEY=$(nak key generate)
    
    local admin_pubkey=$(echo "$ADMIN_KEY" | nak key public)
    local server_pubkey=$(echo "$SERVER_KEY" | nak key public)
    
    log_success "New keys generated:"
    echo "  Admin Private Key:  $ADMIN_KEY"
    echo "  Admin Public Key:   $admin_pubkey"
    echo "  Server Private Key: $SERVER_KEY"
    echo "  Server Public Key:  $server_pubkey"
    echo ""
    log_warning "Save these keys securely!"
}

# Validate keys
validate_keys() {
    log_info "Validating keys..."
    
    if [ -z "$ADMIN_KEY" ]; then
        log_error "Admin key is required (use --admin-key or --generate-keys)"
        exit 1
    fi
    
    if [ -z "$SERVER_KEY" ]; then
        log_error "Server key is required (use --server-key or --generate-keys)"
        exit 1
    fi
    
    # Validate key format (64 hex characters)
    if [[ ! "$ADMIN_KEY" =~ ^[a-fA-F0-9]{64}$ ]]; then
        log_error "Invalid admin key format (must be 64 hex characters)"
        exit 1
    fi
    
    if [[ ! "$SERVER_KEY" =~ ^[a-fA-F0-9]{64}$ ]]; then
        log_error "Invalid server key format (must be 64 hex characters)"
        exit 1
    fi
    
    # Test key validity with nak
    local admin_pubkey=$(echo "$ADMIN_KEY" | nak key public 2>/dev/null)
    local server_pubkey=$(echo "$SERVER_KEY" | nak key public 2>/dev/null)
    
    if [ -z "$admin_pubkey" ]; then
        log_error "Invalid admin private key"
        exit 1
    fi
    
    if [ -z "$server_pubkey" ]; then
        log_error "Invalid server private key"
        exit 1
    fi
    
    log_success "Keys validated"
}

# Validate configuration values
validate_config() {
    log_info "Validating configuration..."
    
    # Validate URL format
    if [[ ! "$CDN_ORIGIN" =~ ^https?:// ]]; then
        log_error "CDN origin must be a valid HTTP/HTTPS URL"
        exit 1
    fi
    
    # Validate max file size
    if [[ ! "$MAX_FILE_SIZE" =~ ^[0-9]+$ ]]; then
        log_error "Max file size must be a number"
        exit 1
    fi
    
    if [ "$MAX_FILE_SIZE" -lt 1024 ]; then
        log_error "Max file size must be at least 1024 bytes"
        exit 1
    fi
    
    # Validate boolean values
    if [[ ! "$NIP94_ENABLED" =~ ^(true|false)$ ]]; then
        log_error "NIP94 enabled must be 'true' or 'false'"
        exit 1
    fi
    
    if [[ ! "$AUTH_RULES_ENABLED" =~ ^(true|false)$ ]]; then
        log_error "Auth rules enabled must be 'true' or 'false'"
        exit 1
    fi
    
    # Validate cache TTL
    if [[ ! "$AUTH_CACHE_TTL" =~ ^[0-9]+$ ]]; then
        log_error "Cache TTL must be a number"
        exit 1
    fi
    
    if [ "$AUTH_CACHE_TTL" -lt 60 ]; then
        log_error "Cache TTL must be at least 60 seconds"
        exit 1
    fi
    
    log_success "Configuration validated"
}

# Create configuration event
create_config_event() {
    log_info "Creating signed configuration event..."
    
    local expiration=$(($(date +%s) + (EXPIRATION_HOURS * 3600)))
    
    # Create configuration event with all settings
    CONFIG_EVENT=$(nak event -k 33333 -c "Ginxsom server configuration" \
        --tag server_privkey="$SERVER_KEY" \
        --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="$AUTH_CACHE_TTL" \
        --tag expiration="$expiration" \
        --sec "$ADMIN_KEY")
    
    if [ $? -ne 0 ]; then
        log_error "Failed to create configuration event"
        exit 1
    fi
    
    log_success "Configuration event created and signed"
}

# Save configuration
save_config() {
    if [ -z "$OUTPUT_FILE" ]; then
        # Default output location
        if [ -n "$XDG_CONFIG_HOME" ]; then
            OUTPUT_FILE="$XDG_CONFIG_HOME/ginxsom/ginxsom_config_event.json"
        else
            OUTPUT_FILE="$HOME/.config/ginxsom/ginxsom_config_event.json"
        fi
    fi
    
    log_info "Saving configuration to $OUTPUT_FILE"
    
    # Create directory if needed
    local output_dir=$(dirname "$OUTPUT_FILE")
    mkdir -p "$output_dir"
    
    # Save formatted JSON
    echo "$CONFIG_EVENT" | jq . > "$OUTPUT_FILE"
    
    if [ $? -ne 0 ]; then
        log_error "Failed to save configuration file"
        exit 1
    fi
    
    chmod 600 "$OUTPUT_FILE"
    log_success "Configuration saved to $OUTPUT_FILE"
}

# Display summary
show_summary() {
    local admin_pubkey=$(echo "$ADMIN_KEY" | nak key public)
    local server_pubkey=$(echo "$SERVER_KEY" | nak key public)
    
    echo ""
    echo "================================================================="
    echo "            GINXSOM CONFIGURATION GENERATED"
    echo "================================================================="
    echo ""
    log_success "Configuration file: $OUTPUT_FILE"
    echo ""
    echo "Configuration summary:"
    echo "  Admin Public Key:     $admin_pubkey"
    echo "  Server Public Key:    $server_pubkey"
    echo "  CDN Origin:           $CDN_ORIGIN"
    echo "  Max File Size:        $(( MAX_FILE_SIZE / 1024 / 1024 ))MB"
    echo "  NIP-94 Enabled:       $NIP94_ENABLED"
    echo "  Auth Rules Enabled:   $AUTH_RULES_ENABLED"
    echo "  Cache TTL:            ${AUTH_CACHE_TTL}s"
    echo "  Expires:              $(date -d @$(($(date +%s) + (EXPIRATION_HOURS * 3600))))"
    echo ""
    echo "Next steps:"
    echo "1. Place config file in server's config directory"
    echo "2. Set admin_pubkey in server database:"
    echo "   sqlite3 db/ginxsom.db << EOF"
    echo "   INSERT OR REPLACE INTO server_config (key, value) VALUES"
    echo "       ('admin_pubkey', '$admin_pubkey'),"
    echo "       ('admin_enabled', 'true');"
    echo "   EOF"
    echo "3. Start ginxsom server"
    echo ""
}

# Main execution
main() {
    parse_args "$@"
    
    if [ "$GENERATE_KEYS" = "true" ]; then
        check_dependencies
        generate_keys
    fi
    
    validate_keys
    validate_config
    create_config_event
    save_config
    show_summary
}

# Run main function if script is executed directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi