#!/bin/bash

# Vision Videoke Production Build and Deployment Script
set -e

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

# Configuration
APP_DIR="/var/www/visionvideoke"
BACKUP_DIR="/var/backups/visionvideoke"
LOG_FILE="/var/log/visionvideoke/deploy.log"
SOURCE_DIR="/tmp/visionvideoke-source"
GITHUB_REPO=""  # Set this if deploying from GitHub
BRANCH="main"   # Default branch

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
    exit 1
}

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

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

# Function to check prerequisites
check_prerequisites() {
    log "Checking prerequisites..."
    
    # Check if Node.js is installed
    if ! command -v node &> /dev/null; then
        error "Node.js is not installed. Please run ec2-setup.sh first."
    fi
    
    # Check if PM2 is installed
    if ! command -v pm2 &> /dev/null; then
        error "PM2 is not installed. Please run ec2-setup.sh first."
    fi
    
    # Check if nginx is installed
    if ! command -v nginx &> /dev/null; then
        error "Nginx is not installed. Please run ec2-setup.sh first."
    fi
    
    # Create directories if they don't exist
    sudo mkdir -p $APP_DIR $BACKUP_DIR /var/log/visionvideoke
    sudo chown ec2-user:ec2-user $APP_DIR $BACKUP_DIR /var/log/visionvideoke
    
    log "Prerequisites check completed"
}

# Function to create backup
create_backup() {
    log "Creating backup..."
    
    if [ -d "$APP_DIR" ] && [ "$(ls -A $APP_DIR)" ]; then
        BACKUP_NAME="backup-$(date +%Y%m%d-%H%M%S).tar.gz"
        tar -czf "$BACKUP_DIR/$BACKUP_NAME" -C "$APP_DIR" . 2>/dev/null || true
        log "Backup created: $BACKUP_NAME"
        
        # Keep only last 10 backups
        cd $BACKUP_DIR
        ls -t backup-*.tar.gz | tail -n +11 | xargs rm -f 2>/dev/null || true
    else
        log "No existing application to backup"
    fi
}

# Function to deploy from uploaded source
deploy_from_source() {
    local source_path=$1
    
    if [ ! -d "$source_path" ]; then
        error "Source directory not found: $source_path"
    fi
    
    log "Deploying from source: $source_path"
    
    # Copy source files
    log "Copying source files..."
    rsync -av --delete "$source_path/" "$APP_DIR/" \
        --exclude=node_modules \
        --exclude=.git \
        --exclude=dist \
        --exclude=build \
        --exclude=.env.local \
        --exclude=.env.production
    
    cd $APP_DIR
    
    # Install dependencies
    log "Installing dependencies..."
    npm ci --production=false
    
    # Build application
    log "Building application..."
    npm run build
    
    # Copy environment file if it doesn't exist
    if [ ! -f "$APP_DIR/.env" ] && [ -f "/home/ec2-user/.env.template" ]; then
        log "Creating environment file from template..."
        cp /home/ec2-user/.env.template $APP_DIR/.env
        warn "Please update the environment variables in $APP_DIR/.env"
    fi
    
    # Set proper permissions
    chown -R ec2-user:ec2-user $APP_DIR
    chmod 644 $APP_DIR/.env 2>/dev/null || true
}

# Function to deploy from GitHub
deploy_from_github() {
    local repo_url=$1
    local branch=${2:-main}
    
    log "Deploying from GitHub: $repo_url (branch: $branch)"
    
    # Clean up previous source
    rm -rf $SOURCE_DIR
    
    # Clone repository
    log "Cloning repository..."
    git clone -b $branch $repo_url $SOURCE_DIR
    
    # Deploy from cloned source
    deploy_from_source $SOURCE_DIR
    
    # Clean up
    rm -rf $SOURCE_DIR
}

# Function to create production package.json scripts
setup_production_scripts() {
    log "Setting up production scripts..."
    
    cd $APP_DIR
    
    # Create or update package.json scripts for production
    if [ -f "package.json" ]; then
        # Backup original package.json
        cp package.json package.json.backup
        
        # Add production scripts using Node.js
        node -e "
        const fs = require('fs');
        const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
        
        pkg.scripts = pkg.scripts || {};
        pkg.scripts['start'] = 'serve -s dist -l 3000';
        pkg.scripts['prod:build'] = 'npm run build';
        pkg.scripts['prod:start'] = 'pm2 start ecosystem.config.js';
        pkg.scripts['prod:stop'] = 'pm2 stop ecosystem.config.js';
        pkg.scripts['prod:restart'] = 'pm2 restart ecosystem.config.js';
        pkg.scripts['prod:logs'] = 'pm2 logs';
        
        fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
        "
        
        # Install serve if not present
        if ! npm list serve &>/dev/null; then
            log "Installing serve for production..."
            npm install serve --save
        fi
    fi
}

