#!/usr/bin/env bash

set -eo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/world_server_force_changed.conf"

cron_file="$CRON_FORCE_CHANGED_FILE"
notify_script="$NOTIFY_FORCE_CHANGED_SCRIPT"
log_file="$NOTIFY_FORCE_CHANGED_LOG_FILE"
lock_file="$NOTIFY_FORCE_CHANGED_LOCK_FILE"
max_log_size="$NOTIFY_FORCE_CHANGED_MAX_LOG_SIZE"

rotate_log_if_needed() {
    if [[ -f "$log_file" ]]; then
        local log_size
        log_size=$(wc -c < "$log_file")
        if (( log_size >= max_log_size )); then
            mv "$log_file" "${log_file}.$(date '+%Y%m%d_%H%M%S')"
        fi
    fi
}

log() {
    rotate_log_if_needed
    printf '[%s] %s\n' "$(date '+%F %T')" "$*" >> "$log_file"
}

exec 9>"$lock_file"

if ! flock -n 9; then
    log "another instance is still running, skip this round"
    exit 0
fi

if [[ ! -f "$cron_file" ]]; then
    log "cron file not found: $cron_file"
    exit 0
fi

target_unixtime="$(tr -d '[:space:]' < "$cron_file")"

if [[ -z "$target_unixtime" ]]; then
    log "cron file is empty: $cron_file"
    exit 0
fi

if ! [[ "$target_unixtime" =~ ^[0-9]+$ ]]; then
    log "invalid unixtime in $cron_file: $target_unixtime"
    exit 1
fi

now_unixtime="$(date +%s)"

if (( now_unixtime < target_unixtime )); then
    log "not yet reached target time: now=$now_unixtime target=$target_unixtime"
    exit 0
fi

# ---- WS-startup gate: only fire once every World Server has finished
#      starting (worlds.state != 0); otherwise keep cron_file and retry on
#      the next tick. No deadline: if it never completes that is a bug, do
#      not force-fire over it. ----
set +e
source "$HOME/.gamerc"
ws_query_out="$(ssh -n -o StrictHostKeyChecking=no ACCOUNTDB \
    "psql -U postgres ${ACCOUNT_DB_NAME} -Atqc \"SELECT id FROM worlds WHERE state = 0 ORDER BY id;\" && echo __WSOK__" 2>/dev/null)"
set -e

if [[ "$ws_query_out" != *__WSOK__* ]]; then
    log "WS startup query failed (ssh/psql/ACCOUNTDB), keep cron file, retry next tick"
    exit 0
fi

unstarted=""
while IFS= read -r line; do
    line="${line//[[:space:]]/}"
    [[ "$line" =~ ^[0-9]+$ ]] && unstarted+="WS$line "
done <<< "$ws_query_out"
unstarted="${unstarted% }"

if [[ -n "$unstarted" ]]; then
    log "WS not fully started yet, keep waiting: $unstarted"
    exit 0
fi

log "all World Servers started"
log "target time reached: now=$now_unixtime target=$target_unixtime"

set +e
ws_count="$(ssh -n -o StrictHostKeyChecking=no ACCOUNTDB \
    "psql -U postgres ${ACCOUNT_DB_NAME} -Atqc \"SELECT count(*) FROM worlds;\"" 2>/dev/null)"
set -e
ws_count="${ws_count//[[:space:]]/}"
log "send WS-startup-complete notification (count=$ws_count)"
"$notify_script" --wsok "$ws_count" >> "$log_file" 2>&1 || log "wsok notification failed (non-fatal), continue"

log "start notify script: $notify_script --allws"

if "$notify_script" --allws >> "$log_file" 2>&1; then
    log "notify script completed successfully"
    rm -f "$cron_file"
    log "removed cron file: $cron_file"
else
    rc=$?
    log "notify script failed with rc=$rc"
    exit "$rc"
fi
