#!/bin/bash

# C Nostr Relay - Backup Script
# Automated backup solution for event-based configuration relay

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 configuration
RELAY_DIR="/opt/c-relay"
BACKUP_DIR="/backup/c-relay"
RETENTION_DAYS="30"
COMPRESS="true"
REMOTE_BACKUP=""
S3_BUCKET=""
NOTIFICATION_EMAIL=""
LOG_FILE="/var/log/relay-backup.log"

# Functions
print_step() {
    echo -e "${BLUE}[STEP]${NC} $1"
    echo "$(date '+%Y-%m-%d %H:%M:%S') [STEP] $1" >> "$LOG_FILE"
}

print_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
    echo "$(date '+%Y-%m-%d %H:%M:%S') [SUCCESS] $1" >> "$LOG_FILE"
}

print_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
    echo "$(date '+%Y-%m-%d %H:%M:%S') [WARNING] $1" >> "$LOG_FILE"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
    echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1" >> "$LOG_FILE"
}

show_help() {
    echo "Usage: $0 [OPTIONS]"
    echo
    echo "Options:"
    echo "  -d, --relay-dir DIR       Relay directory (default: /opt/c-relay)"
    echo "  -b, --backup-dir DIR      Backup directory (default: /backup/c-relay)"
    echo "  -r, --retention DAYS      Retention period in days (default: 30)"
    echo "  -n, --no-compress         Don't compress backups"
    echo "  -s, --s3-bucket BUCKET    Upload to S3 bucket"
    echo "  -e, --email EMAIL         Send notification email"
    echo "  -v, --verify              Verify backup integrity"
    echo "  -h, --help                Show this help message"
    echo
    echo "Examples:"
    echo "  $0                                    # Basic backup"
    echo "  $0 -s my-backup-bucket -e admin@example.com"
    echo "  $0 -r 7 -n                          # 7-day retention, no compression"
}

parse_args() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            -d|--relay-dir)
                RELAY_DIR="$2"
                shift 2
                ;;
            -b|--backup-dir)
                BACKUP_DIR="$2"
                shift 2
                ;;
            -r|--retention)
                RETENTION_DAYS="$2"
                shift 2
                ;;
            -n|--no-compress)
                COMPRESS="false"
                shift
                ;;
            -s|--s3-bucket)
                S3_BUCKET="$2"
                shift 2
                ;;
            -e|--email)
                NOTIFICATION_EMAIL="$2"
                shift 2
                ;;
            -v|--verify)
                VERIFY="true"
                shift
                ;;
            -h|--help)
                show_help
                exit 0
                ;;
            *)
                print_error "Unknown option: $1"
                show_help
                exit 1
                ;;
        esac
    done
}

check_dependencies() {
    print_step "Checking dependencies..."
    
    # Check sqlite3
    if ! command -v sqlite3 &> /dev/null; then
        print_error "sqlite3 not found. Install with: apt install sqlite3"
        exit 1
    fi
    
    # Check compression tools
    if [[ "$COMPRESS" == "true" ]]; then
        if ! command -v gzip &> /dev/null; then
            print_error "gzip not found for compression"
            exit 1
        fi
    fi
    
    # Check S3 tools if needed
    if [[ -n "$S3_BUCKET" ]]; then
        if ! command -v aws &> /dev/null; then
            print_error "AWS CLI not found. Install with: apt install awscli"
            exit 1
        fi
    fi
    
    print_success "Dependencies verified"
}

