#!/bin/bash

# Production Backup Script
# Automated backup for database, Vault, and critical files
#
# Usage:
#   ./scripts/backup.sh [--full|--database-only|--vault-only] [--encrypt]
#
# Options:
#   --full           Full backup (database + vault + files)
#   --database-only  Database backup only
#   --vault-only     Vault backup only
#   --encrypt        Encrypt backup files with GPG

set -euo pipefail

PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
BACKUP_DIR="${PROJECT_ROOT}/../backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_PATH="${BACKUP_DIR}/${TIMESTAMP}"

# Default options
BACKUP_TYPE="full"
ENCRYPT=false

# Parse arguments
for arg in "$@"; do
    case $arg in
        --full)
            BACKUP_TYPE="full"
            ;;
        --database-only)
            BACKUP_TYPE="database"
            ;;
        --vault-only)
            BACKUP_TYPE="vault"
            ;;
        --encrypt)
            ENCRYPT=true
            ;;
    esac
done

# Colors
GREEN="\e[32m"
YELLOW="\e[33m"
RED="\e[31m"
BLUE="\e[34m"
RESET="\e[0m"

# Logging functions
log() {
    echo -e "${BLUE}[$(date +'%H:%M:%S')]${RESET} $1"
}

success() {
    echo -e "${GREEN}✅ $1${RESET}"
}

warning() {
    echo -e "${YELLOW}⚠️  $1${RESET}"
}

error() {
    echo -e "${RED}❌ $1${RESET}"
    exit 1
}

# Create backup directory
prepare_backup_dir() {
    log "Preparing backup directory..."

    mkdir -p "$BACKUP_PATH"
    success "Backup directory created: $BACKUP_PATH"
}

# Backup database
backup_database() {
    log "Backing up database..."

    cd "$PROJECT_ROOT"

    # Check if database is running
    if ! docker compose ps db | grep -q "Up"; then
        error "Database container is not running"
    fi

    # Dump database
    local db_backup="${BACKUP_PATH}/database.sql"

    if docker compose exec -T db pg_dump -U postgres michaelschiemer_prod > "$db_backup"; then
        # Compress
        gzip -f "$db_backup"
        local size=$(du -h "${db_backup}.gz" | cut -f1)

        success "Database backup created: database.sql.gz ($size)"

        # Encrypt if requested
        if [[ "$ENCRYPT" == "true" ]]; then
            encrypt_file "${db_backup}.gz"
        fi
    else
        error "Database backup failed"
    fi
}

# Backup Vault secrets
backup_vault() {
    log "Backing up Vault secrets..."

    cd "$PROJECT_ROOT"

    local vault_backup="${BACKUP_PATH}/vault_secrets.sql"

    # Export Vault tables
    if docker compose exec -T db pg_dump -U postgres michaelschiemer_prod \
        -t vault_secrets -t vault_audit > "$vault_backup"; then

        # Compress
        gzip -f "$vault_backup"
        local size=$(du -h "${vault_backup}.gz" | cut -f1)

        success "Vault backup created: vault_secrets.sql.gz ($size)"

        # Encrypt (recommended for Vault backups)
        if [[ "$ENCRYPT" == "true" ]]; then
            encrypt_file "${vault_backup}.gz"
        else
            warning "Vault backup is not encrypted - consider using --encrypt"
        fi
    else
        error "Vault backup failed"
    fi
}

# Backup environment configuration
backup_environment() {
    log "Backing up environment configuration..."

    if [[ -f "$PROJECT_ROOT/.env.production" ]]; then
        cp "$PROJECT_ROOT/.env.production" "${BACKUP_PATH}/env.production"
        success "Environment configuration backed up"

        if [[ "$ENCRYPT" == "true" ]]; then
            encrypt_file "${BACKUP_PATH}/env.production"
        fi
    else
        warning ".env.production not found"
    fi
}

# Backup storage directory
backup_storage() {
    log "Backing up storage directory..."

    if [[ -d "$PROJECT_ROOT/storage" ]]; then
        local storage_backup="${BACKUP_PATH}/storage.tar.gz"

        tar -czf "$storage_backup" -C "$PROJECT_ROOT" storage

        local size=$(du -h "$storage_backup" | cut -f1)
        success "Storage backup created: storage.tar.gz ($size)"

        if [[ "$ENCRYPT" == "true" ]]; then
            encrypt_file "$storage_backup"
        fi
    else
        warning "Storage directory not found"
    fi
}

# Backup uploaded files
backup_uploads() {
    log "Backing up uploaded files..."

    if [[ -d "$PROJECT_ROOT/public/uploads" ]]; then
        local uploads_backup="${BACKUP_PATH}/uploads.tar.gz"

        tar -czf "$uploads_backup" -C "$PROJECT_ROOT/public" uploads

        local size=$(du -h "$uploads_backup" | cut -f1)
        success "Uploads backup created: uploads.tar.gz ($size)"

        if [[ "$ENCRYPT" == "true" ]]; then
            encrypt_file "$uploads_backup"
        fi
    else
        log "No uploads directory found (skipping)"
    fi
}

