#!/bin/bash
# WHP Update Script
# Updates existing WHP installation from release package

# Exit on any error
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

# Get the directory where this script is located
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

# Check if this is being run from extracted package
if [ ! -f "$SCRIPT_DIR/VERSION" ]; then
    echo -e "${RED}Error: update.sh must be run from extracted WHP package directory${NC}"
    echo "Expected to find VERSION file in: $SCRIPT_DIR"
    exit 1
fi

# Check if WHP is installed
if [ ! -f /etc/whp-version ] && [ ! -f /root/whp/VERSION ]; then
    echo -e "${RED}Error: WHP not installed. Please run setup.sh for new installations.${NC}"
    exit 1
fi

# Get current version (check both locations for compatibility)
if [ -f /etc/whp-version ]; then
    CURRENT_VERSION=$(cat /etc/whp-version | tr -cd '0-9.')
elif [ -f /root/whp/VERSION ]; then
    CURRENT_VERSION=$(cat /root/whp/VERSION | tr -cd '0-9.')
else
    echo -e "${RED}Error: Cannot determine current WHP version${NC}"
    exit 1
fi

NEW_VERSION=$(cat "$SCRIPT_DIR/VERSION" | tr -cd '0-9.')

# Validate version format
if [[ -z "$CURRENT_VERSION" ]] || ! [[ "$CURRENT_VERSION" =~ ^[0-9]{4}\.[0-9]{1,2}\.[0-9]+$ ]]; then
    echo -e "${RED}Error: Invalid current version format: $CURRENT_VERSION${NC}"
    exit 1
fi

if [[ -z "$NEW_VERSION" ]] || ! [[ "$NEW_VERSION" =~ ^[0-9]{4}\.[0-9]{1,2}\.[0-9]+$ ]]; then
    echo -e "${RED}Error: Invalid new version format: $NEW_VERSION${NC}"
    exit 1
fi

echo -e "${BLUE}=== WHP Update ===${NC}"
echo "Current version: $CURRENT_VERSION"
echo "New version: $NEW_VERSION"

# Check if already on latest version
if [ "$CURRENT_VERSION" = "$NEW_VERSION" ]; then
    echo -e "${GREEN}Already running version $NEW_VERSION${NC}"
    exit 0
fi

# Function to compare versions (YYYY.MM.N format)
version_compare() {
    # Validate input format
    if ! [[ "$1" =~ ^[0-9]{4}\.[0-9]{1,2}\.[0-9]+$ ]] || ! [[ "$2" =~ ^[0-9]{4}\.[0-9]{1,2}\.[0-9]+$ ]]; then
        echo "Error: Invalid version format. Expected YYYY.MM.N" >&2
        return 1
    fi
    
    # Parse version components
    local v1_year=$(echo "$1" | cut -d'.' -f1)
    local v1_month=$(echo "$1" | cut -d'.' -f2)
    local v1_patch=$(echo "$1" | cut -d'.' -f3)
    
    local v2_year=$(echo "$2" | cut -d'.' -f1)
    local v2_month=$(echo "$2" | cut -d'.' -f2)
    local v2_patch=$(echo "$2" | cut -d'.' -f3)
    
    # Handle empty components with defaults
    v1_patch=${v1_patch:-0}
    v2_patch=${v2_patch:-0}
    
    # Compare year first
    if [ "$v1_year" -lt "$v2_year" ]; then
        echo "-1"
        return
    elif [ "$v1_year" -gt "$v2_year" ]; then
        echo "1"
        return
    fi
    
    # Years are equal, compare month
    if [ "$v1_month" -lt "$v2_month" ]; then
        echo "-1"
        return
    elif [ "$v1_month" -gt "$v2_month" ]; then
        echo "1"
        return
    fi
    
    # Years and months are equal, compare patch
    if [ "$v1_patch" -lt "$v2_patch" ]; then
        echo "-1"
    elif [ "$v1_patch" -gt "$v2_patch" ]; then
        echo "1"
    else
        echo "0"
    fi
}

