#!/bin/bash

# HDGL Multi-Chain Bridge - Production Deployment Script
# Usage: ./deploy.sh [environment] [action]
# Example: ./deploy.sh production deploy

set -euo pipefail  # Exit on error, undefined vars, pipe failures

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
ENVIRONMENT="${1:-staging}"
ACTION="${2:-deploy}"
DOCKER_COMPOSE_FILE="docker-compose.yml"
BACKUP_DIR="/var/backups/hdgl"
LOG_FILE="/var/log/hdgl/deploy.log"

# 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() {
    echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}" | tee -a "$LOG_FILE"
}

error() {
    echo -e "${RED}[ERROR] $1${NC}" | tee -a "$LOG_FILE" >&2
}

warn() {
    echo -e "${YELLOW}[WARN] $1${NC}" | tee -a "$LOG_FILE"
}

info() {
    echo -e "${BLUE}[INFO] $1${NC}" | tee -a "$LOG_FILE"
}

# Environment validation
validate_environment() {
    case $ENVIRONMENT in
        development|staging|production)
            log "Deploying to $ENVIRONMENT environment"
            ;;
        *)
            error "Invalid environment: $ENVIRONMENT. Use: development, staging, or production"
            exit 1
            ;;
    esac
}

# Prerequisites check
check_prerequisites() {
    log "Checking prerequisites..."
    
    # Check if running as root or with sudo
    if [[ $EUID -eq 0 ]]; then
        error "Don't run this script as root. Use a user with docker permissions."
        exit 1
    fi
    
    # Check Docker
    if ! command -v docker &> /dev/null; then
        error "Docker is not installed or not in PATH"
        exit 1
    fi
    
    # Check Docker Compose
    if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
        error "Docker Compose is not installed"
        exit 1
    fi
    
    # Check if user is in docker group
    if ! groups | grep -q docker; then
        error "User $USER is not in the docker group"
        exit 1
    fi
    
    # Check required files
    local required_files=(
        "$PROJECT_ROOT/hdgl_daemon.py"
        "$PROJECT_ROOT/hdgl_operators.py"
        "$PROJECT_ROOT/$DOCKER_COMPOSE_FILE"
        "$PROJECT_ROOT/config/hdgl_config.json"
    )
    
    for file in "${required_files[@]}"; do
        if [[ ! -f "$file" ]]; then
            error "Required file not found: $file"
            exit 1
        fi
    done
    
    log "Prerequisites check passed"
}

# Create directories
create_directories() {
    log "Creating necessary directories..."
    
    sudo mkdir -p \
        /var/log/hdgl \
        /var/lib/hdgl \
        $BACKUP_DIR \
        /etc/hdgl
    
    sudo chown -R $USER:$USER /var/log/hdgl /var/lib/hdgl $BACKUP_DIR /etc/hdgl
    
    mkdir -p \
        "$PROJECT_ROOT/logs" \
        "$PROJECT_ROOT/proofs" \
        "$PROJECT_ROOT/circuits/build" \
        "$PROJECT_ROOT/monitoring/grafana/dashboards" \
        "$PROJECT_ROOT/monitoring/grafana/datasources" \
        "$PROJECT_ROOT/nginx/ssl"
}

# Environment setup
setup_environment() {
    log "Setting up environment configuration..."
    
    # Copy environment-specific configuration
    local env_config="$PROJECT_ROOT/config/hdgl_config.$ENVIRONMENT.json"
    if [[ -f "$env_config" ]]; then
        cp "$env_config" "$PROJECT_ROOT/config/hdgl_config.json"
        log "Loaded $ENVIRONMENT configuration"
    else
        warn "Environment-specific config not found: $env_config"
    fi
    
    # Set environment variables
    export ENVIRONMENT
    export COMPOSE_PROJECT_NAME="hdgl-$ENVIRONMENT"
    export COMPOSE_FILE="$PROJECT_ROOT/$DOCKER_COMPOSE_FILE"
    
    # Load environment-specific overrides
    local env_override="$PROJECT_ROOT/docker-compose.$ENVIRONMENT.yml"
    if [[ -f "$env_override" ]]; then
        export COMPOSE_FILE="$COMPOSE_FILE:$env_override"
        log "Loaded environment override: $env_override"
    fi
}

