#!/usr/bin/env nu

# VAPORA Database Backup Script - SurrealDB to S3 + Restic
# Follows NUSHELL_GUIDELINES.md strictly (0.109.0+)

# Get ISO 8601 timestamp
def get-timestamp []: nothing -> string {
    date now | format date "%Y%m%d-%H%M%S"
}

# Export SurrealDB
def export-database [
    surreal_url: string
    surreal_user: string
    surreal_pass: string
    output_file: string
]: nothing -> record {
    print $"Exporting database from [$surreal_url]..."

    let result = do {
        ^surreal export \
            --conn $surreal_url \
            --user $surreal_user \
            --pass $surreal_pass \
            --output $output_file
    } | complete

    if ($result.exit_code == 0) {
        {
            success: true
            file: $output_file
            timestamp: (get-timestamp)
            error: null
        }
    } else {
        {
            success: false
            file: $output_file
            timestamp: (get-timestamp)
            error: ($result.stderr | str trim)
        }
    }
}

# Compress backup
def compress-backup [input_file: string]: nothing -> record {
    print $"Compressing [$input_file]..."

    let compressed = $"($input_file).gz"
    let result = do {
        ^gzip --force $input_file
    } | complete

    if ($result.exit_code == 0) {
        {
            success: true
            original: $input_file
            compressed: $compressed
            error: null
        }
    } else {
        {
            success: false
            original: $input_file
            compressed: $compressed
            error: ($result.stderr | str trim)
        }
    }
}

# Encrypt with AES-256
def encrypt-backup [
    input_file: string
    key_file: string
]: nothing -> record {
    print $"Encrypting [$input_file]..."

    let encrypted = $"($input_file).enc"
    let result = do {
        ^openssl enc -aes-256-cbc \
            -in $input_file \
            -out $encrypted \
            -pass file:$key_file
    } | complete

    if ($result.exit_code == 0) {
        {
            success: true
            encrypted_file: $encrypted
            error: null
        }
    } else {
        {
            success: false
            encrypted_file: $encrypted
            error: ($result.stderr | str trim)
        }
    }
}

# Upload to S3
def upload-to-s3 [
    file_path: string
    s3_bucket: string
    s3_prefix: string
]: nothing -> record {
    print $"Uploading to S3 [$s3_bucket]..."

    let s3_key = $"($s3_prefix)/database-$(get-timestamp).sql.gz.enc"
    let result = do {
        ^aws s3 cp $file_path \
            $"s3://($s3_bucket)/($s3_key)" \
            --sse AES256 \
            --metadata $"backup-type=database,timestamp=$(get-timestamp)"
    } | complete

    if ($result.exit_code == 0) {
        {
            success: true
            s3_location: $"s3://($s3_bucket)/($s3_key)"
            timestamp: (get-timestamp)
            error: null
        }
    } else {
        {
            success: false
            s3_location: $"s3://($s3_bucket)/($s3_key)"
            error: ($result.stderr | str trim)
        }
    }
}

# Verify S3 backup exists
def verify-backup [s3_location: string]: nothing -> record {
    print $"Verifying backup [$s3_location]..."

    let result = do {
        ^aws s3 ls $s3_location --human-readable
    } | complete

    if ($result.exit_code == 0) {
        {
            success: true
            location: $s3_location
            size_info: ($result.stdout | str trim)
            error: null
        }
    } else {
        {
            success: false
            location: $s3_location
            error: ($result.stderr | str trim)
        }
    }
}

# Cleanup temporary files
def cleanup-temp-files [temp_dir: string]: nothing -> record {
    print $"Cleaning up [$temp_dir]..."

    let result = do {
        ^rm -rf $temp_dir
    } | complete

    if ($result.exit_code == 0) {
        {
            success: true
            removed: $temp_dir
            error: null
        }
    } else {
        {
            success: false
            removed: $temp_dir
            error: ($result.stderr | str trim)
        }
    }
}

# Main backup procedure
def main [
    --surreal-url: string = "ws://localhost:8000"
    --surreal-user: string = "root"
    --surreal-pass: string = ""
    --s3-bucket: string = ""
    --s3-prefix: string = "backups/database"
    --encryption-key: string = ""
    --work-dir: string = "/tmp/vapora-backups"
]: nothing {
    print "=== VAPORA Database Backup (S3) ==="
    print ""

    if ($s3_bucket == "") {
        print "ERROR: --s3-bucket is required"
        exit 1
    }

    if ($surreal_pass == "") {
        print "ERROR: --surreal-pass is required"
        exit 1
    }

    if ($encryption_key == "") {
        print "ERROR: --encryption-key is required"
        exit 1
    }

    # Create work directory
    let work_path = $"($work_dir)/$(get-timestamp)"
    let create_result = do {
        ^mkdir -p $work_path
    } | complete

    if (not ($create_result.exit_code == 0)) {
        print "ERROR: Failed to create work directory"
        exit 1
    }

    # Export database
    let backup_file = $"($work_path)/vapora-db.sql"
    let export_result = (export-database $surreal_url $surreal_user $surreal_pass $backup_file)

    if (not $export_result.success) {
        print $"ERROR: Database export failed: ($export_result.error)"
        cleanup-temp-files $work_path
        exit 1
    }

    print "✓ Database exported successfully"

    # Compress
    let compress_result = (compress-backup $backup_file)

    if (not $compress_result.success) {
        print $"ERROR: Compression failed: ($compress_result.error)"
        cleanup-temp-files $work_path
        exit 1
    }

    print "✓ Backup compressed"

    # Encrypt
    let encrypt_result = (encrypt-backup $compress_result.compressed $encryption_key)

    if (not $encrypt_result.success) {
        print $"ERROR: Encryption failed: ($encrypt_result.error)"
        cleanup-temp-files $work_path
        exit 1
    }

    print "✓ Backup encrypted"

    # Upload to S3
    let upload_result = (upload-to-s3 $encrypt_result.encrypted_file $s3_bucket $s3_prefix)

    if (not $upload_result.success) {
        print $"ERROR: S3 upload failed: ($upload_result.error)"
        cleanup-temp-files $work_path
        exit 1
    }

    print "✓ Backup uploaded to S3"

    # Verify
    let verify_result = (verify-backup $upload_result.s3_location)

    if (not $verify_result.success) {
        print $"ERROR: Backup verification failed: ($verify_result.error)"
        cleanup-temp-files $work_path
        exit 1
    }

    print "✓ Backup verified"

    # Cleanup
    cleanup-temp-files $work_path

    # Summary
    print ""
    print "=== Backup Complete ==="
    print $"Location: [$upload_result.s3_location]"
    print $"Size: [$verify_result.size_info]"
    print $"Timestamp: [$(get-timestamp)]"
}