# Function to setup PM2 ecosystem
setup_pm2_ecosystem() {
    log "Setting up PM2 ecosystem..."
    
    cd $APP_DIR
    
    # Create ecosystem.config.js if it doesn't exist
    if [ ! -f "ecosystem.config.js" ]; then
        cat > ecosystem.config.js <<EOF
module.exports = {
  apps: [{
    name: 'visionvideoke',
    script: 'node_modules/.bin/serve',
    args: '-s dist -l 3000',
    cwd: '/var/www/visionvideoke',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    error_file: '/var/log/visionvideoke/error.log',
    out_file: '/var/log/visionvideoke/out.log',
    log_file: '/var/log/visionvideoke/combined.log',
    time: true,
    max_memory_restart: '1G',
    node_args: '--max-old-space-size=1024',
    watch: false,
    ignore_watch: ['node_modules', 'logs'],
    restart_delay: 4000,
    max_restarts: 10,
    min_uptime: '10s'
  }]
};
EOF
    fi
}

# Function to start/restart application
restart_application() {
    log "Restarting application..."
    
    cd $APP_DIR
    
    # Stop existing PM2 processes
    pm2 stop all 2>/dev/null || true
    pm2 delete all 2>/dev/null || true
    
    # Start application with PM2
    pm2 start ecosystem.config.js
    
    # Save PM2 configuration
    pm2 save
    
    # Wait for application to start
    sleep 5
    
    # Check if application is running
    if pm2 list | grep -q "online"; then
        log "Application started successfully"
    else
        error "Failed to start application"
    fi
}

# Function to test deployment
test_deployment() {
    log "Testing deployment..."
    
    # Test local connection
    local max_attempts=30
    local attempt=1
    
    while [ $attempt -le $max_attempts ]; do
        if curl -f -s http://localhost:3000/health > /dev/null 2>&1; then
            log "Health check passed"
            break
        else
            if [ $attempt -eq $max_attempts ]; then
                error "Health check failed after $max_attempts attempts"
            fi
            log "Health check attempt $attempt/$max_attempts failed, retrying..."
            sleep 2
            ((attempt++))
        fi
    done
    
    # Test nginx configuration
    if sudo nginx -t > /dev/null 2>&1; then
        log "Nginx configuration is valid"
        sudo systemctl reload nginx
    else
        error "Nginx configuration test failed"
    fi
}

# Function to cleanup
cleanup() {
    log "Cleaning up..."
    
    # Remove temporary files
    rm -rf $SOURCE_DIR
    
    # Clean npm cache
    npm cache clean --force 2>/dev/null || true
    
    # Clean old log files (keep last 7 days)
    find /var/log/visionvideoke -name "*.log" -mtime +7 -delete 2>/dev/null || true
}

# Function to show deployment status
show_status() {
    log "Deployment Status:"
    echo ""
    
    # PM2 status
    echo "PM2 Status:"
    pm2 list
    echo ""
    
    # Nginx status
    echo "Nginx Status:"
    sudo systemctl status nginx --no-pager -l
    echo ""
    
    # Disk usage
    echo "Disk Usage:"
    df -h /var/www/visionvideoke
    echo ""
    
    # Memory usage
    echo "Memory Usage:"
    free -h
    echo ""
    
    # Application logs (last 10 lines)
    echo "Recent Application Logs:"
    tail -n 10 /var/log/visionvideoke/combined.log 2>/dev/null || echo "No logs available"
}

# Main deployment function
main() {
    local deployment_type=${1:-"source"}
    local source_path=${2:-"/tmp/visionvideoke-upload"}
    local repo_url=${3:-""}
    local branch=${4:-"main"}
    
    log "Starting Vision Videoke deployment..."
    log "Deployment type: $deployment_type"
    
    # Check prerequisites
    check_prerequisites
    
    # Create backup
    create_backup
    
    # Deploy based on type
    case $deployment_type in
        "source")
            deploy_from_source "$source_path"
            ;;
        "github")
            if [ -z "$repo_url" ]; then
                error "GitHub repository URL is required for GitHub deployment"
            fi
            deploy_from_github "$repo_url" "$branch"
            ;;
        *)
            error "Invalid deployment type. Use 'source' or 'github'"
            ;;
    esac
    
    # Setup production environment
    setup_production_scripts
    setup_pm2_ecosystem
    
    # Restart application
    restart_application
    
    # Test deployment
    test_deployment
    
    # Cleanup
    cleanup
    
    # Show status
    show_status
    
    log "Deployment completed successfully!"
    log ""
    log "Application is running at:"
    log "- Local: http://localhost:3000"
    log "- Public: http://$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4 2>/dev/null || echo 'YOUR-SERVER-IP')"
    log ""
    log "Useful commands:"
    log "- pm2 status          # Check application status"
    log "- pm2 logs            # View application logs"
    log "- pm2 restart all     # Restart application"
    log "- sudo nginx -t       # Test nginx configuration"
    log "- sudo systemctl reload nginx  # Reload nginx"
}

# Script usage
usage() {
    echo "Usage: $0 [deployment_type] [source_path|repo_url] [branch]"
    echo ""
    echo "Deployment types:"
    echo "  source    Deploy from local source directory (default)"
    echo "  github    Deploy from GitHub repository"
    echo ""
    echo "Examples:"
    echo "  $0 source /tmp/visionvideoke-upload"
    echo "  $0 github https://github.com/user/visionvideoke.git main"
    echo ""
    echo "For source deployment, upload your source code to the specified directory first."
}

# Handle command line arguments
if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
    usage
    exit 0
fi

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