# Backup existing data
backup_data() {
    if [[ "$ENVIRONMENT" == "production" ]]; then
        log "Creating backup of production data..."
        
        local backup_timestamp=$(date +%Y%m%d_%H%M%S)
        local backup_path="$BACKUP_DIR/hdgl_backup_$backup_timestamp"
        
        mkdir -p "$backup_path"
        
        # Backup Docker volumes
        docker run --rm \
            -v hdgl-${ENVIRONMENT}_redis-data:/data:ro \
            -v hdgl-${ENVIRONMENT}_prometheus-data:/prometheus:ro \
            -v hdgl-${ENVIRONMENT}_grafana-data:/grafana:ro \
            -v hdgl-${ENVIRONMENT}_elasticsearch-data:/elasticsearch:ro \
            -v "$backup_path:/backup" \
            busybox tar czf /backup/volumes_$backup_timestamp.tar.gz /data /prometheus /grafana /elasticsearch
        
        # Backup configuration
        cp -r "$PROJECT_ROOT/config" "$backup_path/"
        
        # Keep only last 5 backups
        cd "$BACKUP_DIR"
        ls -t hdgl_backup_* | tail -n +6 | xargs -r rm -rf
        
        log "Backup completed: $backup_path"
    fi
}

# Build images
build_images() {
    log "Building Docker images..."
    
    cd "$PROJECT_ROOT"
    
    # Build with BuildKit for better caching
    export DOCKER_BUILDKIT=1
    export COMPOSE_DOCKER_CLI_BUILD=1
    
    docker-compose build --parallel --pull
    
    # Tag images for environment
    docker tag hdgl_hdgl-daemon:latest hdgl_hdgl-daemon:$ENVIRONMENT
    
    log "Image build completed"
}

# Compile ZK circuits
compile_circuits() {
    log "Compiling ZK circuits..."
    
    cd "$PROJECT_ROOT/circuits"
    
    # Run circuit compilation container
    docker-compose run --rm circuit-compiler
    
    # Verify circuit artifacts
    local required_artifacts=(
        "hdgl_blending.r1cs"
        "hdgl_blending_js/hdgl_blending.wasm"
        "hdgl_blending_final.zkey"
        "verification_key.json"
    )
    
    for artifact in "${required_artifacts[@]}"; do
        if [[ ! -f "$artifact" ]]; then
            error "Circuit artifact missing: $artifact"
            exit 1
        fi
    done
    
    log "Circuit compilation completed"
}

# Generate SSL certificates
generate_ssl() {
    if [[ "$ENVIRONMENT" == "production" ]]; then
        log "Generating SSL certificates..."
        
        local ssl_dir="$PROJECT_ROOT/nginx/ssl"
        local domain="${HDGL_DOMAIN:-hdgl.local}"
        
        if [[ ! -f "$ssl_dir/fullchain.pem" ]] || [[ ! -f "$ssl_dir/privkey.pem" ]]; then
            # Generate self-signed certificates for development
            # In production, use Let's Encrypt or proper CA certificates
            openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
                -keyout "$ssl_dir/privkey.pem" \
                -out "$ssl_dir/fullchain.pem" \
                -subj "/C=US/ST=State/L=City/O=HDGL/CN=$domain"
            
            log "SSL certificates generated for $domain"
        else
            log "SSL certificates already exist"
        fi
    fi
}

