#!/bin/bash
# ROA2WEB Production Deployment Script
# Zero-downtime deployment with health checks and rollback capability

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/deploy.log"
MAX_RETRIES=3
HEALTH_CHECK_TIMEOUT=60

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

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

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

# Check if running as root
check_root() {
    if [[ $EUID -eq 0 ]]; then
        error_exit "This script should not be run as root for security reasons"
    fi
}

# Check prerequisites
check_prerequisites() {
    info "Checking prerequisites..."
    
    # Check if Docker is installed and running
    if ! command -v docker &> /dev/null; then
        error_exit "Docker is not installed"
    fi
    
    if ! docker info &> /dev/null; then
        error_exit "Docker daemon is not running"
    fi
    
    # Check if Docker Compose is installed
    if ! command -v docker-compose &> /dev/null; then
        error_exit "Docker Compose is not installed"
    fi
    
    # Check if required files exist
    if [[ ! -f "$PROJECT_DIR/.env.production" ]]; then
        error_exit "Production environment file (.env.production) not found"
    fi
    
    if [[ ! -f "$PROJECT_DIR/docker-compose.yml" ]]; then
        error_exit "Docker Compose file not found"
    fi
    
    if [[ ! -f "$PROJECT_DIR/docker-compose.production.yml" ]]; then
        error_exit "Production Docker Compose file not found"
    fi
    
    success "Prerequisites check passed"
}

# Create backup directory
create_backup_dir() {
    if [[ ! -d "$BACKUP_DIR" ]]; then
        mkdir -p "$BACKUP_DIR"
        info "Created backup directory: $BACKUP_DIR"
    fi
}

# Create backup of current deployment
create_backup() {
    info "Creating backup of current deployment..."
    
    local backup_name="backup_$(date +%Y%m%d_%H%M%S)"
    local backup_path="$BACKUP_DIR/$backup_name"
    
    # Create backup directory
    mkdir -p "$backup_path"
    
    # Backup Docker images
    info "Backing up Docker images..."
    docker save -o "$backup_path/images.tar" \
        roa2web/backend:latest \
        roa2web/frontend:latest \
        roa2web/nginx-gateway:latest 2>/dev/null || warning "Some images may not exist yet"
    
    # Backup configuration files
    cp -r "$PROJECT_DIR"/.env* "$backup_path/" 2>/dev/null || true
    cp -r "$PROJECT_DIR"/docker-compose*.yml "$backup_path/"
    cp -r "$PROJECT_DIR"/nginx/conf "$backup_path/" 2>/dev/null || true
    
    # Backup volumes data
    info "Backing up volume data..."
    docker run --rm -v roa2web_nginx-logs:/data -v "$backup_path":/backup alpine tar czf /backup/nginx-logs.tar.gz -C /data . 2>/dev/null || warning "Nginx logs backup failed"
    docker run --rm -v roa2web_ssl-certs:/data -v "$backup_path":/backup alpine tar czf /backup/ssl-certs.tar.gz -C /data . 2>/dev/null || warning "SSL certs backup failed"
    docker run --rm -v roa2web_redis-data:/data -v "$backup_path":/backup alpine tar czf /backup/redis-data.tar.gz -C /data . 2>/dev/null || warning "Redis data backup failed"
    
    echo "$backup_name" > "$PROJECT_DIR/.last_backup"
    success "Backup created: $backup_name"
}

# Health check function
health_check() {
    local service=$1
    local url=$2
    local timeout=${3:-30}
    
    info "Performing health check for $service..."
    
    local count=0
    while [[ $count -lt $timeout ]]; do
        if curl -f -s "$url" > /dev/null 2>&1; then
            success "$service health check passed"
            return 0
        fi
        
        sleep 1
        ((count++))
    done
    
    error_exit "$service health check failed after ${timeout}s"
}

# Wait for services to be healthy
wait_for_services() {
    info "Waiting for services to be healthy..."
    
    # Wait for containers to be running
    sleep 10
    
    # Check backend health
    health_check "Backend API" "http://localhost/api/health" $HEALTH_CHECK_TIMEOUT
    
    # Check frontend health  
    health_check "Frontend" "http://localhost/health" $HEALTH_CHECK_TIMEOUT
    
    # Check gateway health
    health_check "Gateway" "http://localhost/health" $HEALTH_CHECK_TIMEOUT
    
    success "All services are healthy"
}

# Deploy function
deploy() {
    info "Starting deployment..."
    
    cd "$PROJECT_DIR"
    
    # Load production environment
    set -a
    source .env.production
    set +a
    
    # Build images
    info "Building Docker images..."
    docker-compose -f docker-compose.yml -f docker-compose.production.yml build --no-cache
    
    # Pull any updated base images
    info "Pulling base images..."
    docker-compose -f docker-compose.yml -f docker-compose.production.yml pull
    
    # Deploy with zero downtime
    info "Deploying services..."
    docker-compose -f docker-compose.yml -f docker-compose.production.yml up -d --force-recreate
    
    # Wait for services to be ready
    wait_for_services
    
    # Clean up old images
    info "Cleaning up old images..."
    docker image prune -f
    
    success "Deployment completed successfully!"
}

# Rollback function
rollback() {
    local backup_name=$1
    
    if [[ -z "$backup_name" ]]; then
        if [[ -f "$PROJECT_DIR/.last_backup" ]]; then
            backup_name=$(cat "$PROJECT_DIR/.last_backup")
        else
            error_exit "No backup specified and no last backup found"
        fi
    fi
    
    local backup_path="$BACKUP_DIR/$backup_name"
    
    if [[ ! -d "$backup_path" ]]; then
        error_exit "Backup not found: $backup_name"
    fi
    
    warning "Rolling back to backup: $backup_name"
    
    # Stop current services
    docker-compose -f docker-compose.yml -f docker-compose.production.yml down
    
    # Restore images
    if [[ -f "$backup_path/images.tar" ]]; then
        docker load -i "$backup_path/images.tar"
    fi
    
    # Restore configuration
    cp "$backup_path"/.env* "$PROJECT_DIR/"
    
    # Start services
    docker-compose -f docker-compose.yml -f docker-compose.production.yml up -d
    
    # Wait for services
    wait_for_services
    
    success "Rollback completed successfully!"
}

# Main deployment workflow
main() {
    local action=${1:-deploy}
    
    case $action in
        "deploy")
            info "=== ROA2WEB Production Deployment ==="
            check_root
            check_prerequisites
            create_backup_dir
            create_backup
            deploy
            ;;
        "rollback")
            info "=== ROA2WEB Rollback ==="
            check_root
            rollback "$2"
            ;;
        "health-check")
            info "=== ROA2WEB Health Check ==="
            wait_for_services
            ;;
        *)
            echo "Usage: $0 {deploy|rollback [backup_name]|health-check}"
            echo ""
            echo "Commands:"
            echo "  deploy       - Deploy the application to production"
            echo "  rollback     - Rollback to the last backup or specified backup"
            echo "  health-check - Perform health check on running services"
            exit 1
            ;;
    esac
}

# Run main function with all arguments
main "$@"