# Self-test: a regressed comparator silently skips per-version update scripts
# (each cross-month low-patch rollover is a tripwire). Fail loudly here rather
# than silently apply nothing — the alternative is a "successful" update where
# half the work just didn't happen.
_VC_SELFTEST_FAIL=""
[ "$(version_compare 2026.04.146 2026.05.1)" = "-1" ] || _VC_SELFTEST_FAIL="2026.04.146 < 2026.05.1"
[ "$(version_compare 2026.05.2 2026.05.1)" = "1" ]   || _VC_SELFTEST_FAIL="${_VC_SELFTEST_FAIL:-2026.05.2 > 2026.05.1}"
[ "$(version_compare 2026.05.1 2026.05.1)" = "0" ]   || _VC_SELFTEST_FAIL="${_VC_SELFTEST_FAIL:-2026.05.1 == 2026.05.1}"
if [ -n "$_VC_SELFTEST_FAIL" ]; then
    echo -e "${RED}Error: version_compare() self-test failed: $_VC_SELFTEST_FAIL${NC}"
    echo "Refusing to run updates with a broken comparator — would silently skip update scripts."
    exit 1
fi
unset _VC_SELFTEST_FAIL

# Check migration compatibility
if [ -f "$SCRIPT_DIR/MIGRATION_HISTORY.json" ]; then
    OLDEST_SUPPORTED=$(grep '"oldest_supported"' "$SCRIPT_DIR/MIGRATION_HISTORY.json" | cut -d'"' -f4)
    
    # Proper version comparison (YYYY.MM.N format)
    COMPARE_RESULT=$(version_compare "$CURRENT_VERSION" "$OLDEST_SUPPORTED")
    if [ "$COMPARE_RESULT" = "-1" ]; then
        echo -e "${RED}Error: Your current version ($CURRENT_VERSION) is too old.${NC}"
        echo "This update package only supports versions $OLDEST_SUPPORTED and newer."
        echo "Please update to an intermediate version first."
        echo ""
        echo "Visit https://whp-releases.cloud-hosting.io for older releases."
        exit 1
    fi
fi

# Confirmation prompt
echo ""
echo -e "${YELLOW}This will update WHP from $CURRENT_VERSION to $NEW_VERSION${NC}"
read -p "Continue with update? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    echo "Update cancelled."
    exit 0
fi

# Backup current installation
echo ""
echo "Creating backup..."
if [ -x /root/whp/scripts/backup-whp.sh ]; then
    /root/whp/scripts/backup-whp.sh
else
    # Simple backup if backup script doesn't exist
    BACKUP_FILE="/root/whp-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
    tar -czf "$BACKUP_FILE" -C / root/whp docker/whp/web 2>/dev/null || true
    echo "Backup created: $BACKUP_FILE"
fi

# Create WHP directory if needed
mkdir -p /root/whp

# First, copy the apply-migrations.sh script if it exists
if [ -f "$SCRIPT_DIR/scripts/apply-migrations.sh" ]; then
    echo "Updating migration scripts..."
    mkdir -p /root/whp/scripts
    cp "$SCRIPT_DIR/scripts/apply-migrations.sh" /root/whp/scripts/
    chmod +x /root/whp/scripts/apply-migrations.sh
fi

# Apply SQL migrations before file sync
if [ -d "$SCRIPT_DIR/sql/migrations" ]; then
    echo ""
    echo "Applying database migrations..."
    
    # Create a temporary script to apply migrations
    cat > /tmp/whp-apply-migrations.sh << 'MIGRATION_SCRIPT'
#!/bin/bash
CURRENT_VERSION="$1"
NEW_VERSION="$2"
MIGRATION_DIR="$3"