find_database() {
    print_step "Finding relay database..."
    
    # Look for .nrdb files in relay directory
    DB_FILES=($(find "$RELAY_DIR" -name "*.nrdb" 2>/dev/null))
    
    if [[ ${#DB_FILES[@]} -eq 0 ]]; then
        print_error "No relay database files found in $RELAY_DIR"
        exit 1
    elif [[ ${#DB_FILES[@]} -gt 1 ]]; then
        print_warning "Multiple database files found:"
        printf '%s\n' "${DB_FILES[@]}"
        print_warning "Using the first one: ${DB_FILES[0]}"
    fi
    
    DB_FILE="${DB_FILES[0]}"
    DB_NAME=$(basename "$DB_FILE")
    
    print_success "Found database: $DB_FILE"
}

create_backup_directory() {
    print_step "Creating backup directory..."
    
    if [[ ! -d "$BACKUP_DIR" ]]; then
        mkdir -p "$BACKUP_DIR"
        chmod 700 "$BACKUP_DIR"
        print_success "Created backup directory: $BACKUP_DIR"
    else
        print_success "Using existing backup directory: $BACKUP_DIR"
    fi
}

perform_backup() {
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local backup_name="relay_backup_${timestamp}"
    local backup_file="$BACKUP_DIR/${backup_name}.nrdb"
    
    print_step "Creating database backup..."
    
    # Check if database is accessible
    if [[ ! -r "$DB_FILE" ]]; then
        print_error "Cannot read database file: $DB_FILE"
        exit 1
    fi
    
    # Get database size
    local db_size=$(du -h "$DB_FILE" | cut -f1)
    print_step "Database size: $db_size"
    
    # Create SQLite backup using .backup command (hot backup)
    if sqlite3 "$DB_FILE" ".backup $backup_file" 2>/dev/null; then
        print_success "Database backup created: $backup_file"
    else
        # Fallback to file copy if .backup fails
        print_warning "SQLite backup failed, using file copy method"
        cp "$DB_FILE" "$backup_file"
        print_success "File copy backup created: $backup_file"
    fi
    
    # Verify backup file
    if [[ ! -f "$backup_file" ]]; then
        print_error "Backup file was not created"
        exit 1
    fi
    
    # Check backup integrity
    if [[ "$VERIFY" == "true" ]]; then
        print_step "Verifying backup integrity..."
        if sqlite3 "$backup_file" "PRAGMA integrity_check;" | grep -q "ok"; then
            print_success "Backup integrity verified"
        else
            print_error "Backup integrity check failed"
            exit 1
        fi
    fi
    
    # Compress backup
    if [[ "$COMPRESS" == "true" ]]; then
        print_step "Compressing backup..."
        gzip "$backup_file"
        backup_file="${backup_file}.gz"
        print_success "Backup compressed: $backup_file"
    fi
    
    # Set backup file as global variable for other functions
    BACKUP_FILE="$backup_file"
    BACKUP_NAME="$backup_name"
}

upload_to_s3() {
    if [[ -z "$S3_BUCKET" ]]; then
        return 0
    fi
    
    print_step "Uploading backup to S3..."
    
    local s3_path="s3://$S3_BUCKET/c-relay/$(date +%Y)/$(date +%m)/"
    
    if aws s3 cp "$BACKUP_FILE" "$s3_path" --storage-class STANDARD_IA; then
        print_success "Backup uploaded to S3: $s3_path"
    else
        print_error "Failed to upload backup to S3"
        return 1
    fi
}

cleanup_old_backups() {
    print_step "Cleaning up old backups..."
    
    local deleted_count=0
    
    # Clean local backups
    while IFS= read -r -d '' file; do
        rm "$file"
        ((deleted_count++))
    done < <(find "$BACKUP_DIR" -name "relay_backup_*.nrdb*" -mtime "+$RETENTION_DAYS" -print0 2>/dev/null)
    
    if [[ $deleted_count -gt 0 ]]; then
        print_success "Deleted $deleted_count old local backups"
    else
        print_success "No old local backups to delete"
    fi
    
    # Clean S3 backups if configured
    if [[ -n "$S3_BUCKET" ]]; then
        local cutoff_date=$(date -d "$RETENTION_DAYS days ago" +%Y-%m-%d)
        print_step "Cleaning S3 backups older than $cutoff_date..."
        
        # Note: This is a simplified approach. In production, use S3 lifecycle policies
        aws s3 ls "s3://$S3_BUCKET/c-relay/" --recursive | \
        awk '$1 < "'$cutoff_date'" {print $4}' | \
        while read -r key; do
            aws s3 rm "s3://$S3_BUCKET/$key"
            print_step "Deleted S3 backup: $key"
        done
    fi
}

send_notification() {
    if [[ -z "$NOTIFICATION_EMAIL" ]]; then
        return 0
    fi
    
    print_step "Sending notification email..."
    
    local subject="C Nostr Relay Backup - $(date +%Y-%m-%d)"
    local backup_size=$(du -h "$BACKUP_FILE" | cut -f1)
    
    local message="Backup completed successfully.

Details:
- Date: $(date)
- Database: $DB_FILE
- Backup File: $BACKUP_FILE
- Backup Size: $backup_size
- Retention: $RETENTION_DAYS days
"
    
    if [[ -n "$S3_BUCKET" ]]; then
        message+="\n- S3 Bucket: $S3_BUCKET"
    fi
    
    # Try to send email using mail command
    if command -v mail &> /dev/null; then
        echo -e "$message" | mail -s "$subject" "$NOTIFICATION_EMAIL"
        print_success "Notification sent to $NOTIFICATION_EMAIL"
    else
        print_warning "Mail command not available, skipping notification"
    fi
}

show_backup_summary() {
    local backup_size=$(du -h "$BACKUP_FILE" | cut -f1)
    local backup_count=$(find "$BACKUP_DIR" -name "relay_backup_*.nrdb*" | wc -l)
    
    echo
    echo "🎉 Backup Completed Successfully!"
    echo
    echo "Backup Details:"
    echo "  Source DB:     $DB_FILE"
    echo "  Backup File:   $BACKUP_FILE"
    echo "  Backup Size:   $backup_size"
    echo "  Compressed:    $COMPRESS"
    echo "  Verified:      ${VERIFY:-false}"
    echo
    echo "Storage:"
    echo "  Local Backups: $backup_count files in $BACKUP_DIR"
    echo "  Retention:     $RETENTION_DAYS days"
    
    if [[ -n "$S3_BUCKET" ]]; then
        echo "  S3 Bucket:     $S3_BUCKET"
    fi
    
    echo
    echo "Management Commands:"
    echo "  List backups:  find $BACKUP_DIR -name 'relay_backup_*'"
    echo "  Restore:       See examples/deployment/backup/restore-relay.sh"
    echo
}

# Main execution
main() {
    echo
    echo "==============================================="
    echo "💾 C Nostr Relay - Database Backup"
    echo "==============================================="
    echo
    
    # Initialize log file
    mkdir -p "$(dirname "$LOG_FILE")"
    touch "$LOG_FILE"
    
    parse_args "$@"
    check_dependencies
    find_database
    create_backup_directory
    perform_backup
    upload_to_s3
    cleanup_old_backups
    send_notification
    show_backup_summary
    
    print_success "Backup process completed successfully!"
}

# Handle errors
trap 'print_error "Backup failed at line $LINENO"' ERR

# Run main function
main "$@"