#!/bin/bash

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

# Configuration
ENVIRONMENT=${1:-production}
COMPOSE_FILE="docker-compose.production.yml"
BACKUP_DIR="./backups/$(date +%Y%m%d_%H%M%S)"
ROLLBACK_DIR="./rollback-backups"
MAX_BACKUPS=10

# Function to print colored messages
print_info() {
    echo -e "${BLUE}ℹ️  $1${NC}"
}

print_success() {
    echo -e "${GREEN}✅ $1${NC}"
}

print_warning() {
    echo -e "${YELLOW}⚠️  $1${NC}"
}

print_error() {
    echo -e "${RED}❌ $1${NC}"
}

# Function to check prerequisites
check_prerequisites() {
    print_info "Checking prerequisites..."
    
    command -v docker >/dev/null 2>&1 || { 
        print_error "Docker is required but not installed. Aborting."; 
        exit 1; 
    }
    
    command -v docker-compose >/dev/null 2>&1 || { 
        print_error "Docker Compose is required but not installed. Aborting."; 
        exit 1; 
    }
    
    if ! docker info >/dev/null 2>&1; then
        print_error "Docker daemon is not running. Please start Docker and try again.";
        exit 1;
    fi
    
    if [ ! -f "$COMPOSE_FILE" ]; then
        print_error "$COMPOSE_FILE not found. Aborting.";
        exit 1;
    fi
    
    print_success "Prerequisites check passed"
}

# Function to create backup
create_backup() {
    print_info "Creating backup..."
    
    mkdir -p "${BACKUP_DIR}"
    mkdir -p "${ROLLBACK_DIR}"
    
    # Backup database
    print_info "Backing up database..."
    if docker-compose -f "$COMPOSE_FILE" ps postgres | grep -q "Up"; then
        docker-compose -f "$COMPOSE_FILE" exec -T postgres pg_dump -U "${POSTGRES_USER:-veza_user}" "${POSTGRES_DB:-veza_db}" > "${BACKUP_DIR}/database.sql" 2>/dev/null || {
            print_warning "Database backup failed (may not be critical if database is empty)"
        }
    else
        print_warning "PostgreSQL container is not running, skipping database backup"
    fi
    
    # Backup Redis data
    print_info "Backing up Redis data..."
    if docker-compose -f "$COMPOSE_FILE" ps redis | grep -q "Up"; then
        docker-compose -f "$COMPOSE_FILE" exec -T redis redis-cli --rdb - > "${BACKUP_DIR}/redis.rdb" 2>/dev/null || {
            print_warning "Redis backup failed (may not be critical)"
        }
    else
        print_warning "Redis container is not running, skipping Redis backup"
    fi
    
    # Save current image tags
    print_info "Saving current image tags..."
    docker-compose -f "$COMPOSE_FILE" config | grep "image:" > "${BACKUP_DIR}/image-tags.txt" || true
    
    # Copy current docker-compose file
    cp "$COMPOSE_FILE" "${BACKUP_DIR}/docker-compose.production.yml"
    
    # Create rollback backup
    cp -r "${BACKUP_DIR}" "${ROLLBACK_DIR}/latest"
    
    print_success "Backup created at ${BACKUP_DIR}"
}

# Function to cleanup old backups
cleanup_old_backups() {
    print_info "Cleaning up old backups (keeping last ${MAX_BACKUPS})..."
    
    if [ -d "./backups" ]; then
        cd ./backups
        ls -t | tail -n +$((MAX_BACKUPS + 1)) | xargs rm -rf 2>/dev/null || true
        cd ..
    fi
    
    print_success "Old backups cleaned up"
}

# Function to pull latest images
pull_latest_images() {
    print_info "Pulling latest images..."
    
    docker-compose -f "$COMPOSE_FILE" pull || {
        print_error "Failed to pull images";
        exit 1;
    }
    
    print_success "Images pulled successfully"
}

