#!/bin/bash
#
# ThrillWiki Auto-Pull Script
# Automatically pulls latest changes from Git repository every 10 minutes
# Designed to run as a cron job on the VM
#

set -e

# Configuration
PROJECT_DIR="/home/thrillwiki/thrillwiki"
LOG_FILE="/home/thrillwiki/logs/auto-pull.log"
LOCK_FILE="/tmp/thrillwiki-auto-pull.lock"
SERVICE_NAME="thrillwiki"
MAX_LOG_SIZE=10485760  # 10MB

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

log_error() {
    echo -e "$(date '+%Y-%m-%d %H:%M:%S') ${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE"
}

log_success() {
    echo -e "$(date '+%Y-%m-%d %H:%M:%S') ${GREEN}[SUCCESS]${NC} $1" | tee -a "$LOG_FILE"
}

log_warning() {
    echo -e "$(date '+%Y-%m-%d %H:%M:%S') ${YELLOW}[WARNING]${NC} $1" | tee -a "$LOG_FILE"
}

# Function to rotate log file if it gets too large
rotate_log() {
    if [ -f "$LOG_FILE" ] && [ $(stat -f%z "$LOG_FILE" 2>/dev/null || stat -c%s "$LOG_FILE" 2>/dev/null || echo 0) -gt $MAX_LOG_SIZE ]; then
        mv "$LOG_FILE" "${LOG_FILE}.old"
        log "Log file rotated due to size limit"
    fi
}

# Function to acquire lock
acquire_lock() {
    if [ -f "$LOCK_FILE" ]; then
        local lock_pid=$(cat "$LOCK_FILE" 2>/dev/null || echo "")
        if [ -n "$lock_pid" ] && kill -0 "$lock_pid" 2>/dev/null; then
            log_warning "Auto-pull already running (PID: $lock_pid), skipping this run"
            exit 0
        else
            log "Removing stale lock file"
            rm -f "$LOCK_FILE"
        fi
    fi
    
    echo $$ > "$LOCK_FILE"
    trap 'rm -f "$LOCK_FILE"' EXIT
}

# Function to setup GitHub authentication
setup_git_auth() {
    log "🔐 Setting up GitHub authentication..."
    
    # Check if GITHUB_TOKEN is available
    if [ -z "${GITHUB_TOKEN:-}" ]; then
        # Try loading from ***REMOVED*** file in project directory
        if [ -f "$PROJECT_DIR/***REMOVED***" ]; then
            source "$PROJECT_DIR/***REMOVED***"
        fi
        
        # Try loading from global ***REMOVED***.unraid
        if [ -z "${GITHUB_TOKEN:-}" ] && [ -f "$PROJECT_DIR/../../***REMOVED***.unraid" ]; then
            source "$PROJECT_DIR/../../***REMOVED***.unraid"
        fi
        
        # Try loading from parent directory ***REMOVED***.unraid
        if [ -z "${GITHUB_TOKEN:-}" ] && [ -f "$PROJECT_DIR/../***REMOVED***.unraid" ]; then
            source "$PROJECT_DIR/../***REMOVED***.unraid"
        fi
    fi
    
    # Verify we have the token
    if [ -z "${GITHUB_TOKEN:-}" ]; then
        log_warning "⚠️  GITHUB_TOKEN not found, trying public access..."
        return 1
    fi
    
    # Configure git to use token authentication
    local repo_url="https://github.com/pacnpal/thrillwiki_django_no_react.git"
    local auth_url="https://pacnpal:${GITHUB_TOKEN}@github.com/pacnpal/thrillwiki_django_no_react.git"
    
    # Update remote URL to use token
    if git remote get-url origin | grep -q "github.com/pacnpal/thrillwiki_django_no_react"; then
        git remote set-url origin "$auth_url"
        log_success "✅ GitHub authentication configured with token"
        return 0
    else
        log_warning "⚠️  Repository origin URL doesn't match expected GitHub repo"
        return 1
    fi
}

# Function to check if Git repository has changes
has_remote_changes() {
    # Setup authentication first
    if ! setup_git_auth; then
        log_warning "⚠️  GitHub authentication failed, skipping remote check"
        return 1  # Assume no changes if we can't authenticate
    fi
    
    # Fetch latest changes without merging
    log "📡 Fetching latest changes from remote..."
    if ! git fetch origin main --quiet 2>/dev/null; then
        log_error "❌ Failed to fetch from remote repository - authentication or network issue"
        log_warning "⚠️  Auto-pull will skip this cycle due to fetch failure"
        return 1
    fi
    
    # Compare local and remote
    local local_commit=$(git rev-parse HEAD)
    local remote_commit=$(git rev-parse origin/main)
    
    log "📊 Local commit: ${local_commit:0:8}"
    log "📊 Remote commit: ${remote_commit:0:8}"
    
    if [ "$local_commit" != "$remote_commit" ]; then
        log "📥 New changes detected!"
        return 0  # Has changes
    else
        log "✅ Repository is up to date"
        return 1  # No changes
    fi
}

