#!/bin/bash
# ROA2WEB Database and Application Backup Script
# Creates backups of Oracle database, Docker volumes, and configuration

set -e

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
BACKUP_DIR="$PROJECT_DIR/backups"
LOG_FILE="$PROJECT_DIR/backup.log"
RETENTION_DAYS=30
MAX_BACKUPS=10

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

# Logging function
log() {
    local level=$1
    shift
    local message="$*"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo -e "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
}

# Error handling
error_exit() {
    log "ERROR" "$1"
    exit 1
}

# Success message
success() {
    log "SUCCESS" "$1"
}

# Info message
info() {
    log "INFO" "$1"
}

# Warning message
warning() {
    log "WARNING" "$1"
}

# Load environment variables
load_env() {
    if [[ -f "$PROJECT_DIR/.env" ]]; then
        set -a
        source "$PROJECT_DIR/.env"
        set +a
    elif [[ -f "$PROJECT_DIR/.env.production" ]]; then
        set -a
        source "$PROJECT_DIR/.env.production"
        set +a
    else
        error_exit "No environment file found"
    fi
}

# Create backup directory structure
create_backup_structure() {
    local backup_name=$1
    local backup_path="$BACKUP_DIR/$backup_name"
    
    mkdir -p "$backup_path"/{database,volumes,config,logs}
    echo "$backup_path"
}

# Backup Oracle database
backup_database() {
    local backup_path=$1
    
    info "Starting Oracle database backup..."
    
    # Check if SSH tunnel is required
    if [[ "$ORACLE_HOST" == "localhost" && -f "$PROJECT_DIR/ssh-tunnel-prod.sh" ]]; then
        info "Ensuring SSH tunnel is running..."
        "$PROJECT_DIR/ssh-tunnel-prod.sh" status || "$PROJECT_DIR/ssh-tunnel-prod.sh" start
    fi
    
    # Create database backup using Oracle export
    local db_backup_file="$backup_path/database/roa_backup_$(date +%Y%m%d_%H%M%S).dmp"
    local log_file="$backup_path/database/export.log"
    
    # Export specific schemas (adjust as needed)
    if command -v expdp &> /dev/null; then
        info "Using Oracle Data Pump for backup..."
        expdp \
            userid="$ORACLE_USER/$ORACLE_PASSWORD@$ORACLE_HOST:$ORACLE_PORT/$ORACLE_SID" \
            schemas="$ORACLE_USER" \
            dumpfile="$(basename "$db_backup_file")" \
            logfile="$(basename "$log_file")" \
            directory=DATA_PUMP_DIR \
            compression=ALL &> /dev/null || warning "Data Pump backup failed, trying alternative method"
    fi
    
    # Alternative: SQL backup for essential data
    if [[ ! -f "$db_backup_file" ]]; then
        info "Creating SQL backup of essential tables..."
        cat > "$backup_path/database/backup.sql" << EOF
-- ROA2WEB Database Backup $(date)
-- Essential tables backup

-- Users table
CREATE TABLE users_backup AS SELECT * FROM users;

-- Companies table  
CREATE TABLE companies_backup AS SELECT * FROM companies;

-- Invoices table
CREATE TABLE invoices_backup AS SELECT * FROM invoices;

-- Payments table
CREATE TABLE payments_backup AS SELECT * FROM payments;

-- Authentication tokens (structure only for security)
CREATE TABLE auth_tokens_backup AS SELECT user_id, created_at, expires_at FROM auth_tokens WHERE 1=0;

COMMIT;
EOF
        
        # Execute SQL backup if sqlplus is available
        if command -v sqlplus &> /dev/null; then
            sqlplus -s "$ORACLE_USER/$ORACLE_PASSWORD@$ORACLE_HOST:$ORACLE_PORT/$ORACLE_SID" @"$backup_path/database/backup.sql" > "$backup_path/database/backup_output.log" 2>&1 || warning "SQL backup failed"
        fi
    fi
    
    success "Database backup completed"
}