# Function to compare versions (YYYY.MM.N format)
version_compare() {
    # Validate input format
    if ! [[ "$1" =~ ^[0-9]{4}\.[0-9]{1,2}\.[0-9]+$ ]] || ! [[ "$2" =~ ^[0-9]{4}\.[0-9]{1,2}\.[0-9]+$ ]]; then
        echo "Error: Invalid version format. Expected YYYY.MM.N" >&2
        return 1
    fi
    
    # Parse version components
    local v1_year=$(echo "$1" | cut -d'.' -f1)
    local v1_month=$(echo "$1" | cut -d'.' -f2)
    local v1_patch=$(echo "$1" | cut -d'.' -f3)
    
    local v2_year=$(echo "$2" | cut -d'.' -f1)
    local v2_month=$(echo "$2" | cut -d'.' -f2)
    local v2_patch=$(echo "$2" | cut -d'.' -f3)
    
    # Handle empty components with defaults
    v1_patch=${v1_patch:-0}
    v2_patch=${v2_patch:-0}
    
    # Compare year first
    if [ "$v1_year" -lt "$v2_year" ]; then
        echo "-1"
        return
    elif [ "$v1_year" -gt "$v2_year" ]; then
        echo "1"
        return
    fi
    
    # Years are equal, compare month
    if [ "$v1_month" -lt "$v2_month" ]; then
        echo "-1"
        return
    elif [ "$v1_month" -gt "$v2_month" ]; then
        echo "1"
        return
    fi
    
    # Years and months are equal, compare patch
    if [ "$v1_patch" -lt "$v2_patch" ]; then
        echo "-1"
    elif [ "$v1_patch" -gt "$v2_patch" ]; then
        echo "1"
    else
        echo "0"
    fi
}

# Get list of versions between current and new
cd "$MIGRATION_DIR"
VERSIONS=($(ls -d */ 2>/dev/null | sed 's/\///' | sort -V))

echo "Found ${#VERSIONS[@]} migration versions"

