#!/usr/bin/env bash
set -euo pipefail

# WHP WordPress version-cache refresher.
#
# Walks every active WordPress site in whp.wordpress_sites, runs
# `wp core version` inside its container, and writes the result to
# wordpress_sites.wp_version + wp_version_checked_at.
#
# The panel's /pages/wordpress.php reads from these cached columns instead
# of fetching versions on every page load. Without this script, that page
# fired one wp-cli boot per site (serial, ~1.5s each), holding the PHP
# session lock long enough to block every other panel action for ~40s on a
# 27-site install — and worse as the fleet grows.
#
# Run once from the install script (--all flag) and then hourly via cron
# (--stale flag) wrapped in flock + timeout per WHP convention.
#
# Flags:
#   --all     refresh every active site (used by the install script and on demand)
#   --stale   only refresh rows older than $STALE_HOURS hours (default 1) or NULL
#   --site=N  refresh a single site by id

LOG=/var/log/whp/refresh-wp-versions.log
mkdir -p "$(dirname "$LOG")"
exec >>"$LOG" 2>&1

STALE_HOURS=1
MODE="stale"
SITE_ID=""
for arg in "$@"; do
    case "$arg" in
        --all)        MODE="all" ;;
        --stale)      MODE="stale" ;;
        --site=*)     MODE="site"; SITE_ID="${arg#--site=}" ;;
        --hours=*)    STALE_HOURS="${arg#--hours=}" ;;
        *)
            echo "$(date -u +%FT%TZ) FATAL: unknown arg: $arg"
            exit 1
            ;;
    esac
done

if ! [ -r /root/.my.cnf ]; then
    echo "$(date -u +%FT%TZ) FATAL: /root/.my.cnf not readable"
    exit 1
fi

case "$MODE" in
    all)
        WHERE="status = 'active'"
        ;;
    stale)
        WHERE="status = 'active' AND (wp_version_checked_at IS NULL OR wp_version_checked_at < (NOW() - INTERVAL ${STALE_HOURS} HOUR))"
        ;;
    site)
        if ! [[ "$SITE_ID" =~ ^[0-9]+$ ]]; then
            echo "$(date -u +%FT%TZ) FATAL: --site requires a numeric id"
            exit 1
        fi
        WHERE="id = ${SITE_ID}"
        ;;
esac

echo "=== $(date -u +%FT%TZ) refresh-wp-versions starting (mode=$MODE) ==="

rows="$(mysql --defaults-file=/root/.my.cnf -N -B \
    -e "SELECT CONCAT(id, '|', user, '|', container_name) FROM whp.wordpress_sites WHERE ${WHERE}" 2>/dev/null || true)"

if [ -z "$rows" ]; then
    echo "$(date -u +%FT%TZ) no rows to refresh; exiting"
    exit 0
fi

scanned=0
updated=0
unchanged=0
no_container=0
errored=0

while IFS='|' read -r id user container; do
    [ -z "${id:-}" ] && continue
    id=$(echo "$id" | tr -d '\r\n')
    user=$(echo "$user" | tr -d '\r\n')
    container=$(echo "$container" | tr -d '\r\n')
    scanned=$((scanned+1))

    if ! docker inspect -f '{{.State.Running}}' "$container" 2>/dev/null | grep -q true; then
        no_container=$((no_container+1))
        # Don't update timestamp — leave NULL/old so we retry on the next run.
        continue
    fi

    new_version="$(docker exec --user "$user" -w "/home/$user/public_html" "$container" \
        wp core version 2>/dev/null | tail -1 | tr -d '\r\n' || true)"

    if ! [[ "$new_version" =~ ^[0-9]+\.[0-9]+ ]]; then
        errored=$((errored+1))
        echo "$(date -u +%FT%TZ) WARN: site id=$id ($user/$container) returned non-version: '${new_version:0:80}'"
        # Update the timestamp anyway so we don't retry every minute on a
        # genuinely-broken site; cron will re-check after STALE_HOURS.
        mysql --defaults-file=/root/.my.cnf -e \
            "UPDATE whp.wordpress_sites SET wp_version_checked_at = NOW() WHERE id = ${id}" \
            2>/dev/null || true
        continue
    fi

    # Only write wp_version if it actually changed (saves a row update).
    current="$(mysql --defaults-file=/root/.my.cnf -N -B \
        -e "SELECT IFNULL(wp_version, '') FROM whp.wordpress_sites WHERE id = ${id}" 2>/dev/null | tr -d '\r\n')"

    if [ "$current" = "$new_version" ]; then
        mysql --defaults-file=/root/.my.cnf -e \
            "UPDATE whp.wordpress_sites SET wp_version_checked_at = NOW() WHERE id = ${id}" \
            2>/dev/null || true
        unchanged=$((unchanged+1))
    else
        # Use a parameterized-style escape for new_version (it's already validated by the regex above).
        mysql --defaults-file=/root/.my.cnf -e \
            "UPDATE whp.wordpress_sites SET wp_version = '${new_version}', wp_version_checked_at = NOW() WHERE id = ${id}" \
            2>/dev/null || true
        updated=$((updated+1))
        echo "$(date -u +%FT%TZ) site id=$id container=$container: '${current:-<empty>}' -> '$new_version'"
    fi
done <<< "$rows"

echo "=== $(date -u +%FT%TZ) refresh-wp-versions done: scanned=$scanned updated=$updated unchanged=$unchanged no_container=$no_container errored=$errored ==="
exit 0