# Function to check service status
is_service_running() {
    systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null
}

# Function to restart service safely
restart_service() {
    log "Restarting ThrillWiki service..."
    
    if systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null; then
        if sudo systemctl restart "$SERVICE_NAME"; then
            log_success "Service restarted successfully"
            return 0
        else
            log_error "Failed to restart service"
            return 1
        fi
    else
        log_warning "Service not enabled, attempting manual restart..."
        # Try to start it anyway
        if sudo systemctl start "$SERVICE_NAME" 2>/dev/null; then
            log_success "Service started successfully"
            return 0
        else
            log_warning "Service restart failed, may need manual intervention"
            return 1
        fi
    fi
}

# Function to update Python dependencies
update_dependencies() {
    log "Checking for dependency updates..."
    
    # Check if UV is available
    export PATH="/home/thrillwiki/.cargo/bin:$PATH"
    if command -v uv > /dev/null 2>&1; then
        log "Updating dependencies with UV..."
        if uv sync --quiet; then
            log_success "Dependencies updated with UV"
            return 0
        else
            log_warning "UV sync failed, trying pip..."
        fi
    fi
    
    # Fallback to pip if UV fails or isn't available
    if [ -d ".venv" ]; then
        log "Activating virtual environment and updating with pip..."
        source .venv/bin/activate
        if pip install -e . --quiet; then
            log_success "Dependencies updated with pip"
            return 0
        else
            log_warning "Pip install failed"
            return 1
        fi
    else
        log_warning "No virtual environment found, skipping dependency update"
        return 1
    fi
}

# Function to run Django migrations
run_migrations() {
    log "Running Django migrations..."
    
    export PATH="/home/thrillwiki/.cargo/bin:$PATH"
    
    # Try with UV first
    if command -v uv > /dev/null 2>&1; then
        if uv run python manage.py migrate --quiet; then
            log_success "Migrations completed with UV"
            return 0
        else
            log_warning "UV migrations failed, trying direct Python..."
        fi
    fi
    
    # Fallback to direct Python
    if [ -d ".venv" ]; then
        source .venv/bin/activate
        if python manage.py migrate --quiet; then
            log_success "Migrations completed with Python"
            return 0
        else
            log_warning "Django migrations failed"
            return 1
        fi
    else
        if python3 manage.py migrate --quiet; then
            log_success "Migrations completed"
            return 0
        else
            log_warning "Django migrations failed"
            return 1
        fi
    fi
}

# Function to collect static files
collect_static() {
    log "Collecting static files..."
    
    export PATH="/home/thrillwiki/.cargo/bin:$PATH"
    
    # Try with UV first
    if command -v uv > /dev/null 2>&1; then
        if uv run python manage.py collectstatic --noinput --quiet; then
            log_success "Static files collected with UV"
            return 0
        else
            log_warning "UV collectstatic failed, trying direct Python..."
        fi
    fi
    
    # Fallback to direct Python
    if [ -d ".venv" ]; then
        source .venv/bin/activate
        if python manage.py collectstatic --noinput --quiet; then
            log_success "Static files collected with Python"
            return 0
        else
            log_warning "Static file collection failed"
            return 1
        fi
    else
        if python3 manage.py collectstatic --noinput --quiet; then
            log_success "Static files collected"
            return 0
        else
            log_warning "Static file collection failed"
            return 1
        fi
    fi
}