# Start services
start_services() {
    log "Starting HDGL services..."
    
    cd "$PROJECT_ROOT"
    
    # Start infrastructure services first
    docker-compose up -d redis prometheus grafana elasticsearch
    
    # Wait for infrastructure to be ready
    log "Waiting for infrastructure services..."
    sleep 30
    
    # Start application services
    docker-compose up -d hdgl-daemon nginx fluentd kibana
    
    # Wait for services to be healthy
    log "Waiting for services to become healthy..."
    local max_attempts=60
    local attempt=0
    
    while [[ $attempt -lt $max_attempts ]]; do
        if docker-compose ps | grep -q "unhealthy"; then
            attempt=$((attempt + 1))
            sleep 5
        else
            break
        fi
    done
    
    if [[ $attempt -eq $max_attempts ]]; then
        error "Some services failed to become healthy"
        docker-compose ps
        exit 1
    fi
    
    log "All services started successfully"
}

# Stop services
stop_services() {
    log "Stopping HDGL services..."
    
    cd "$PROJECT_ROOT"
    docker-compose down --remove-orphans
    
    log "Services stopped"
}

# Update deployment
update_deployment() {
    log "Updating deployment..."
    
    # Pull latest images
    docker-compose pull
    
    # Recreate containers with new images
    docker-compose up -d --force-recreate
    
    log "Deployment updated"
}

# Health check
health_check() {
    log "Performing health check..."
    
    local services=(
        "http://localhost:8080/health"     # HDGL Daemon
        "http://localhost:9090/-/healthy"  # Prometheus
        "http://localhost:3000/api/health" # Grafana
        "http://localhost:9200/_cluster/health" # Elasticsearch
    )
    
    for service in "${services[@]}"; do
        if curl -f -s "$service" > /dev/null; then
            info "✓ $(echo $service | cut -d'/' -f3) is healthy"
        else
            warn "✗ $(echo $service | cut -d'/' -f3) health check failed"
        fi
    done
    
    # Check Docker containers
    local unhealthy=$(docker-compose ps --filter "health=unhealthy" -q | wc -l)
    if [[ $unhealthy -gt 0 ]]; then
        warn "$unhealthy containers are unhealthy"
        docker-compose ps --filter "health=unhealthy"
    else
        info "All containers are healthy"
    fi
}

# View logs
view_logs() {
    local service="${3:-}"
    if [[ -n "$service" ]]; then
        docker-compose logs -f --tail=100 "$service"
    else
        docker-compose logs -f --tail=50
    fi
}

# Clean up
cleanup() {
    log "Cleaning up..."
    
    # Remove unused Docker resources
    docker system prune -f
    docker volume prune -f
    
    # Clean up old log files
    find /var/log/hdgl -name "*.log" -mtime +30 -delete
    
    log "Cleanup completed"
}

# Show status
show_status() {
    info "HDGL Bridge Status:"
    echo "===================="
    docker-compose ps
    echo ""
    
    info "Resource Usage:"
    echo "==============="
    docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
    echo ""
    
    info "Recent Logs:"
    echo "============"
    docker-compose logs --tail=20 hdgl-daemon
}

# Main execution
main() {
    log "Starting HDGL Bridge deployment - Environment: $ENVIRONMENT, Action: $ACTION"
    
    case $ACTION in
        deploy)
            validate_environment
            check_prerequisites
            create_directories
            setup_environment
            backup_data
            build_images
            compile_circuits
            generate_ssl
            start_services
            health_check
            show_status
            log "Deployment completed successfully!"
            ;;
        
        start)
            setup_environment
            start_services
            ;;
        
        stop)
            setup_environment
            stop_services
            ;;
        
        restart)
            setup_environment
            stop_services
            sleep 5
            start_services
            ;;
        
        update)
            setup_environment
            backup_data
            update_deployment
            health_check
            ;;
        
        build)
            build_images
            compile_circuits
            ;;
        
        logs)
            setup_environment
            view_logs "$@"
            ;;
        
        health)
            health_check
            ;;
        
        status)
            show_status
            ;;
        
        cleanup)
            cleanup
            ;;
        
        *)
            error "Unknown action: $ACTION"
            echo "Usage: $0 [environment] [action]"
            echo "Environments: development, staging, production"
            echo "Actions: deploy, start, stop, restart, update, build, logs, health, status, cleanup"
            exit 1
            ;;
    esac
}

# Trap for cleanup on script exit
trap cleanup EXIT

# Run main function
main "$@"