# Encrypt file with GPG
encrypt_file() {
    local file="$1"

    log "Encrypting $file..."

    # Check if GPG is available
    if ! command -v gpg &> /dev/null; then
        warning "GPG not installed - skipping encryption"
        return 1
    fi

    # Encrypt with symmetric encryption (password-based)
    if gpg --symmetric --cipher-algo AES256 "$file"; then
        rm -f "$file"  # Remove unencrypted file
        success "File encrypted: ${file}.gpg"
    else
        error "Encryption failed"
    fi
}

# Create backup manifest
create_manifest() {
    log "Creating backup manifest..."

    local manifest="${BACKUP_PATH}/MANIFEST.txt"

    {
        echo "Backup Manifest"
        echo "==============="
        echo ""
        echo "Timestamp: $(date -Iseconds)"
        echo "Backup Type: $BACKUP_TYPE"
        echo "Encrypted: $ENCRYPT"
        echo ""
        echo "Contents:"
        echo ""
        find "$BACKUP_PATH" -type f -exec du -h {} \; | sort -rh
        echo ""
        echo "Total Size: $(du -sh "$BACKUP_PATH" | cut -f1)"
    } > "$manifest"

    success "Backup manifest created"
}

# Cleanup old backups
cleanup_old_backups() {
    log "Cleaning up old backups..."

    # Keep last 7 days of backups
    find "$BACKUP_DIR" -maxdepth 1 -type d -name "20*" -mtime +7 -exec rm -rf {} \;

    success "Old backups cleaned up (kept last 7 days)"
}

# Verify backup integrity
verify_backup() {
    log "Verifying backup integrity..."

    local all_valid=true

    # Verify gzip files
    for file in "$BACKUP_PATH"/*.gz; do
        if [[ -f "$file" ]]; then
            if gzip -t "$file" 2>/dev/null; then
                log "✓ $file is valid"
            else
                error "✗ $file is corrupted"
                all_valid=false
            fi
        fi
    done

    # Verify tar.gz files
    for file in "$BACKUP_PATH"/*.tar.gz; do
        if [[ -f "$file" ]]; then
            if tar -tzf "$file" &>/dev/null; then
                log "✓ $file is valid"
            else
                error "✗ $file is corrupted"
                all_valid=false
            fi
        fi
    done

    if [[ "$all_valid" == "true" ]]; then
        success "All backup files verified successfully"
    else
        error "Some backup files are corrupted"
    fi
}

# Display backup summary
display_summary() {
    echo ""
    echo -e "${GREEN}========================================${RESET}"
    echo -e "${GREEN}   Backup Summary${RESET}"
    echo -e "${GREEN}========================================${RESET}"
    echo ""
    echo "📋 Backup Type: $BACKUP_TYPE"
    echo "⏰ Timestamp: $(date)"
    echo "📁 Location: $BACKUP_PATH"
    echo "🔒 Encrypted: $ENCRYPT"
    echo ""
    echo "📦 Backup Contents:"
    echo ""
    find "$BACKUP_PATH" -type f -exec du -h {} \; | sort -rh | head -10
    echo ""
    echo "💾 Total Size: $(du -sh "$BACKUP_PATH" | cut -f1)"
    echo ""
    echo "📝 Restoration Commands:"
    echo ""

    if [[ -f "${BACKUP_PATH}/database.sql.gz" ]]; then
        echo "  Database:"
        echo "    gunzip -c database.sql.gz | docker compose exec -T db psql -U postgres michaelschiemer_prod"
        echo ""
    fi

    if [[ -f "${BACKUP_PATH}/vault_secrets.sql.gz" ]]; then
        echo "  Vault:"
        echo "    gunzip -c vault_secrets.sql.gz | docker compose exec -T db psql -U postgres michaelschiemer_prod"
        echo ""
    fi

    if [[ -f "${BACKUP_PATH}/storage.tar.gz" ]]; then
        echo "  Storage:"
        echo "    tar -xzf storage.tar.gz -C /path/to/project"
        echo ""
    fi

    echo -e "${GREEN}========================================${RESET}"
}

# Main backup execution
main() {
    log "🔐 Starting production backup (type: $BACKUP_TYPE)..."
    echo ""

    prepare_backup_dir

    case "$BACKUP_TYPE" in
        full)
            backup_database
            backup_vault
            backup_environment
            backup_storage
            backup_uploads
            ;;
        database)
            backup_database
            ;;
        vault)
            backup_vault
            ;;
    esac

    create_manifest
    verify_backup
    cleanup_old_backups
    display_summary

    success "🎉 Backup completed successfully!"
}

# Run main
main "$@"