# Main auto-pull function
main() {
    # Setup
    rotate_log
    acquire_lock
    
    log "🔄 Starting auto-pull check..."
    
    # Ensure logs directory exists
    mkdir -p "$(dirname "$LOG_FILE")"
    
    # Change to project directory
    if ! cd "$PROJECT_DIR"; then
        log_error "Failed to change to project directory: $PROJECT_DIR"
        exit 1
    fi
    
    # Check if this is a Git repository
    if [ ! -d ".git" ]; then
        log_error "Not a Git repository: $PROJECT_DIR"
        exit 1
    fi
    
    # Check for remote changes
    log "📡 Checking for remote changes..."
    if ! has_remote_changes; then
        log "✅ Repository is up to date, no changes to pull"
        exit 0
    fi
    
    log "📥 New changes detected, pulling updates..."
    
    # Record current service status
    local service_was_running=false
    if is_service_running; then
        service_was_running=true
        log "📊 Service is currently running"
    else
        log "📊 Service is not running"
    fi
    
    # Pull the latest changes
    local pull_output
    if pull_output=$(git pull origin main 2>&1); then
        log_success "✅ Git pull completed successfully"
        log "📋 Changes:"
        echo "$pull_output" | grep -E "^\s*(create|modify|delete|rename)" | head -10 | while read line; do
            log "   $line"
        done
    else
        log_error "❌ Git pull failed:"
        echo "$pull_output" | head -10 | while read line; do
            log_error "   $line"
        done
        exit 1
    fi
    
    # Update dependencies if requirements files changed
    if echo "$pull_output" | grep -qE "(pyproject\.toml|requirements.*\.txt|setup\.py)"; then
        log "📦 Dependencies file changed, updating..."
        update_dependencies
    else
        log "📦 No dependency changes detected, skipping update"
    fi
    
    # Run migrations if models changed
    if echo "$pull_output" | grep -qE "(models\.py|migrations/)"; then
        log "🗄️ Model changes detected, running migrations..."
        run_migrations
    else
        log "🗄️ No model changes detected, skipping migrations"
    fi
    
    # Collect static files if they changed
    if echo "$pull_output" | grep -qE "(static/|templates/|\.css|\.js)"; then
        log "🎨 Static files changed, collecting..."
        collect_static
    else
        log "🎨 No static file changes detected, skipping collection"
    fi
    
    # Restart service if it was running
    if $service_was_running; then
        log "🔄 Restarting service due to code changes..."
        if restart_service; then
            # Wait a moment for service to fully start
            sleep 3
            
            # Verify service is running
            if is_service_running; then
                log_success "🎉 Auto-pull completed successfully! Service is running."
            else
                log_error "⚠️ Service failed to start after restart"
                exit 1
            fi
        else
            log_error "⚠️ Service restart failed"
            exit 1
        fi
    else
        log_success "🎉 Auto-pull completed successfully! (Service was not running)"
    fi
    
    # Health check
    log "🔍 Performing health check..."
    if curl -f http://localhost:8000 > /dev/null 2>&1; then
        log_success "✅ Application health check passed"
    else
        log_warning "⚠️ Application health check failed (may still be starting up)"
    fi
    
    log "✨ Auto-pull cycle completed at $(date)"
}

# Handle script arguments
case "${1:-}" in
    --help|-h)
        echo "ThrillWiki Auto-Pull Script"
        echo ""
        echo "Usage:"
        echo "  $0          Run auto-pull check (default)"
        echo "  $0 --force  Force pull even if no changes detected"
        echo "  $0 --status Check auto-pull service status"
        echo "  $0 --logs   Show recent auto-pull logs"
        echo "  $0 --help   Show this help"
        exit 0
        ;;
    --force)
        log "🚨 Force mode: Pulling regardless of changes"
        # Skip the has_remote_changes check
        cd "$PROJECT_DIR"
        
        # Setup authentication and pull
        setup_git_auth
        if git pull origin main; then
            log_success "✅ Force pull completed"
            
            # Run standard update procedures
            update_dependencies
            run_migrations
            collect_static
            
            # Restart service if it was running
            if is_service_running; then
                restart_service
            fi
            
            log_success "🎉 Force update completed successfully!"
        else
            log_error "❌ Force pull failed"
            exit 1
        fi
        ;;
    --status)
        if systemctl is-active --quiet crond 2>/dev/null; then
            echo "✅ Cron daemon is running"
        else
            echo "❌ Cron daemon is not running"
        fi
        
        if crontab -l 2>/dev/null | grep -q "auto-pull.sh"; then
            echo "✅ Auto-pull cron job is installed"
            echo "📋 Current cron jobs:"
            crontab -l 2>/dev/null | grep -E "(auto-pull|thrillwiki)"
        else
            echo "❌ Auto-pull cron job is not installed"
        fi
        
        if [ -f "$LOG_FILE" ]; then
            echo "📄 Last auto-pull log entries:"
            tail -5 "$LOG_FILE"
        else
            echo "📄 No auto-pull logs found"
        fi
        ;;
    --logs)
        if [ -f "$LOG_FILE" ]; then
            tail -50 "$LOG_FILE"
        else
            echo "No auto-pull logs found at $LOG_FILE"
        fi
        ;;
    *)
        # Default: run main auto-pull
        main
        ;;
esac