# Backup Docker volumes
backup_volumes() {
    local backup_path=$1
    
    info "Backing up Docker volumes..."
    
    # Backup nginx logs
    if docker volume ls | grep -q "roa2web_nginx-logs"; then
        info "Backing up nginx logs..."
        docker run --rm \
            -v roa2web_nginx-logs:/data:ro \
            -v "$backup_path/volumes":/backup \
            alpine tar czf /backup/nginx-logs.tar.gz -C /data . 2>/dev/null || warning "Nginx logs backup failed"
    fi
    
    # Backup SSL certificates
    if docker volume ls | grep -q "roa2web_ssl-certs"; then
        info "Backing up SSL certificates..."
        docker run --rm \
            -v roa2web_ssl-certs:/data:ro \
            -v "$backup_path/volumes":/backup \
            alpine tar czf /backup/ssl-certs.tar.gz -C /data . 2>/dev/null || warning "SSL certs backup failed"
    fi
    
    # Backup Redis data
    if docker volume ls | grep -q "roa2web_redis-data"; then
        info "Backing up Redis data..."
        docker run --rm \
            -v roa2web_redis-data:/data:ro \
            -v "$backup_path/volumes":/backup \
            alpine tar czf /backup/redis-data.tar.gz -C /data . 2>/dev/null || warning "Redis data backup failed"
    fi
    
    # Backup backend logs
    if docker volume ls | grep -q "roa2web_backend-logs"; then
        info "Backing up backend logs..."
        docker run --rm \
            -v roa2web_backend-logs:/data:ro \
            -v "$backup_path/volumes":/backup \
            alpine tar czf /backup/backend-logs.tar.gz -C /data . 2>/dev/null || warning "Backend logs backup failed"
    fi
    
    success "Docker volumes backup completed"
}

# Backup configuration files
backup_config() {
    local backup_path=$1
    
    info "Backing up configuration files..."
    
    # Copy environment files
    cp -r "$PROJECT_DIR"/.env* "$backup_path/config/" 2>/dev/null || true
    
    # Copy Docker Compose files
    cp "$PROJECT_DIR"/docker-compose*.yml "$backup_path/config/"
    
    # Copy nginx configuration
    if [[ -d "$PROJECT_DIR/nginx/conf" ]]; then
        cp -r "$PROJECT_DIR/nginx/conf" "$backup_path/config/"
    fi
    
    # Copy SSL configuration (if exists)
    if [[ -d "$PROJECT_DIR/nginx/ssl" ]]; then
        cp -r "$PROJECT_DIR/nginx/ssl" "$backup_path/config/" 2>/dev/null || true
    fi
    
    # Copy deployment scripts
    if [[ -d "$PROJECT_DIR/scripts" ]]; then
        cp -r "$PROJECT_DIR/scripts" "$backup_path/config/"
    fi
    
    # Create backup metadata
    cat > "$backup_path/backup_info.txt" << EOF
ROA2WEB Backup Information
=========================
Backup Date: $(date)
Backup Type: Full Backup
Environment: ${ENVIRONMENT:-unknown}
Oracle Host: ${ORACLE_HOST:-unknown}
Oracle User: ${ORACLE_USER:-unknown}
Git Commit: $(git rev-parse HEAD 2>/dev/null || echo "unknown")
Git Branch: $(git branch --show-current 2>/dev/null || echo "unknown")
Docker Images:
$(docker images --format "table {{.Repository}}:{{.Tag}}\t{{.CreatedAt}}\t{{.Size}}" | grep roa2web || echo "No ROA2WEB images found")
EOF
    
    success "Configuration backup completed"
}

# Clean old backups
cleanup_old_backups() {
    info "Cleaning up old backups..."
    
    # Remove backups older than retention period
    find "$BACKUP_DIR" -name "backup_*" -type d -mtime +$RETENTION_DAYS -exec rm -rf {} \; 2>/dev/null || true
    
    # Keep only the latest MAX_BACKUPS
    local backup_count=$(find "$BACKUP_DIR" -name "backup_*" -type d | wc -l)
    if [[ $backup_count -gt $MAX_BACKUPS ]]; then
        local excess=$((backup_count - MAX_BACKUPS))
        find "$BACKUP_DIR" -name "backup_*" -type d -printf '%T+ %p\n' | sort | head -n $excess | cut -d' ' -f2- | xargs rm -rf
        info "Removed $excess old backups"
    fi
    
    success "Backup cleanup completed"
}