# Function to deploy services
deploy_services() {
    print_info "Deploying services with zero-downtime strategy..."
    
    # Deploy services one by one to minimize downtime
    SERVICES=("backend-api" "chat-server" "stream-server" "frontend")
    
    for service in "${SERVICES[@]}"; do
        if docker-compose -f "$COMPOSE_FILE" ps "$service" | grep -q "Up"; then
            print_info "Updating ${service}..."
            docker-compose -f "$COMPOSE_FILE" up -d --no-deps "$service" || {
                print_error "Failed to deploy ${service}";
                return 1;
            }
            sleep 5
        fi
    done
    
    print_success "Services deployed successfully"
}

# Function to check health
check_health() {
    local service=$1
    local url=$2
    local name=$3
    local max_attempts=${4:-30}
    local attempt=0
    
    print_info "Checking ${name} health..."
    
    while [ $attempt -lt $max_attempts ]; do
        if curl -sf "$url" >/dev/null 2>&1; then
            print_success "${name} is healthy"
            return 0
        fi
        attempt=$((attempt + 1))
        sleep 2
    done
    
    print_error "${name} health check failed after ${max_attempts} attempts"
    return 1
}

# Function to verify deployment
verify_deployment() {
    print_info "Verifying deployment..."
    
    local failed=0
    
    # Check container status
    if docker-compose -f "$COMPOSE_FILE" ps | grep -q "unhealthy\|Exited\|Restarting"; then
        print_error "Some containers are unhealthy or stopped"
        docker-compose -f "$COMPOSE_FILE" ps
        failed=1
    fi
    
    # Check health endpoints
    check_health "backend-api" "http://localhost:8080/health" "Backend API" 15 || failed=1
    check_health "chat-server" "http://localhost:8081/health" "Chat Server" 15 || failed=1
    check_health "stream-server" "http://localhost:8082/health" "Stream Server" 15 || failed=1
    check_health "frontend" "http://localhost:80/health" "Frontend" 15 || failed=1
    
    if [ $failed -eq 1 ]; then
        return 1
    fi
    
    print_success "Deployment verification passed"
    return 0
}

# Function to rollback
rollback() {
    print_error "Deployment failed! Initiating rollback..."
    
    if [ ! -d "${ROLLBACK_DIR}/latest" ]; then
        print_error "No rollback backup found. Manual intervention required."
        exit 1
    fi
    
    print_info "Rolling back to previous version..."
    
    # Stop current services
    docker-compose -f "$COMPOSE_FILE" down || true
    
    # Restore docker-compose file
    if [ -f "${ROLLBACK_DIR}/latest/docker-compose.production.yml" ]; then
        cp "${ROLLBACK_DIR}/latest/docker-compose.production.yml" "$COMPOSE_FILE"
    fi
    
    # Restore database
    if [ -f "${ROLLBACK_DIR}/latest/database.sql" ]; then
        print_info "Restoring database..."
        docker-compose -f "$COMPOSE_FILE" up -d postgres
        sleep 10
        docker-compose -f "$COMPOSE_FILE" exec -T postgres psql -U "${POSTGRES_USER:-veza_user}" -d "${POSTGRES_DB:-veza_db}" < "${ROLLBACK_DIR}/latest/database.sql" || true
    fi
    
    # Start services with previous images
    docker-compose -f "$COMPOSE_FILE" up -d
    
    print_warning "Rollback completed. Please verify services manually."
    exit 1
}

# Main deployment flow
main() {
    print_info "Starting production deployment to ${ENVIRONMENT}..."
    
    # Trap errors and rollback
    trap rollback ERR
    
    check_prerequisites
    create_backup
    cleanup_old_backups
    pull_latest_images
    deploy_services
    
    # Wait for services to start
    print_info "Waiting for services to start..."
    sleep 30
    
    # Verify deployment
    if ! verify_deployment; then
        rollback
    fi
    
    # Disable trap on success
    trap - ERR
    
    print_success "Deployment to ${ENVIRONMENT} completed successfully!"
    print_info "Backup location: ${BACKUP_DIR}"
    print_info "To rollback, run: ${ROLLBACK_DIR}/latest"
}

# Run main function
main