# Apply each version's migrations in order
for VERSION in "${VERSIONS[@]}"; do
    COMPARE_CURRENT=$(version_compare "$VERSION" "$CURRENT_VERSION")
    COMPARE_NEW=$(version_compare "$VERSION" "$NEW_VERSION")
    
    if [ "$COMPARE_CURRENT" = "1" ] && [ "$COMPARE_NEW" -le "0" ]; then
        echo "Applying migrations for version $VERSION..."
        
        # Get all SQL files in this version directory
        for SQL_FILE in "$VERSION"/*.sql; do
            if [ -f "$SQL_FILE" ]; then
                echo "  - Running: $SQL_FILE"
                mysql < "$SQL_FILE"
                if [ $? -ne 0 ]; then
                    echo "Error applying migration: $SQL_FILE"
                    exit 1
                fi
            fi
        done
    fi
done

echo "All migrations applied successfully"
MIGRATION_SCRIPT

    chmod +x /tmp/whp-apply-migrations.sh
    /tmp/whp-apply-migrations.sh "$CURRENT_VERSION" "$NEW_VERSION" "$SCRIPT_DIR/sql/migrations"
    
    if [ $? -ne 0 ]; then
        echo -e "${RED}Error applying migrations. Update aborted.${NC}"
        rm -f /tmp/whp-apply-migrations.sh
        exit 1
    fi
    
    rm -f /tmp/whp-apply-migrations.sh
fi

# Apply shell scripts after SQL migrations
if [ -d "$SCRIPT_DIR/scripts/updates" ]; then
    echo ""
    echo "Applying update scripts..."

    # Self-heal: refresh /root/whp/scripts/apply-scripts.sh from the new tarball
    # before invoking it. The persistent copy on long-running installations may
    # carry old bugs (e.g., the pre-2026.05 version_compare that silently skipped
    # cross-month low-patch versions); copying first ensures the comparator fix
    # in this release takes effect on the same run, not the next one.
    if [ -f "$SCRIPT_DIR/scripts/apply-scripts.sh" ]; then
        mkdir -p /root/whp/scripts
        cp "$SCRIPT_DIR/scripts/apply-scripts.sh" /root/whp/scripts/apply-scripts.sh
        chmod +x /root/whp/scripts/apply-scripts.sh
    fi

    if [ -f "/root/whp/scripts/apply-scripts.sh" ]; then
        "/root/whp/scripts/apply-scripts.sh" "$CURRENT_VERSION" "$NEW_VERSION" "$SCRIPT_DIR/scripts/updates"

        if [ $? -ne 0 ]; then
            echo -e "${RED}Error applying update scripts. Update aborted.${NC}"
            exit 1
        fi
    elif [ -f "$SCRIPT_DIR/scripts/apply-scripts.sh" ]; then
        # Fallback for first-time setup where /root/whp/ doesn't yet exist.
        chmod +x "$SCRIPT_DIR/scripts/apply-scripts.sh"
        "$SCRIPT_DIR/scripts/apply-scripts.sh" "$CURRENT_VERSION" "$NEW_VERSION" "$SCRIPT_DIR/scripts/updates"

        if [ $? -ne 0 ]; then
            echo -e "${RED}Error applying update scripts. Update aborted.${NC}"
            exit 1
        fi
    else
        echo -e "${YELLOW}No apply-scripts.sh found, skipping script execution${NC}"
    fi
fi

# Sync files (excluding sql/migrations since we already applied them)
echo ""
echo "Syncing files to /root/whp..."
rsync -av \
  --exclude='sql/migrations/' \
  --exclude='update.sh' \
  "$SCRIPT_DIR/" /root/whp/

# Copy update.sh separately after main sync to avoid overwriting running script
echo "Updating update.sh for future updates..."
cp "$SCRIPT_DIR/update.sh" /root/whp/update.sh

# Sync web files
if [ -d "$SCRIPT_DIR/web-files" ]; then
    echo ""
    echo "Syncing web files..."
    mkdir -p /docker/whp/web
    rsync -av --delete "$SCRIPT_DIR/web-files/" /docker/whp/web/
    
    # Set correct permissions
    chown -R apache:apache /docker/whp/web/
    find /docker/whp/web -type d -exec chmod 755 {} \;
    find /docker/whp/web -type f -exec chmod 644 {} \;
fi

# Update version file in both locations
echo $NEW_VERSION > /etc/whp-version
echo $NEW_VERSION > /root/whp/VERSION

# Set executable permissions on scripts
chmod +x /root/whp/scripts/*.sh 2>/dev/null || true
chmod +x /root/whp/setup.sh 2>/dev/null || true
chmod +x /root/whp/update.sh 2>/dev/null || true

# Ensure backup worker cron job exists (for existing installations)
echo "Checking backup system cron jobs..."
if ! crontab -l 2>/dev/null | grep -q "backup-worker.php"; then
    echo "Adding missing backup worker cron job..."
    (crontab -l 2>/dev/null; echo "# WHP Backup System - Process pending backup creations every minute") | crontab -
    (crontab -l 2>/dev/null; echo "* * * * * /usr/bin/php /docker/whp/web/scripts/backup-worker.php >/dev/null 2>&1") | crontab -
    echo "✓ Backup worker cron job added"
else
    echo "✓ Backup worker cron job already exists"
fi

# Run any post-update scripts
if [ -f /root/whp/scripts/post-update.sh ]; then
    echo ""
    echo "Running post-update tasks..."
    /root/whp/scripts/post-update.sh "$CURRENT_VERSION" "$NEW_VERSION"
fi

# Services typically don't need restart for WHP updates
# If restart is needed, it should be done via post-update script

echo ""
echo -e "${GREEN}Update complete!${NC}"
echo "WHP has been updated from $CURRENT_VERSION to $NEW_VERSION"
echo ""
echo "Please verify that everything is working correctly."
echo "If you encounter any issues, check the logs:"
echo "  - Apache: /var/log/httpd/error_log"
echo "  - PHP: /var/log/php-fpm/www-error.log"