# List available backups
list_backups() {
    info "Available backups:"
    echo ""
    
    if [[ ! -d "$BACKUP_DIR" ]] || [[ -z "$(ls -A "$BACKUP_DIR" 2>/dev/null)" ]]; then
        warning "No backups found"
        return
    fi
    
    find "$BACKUP_DIR" -name "backup_*" -type d -printf '%T+ %p\n' | sort -r | while read -r line; do
        local date_part=$(echo "$line" | cut -d' ' -f1 | cut -d+ -f1)
        local backup_name=$(basename "$(echo "$line" | cut -d' ' -f2)")
        local backup_path="$(echo "$line" | cut -d' ' -f2)"
        
        echo "📦 $backup_name ($date_part)"
        
        if [[ -f "$backup_path/backup_info.txt" ]]; then
            grep -E "(Backup Date|Environment|Git)" "$backup_path/backup_info.txt" | sed 's/^/   /'
        fi
        echo ""
    done
}

# Restore from backup
restore_backup() {
    local backup_name=$1
    
    if [[ -z "$backup_name" ]]; then
        error_exit "Backup name is required for restore operation"
    fi
    
    local backup_path="$BACKUP_DIR/$backup_name"
    
    if [[ ! -d "$backup_path" ]]; then
        error_exit "Backup not found: $backup_name"
    fi
    
    warning "Restoring from backup: $backup_name"
    warning "This will overwrite current data. Press Ctrl+C to cancel or wait 10 seconds to continue..."
    sleep 10
    
    info "Starting restore process..."
    
    # Stop services
    docker-compose -f "$PROJECT_DIR/docker-compose.yml" -f "$PROJECT_DIR/docker-compose.production.yml" down 2>/dev/null || true
    
    # Restore configuration
    if [[ -d "$backup_path/config" ]]; then
        info "Restoring configuration files..."
        cp -r "$backup_path/config"/.env* "$PROJECT_DIR/" 2>/dev/null || true
        cp -r "$backup_path/config"/docker-compose*.yml "$PROJECT_DIR/"
        
        if [[ -d "$backup_path/config/conf" ]]; then
            mkdir -p "$PROJECT_DIR/nginx"
            cp -r "$backup_path/config/conf" "$PROJECT_DIR/nginx/"
        fi
    fi
    
    # Restore volumes
    if [[ -d "$backup_path/volumes" ]]; then
        info "Restoring Docker volumes..."
        
        for volume_backup in "$backup_path/volumes"/*.tar.gz; do
            if [[ -f "$volume_backup" ]]; then
                local volume_name=$(basename "$volume_backup" .tar.gz)
                docker volume create "roa2web_$volume_name" 2>/dev/null || true
                docker run --rm \
                    -v "roa2web_$volume_name":/data \
                    -v "$backup_path/volumes":/backup \
                    alpine tar xzf "/backup/$(basename "$volume_backup")" -C /data
                info "Restored volume: $volume_name"
            fi
        done
    fi
    
    success "Restore completed. Please restart services manually."
}

# Main function
main() {
    local action=${1:-backup}
    
    case $action in
        "backup"|"full")
            info "=== ROA2WEB Full Backup ==="
            load_env
            
            local backup_name="backup_$(date +%Y%m%d_%H%M%S)"
            local backup_path=$(create_backup_structure "$backup_name")
            
            mkdir -p "$BACKUP_DIR"
            
            backup_database "$backup_path"
            backup_volumes "$backup_path"
            backup_config "$backup_path"
            cleanup_old_backups
            
            success "Full backup completed: $backup_name"
            ;;
        "database"|"db")
            info "=== ROA2WEB Database Backup ==="
            load_env
            
            local backup_name="db_backup_$(date +%Y%m%d_%H%M%S)"
            local backup_path=$(create_backup_structure "$backup_name")
            
            backup_database "$backup_path"
            success "Database backup completed: $backup_name"
            ;;
        "volumes")
            info "=== ROA2WEB Volumes Backup ==="
            
            local backup_name="volumes_backup_$(date +%Y%m%d_%H%M%S)"
            local backup_path=$(create_backup_structure "$backup_name")
            
            backup_volumes "$backup_path"
            success "Volumes backup completed: $backup_name"
            ;;
        "list")
            list_backups
            ;;
        "restore")
            restore_backup "$2"
            ;;
        "cleanup")
            cleanup_old_backups
            ;;
        *)
            echo "Usage: $0 {backup|database|volumes|list|restore <backup_name>|cleanup}"
            echo ""
            echo "Commands:"
            echo "  backup|full  - Create full backup (database + volumes + config)"
            echo "  database|db  - Backup only Oracle database"
            echo "  volumes      - Backup only Docker volumes"
            echo "  list         - List available backups"
            echo "  restore      - Restore from backup"
            echo "  cleanup      - Clean up old backups"
            exit 1
            ;;
    esac
}

# Run main function
main "$@"