#!/usr/bin/env bash
# Автопубликация сборки FastX, присланной в бот @kjn3bot (правило владельца от 11.09.2026).
# Запускается systemd-юнитом fastx-autopublish.service по событию path-юнита
# (журнал моста inbox.jsonl закрыт после записи) и страховочным таймером раз в 2 минуты.
# Берёт ПОСЛЕДНИЙ html-документ владельца из журнала, и если он ещё не публиковался:
#   бэкап → копия в FastX_publish.html и /var/www/fastx-miniapp/index.html →
#   сверка md5 с ответом сервера → подтверждение в Telegram.
set -u
# Переменные FASTX_* нужны только для тестового прогона на копиях (см. CLAUDE.local.md).
CFG="$HOME/.config/alex-telegram-bridge"
INBOX="${FASTX_INBOX:-$CFG/inbox.jsonl}"
STATE_DIR="${FASTX_STATE_DIR:-$HOME/.config/fastx-autopublish}"
STATE="$STATE_DIR/last_processed_path"
PROJ="$HOME/FasX-test-version"
PUB="${FASTX_PUB:-$PROJ/FastX_publish.html}"
WWW="${FASTX_WWW:-/var/www/fastx-miniapp/index.html}"
URL="${FASTX_URL:-https://test07.fastotc.xyz/fastx-miniapp/index.html}"
OWNER=7462492849
TG="${FASTX_TG:-$HOME/.local/bin/alex-tg-send}"

mkdir -p "$STATE_DIR"
exec 9>"$STATE_DIR/lock"
flock -n 9 || { echo "already running"; exit 0; }

newest() {
  python3 - "$INBOX" "$OWNER" <<'PY'
import json, sys
path, owner = sys.argv[1], int(sys.argv[2])
last = ""
try:
    lines = open(path, encoding="utf-8")
except FileNotFoundError:
    print(""); sys.exit(0)
for line in lines:
    try:
        d = json.loads(line)
    except Exception:
        continue
    if d.get("type") == "document" and d.get("chat_id") == owner \
       and str(d.get("path", "")).lower().endswith(".html"):
        last = str(d["path"])
print(last)
PY
}

spaced() { echo "$1" | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta'; }

while :; do
  NEW=$(newest)
  [ -n "$NEW" ] || { echo "no html documents in inbox"; exit 0; }
  LAST=$(cat "$STATE" 2>/dev/null || true)
  [ "$NEW" != "$LAST" ] || { echo "nothing new: $NEW"; exit 0; }

  BASE=$(basename "$NEW"); NAME=${BASE#*-}; PREFIX=${BASE%%-*}
  HHMM=$(date -d "@$PREFIX" +%H:%M 2>/dev/null || date +%H:%M)

  if [ ! -f "$NEW" ]; then
    echo "$NEW" > "$STATE"
    "$TG" "Автопубликация: в журнале моста есть $NAME, но файла на диске нет. Пришли сборку ещё раз."
    exit 0
  fi
  SIZE=$(stat -c %s "$NEW")
  if [ "$SIZE" -lt 1000000 ] || ! head -c 4000 "$NEW" | grep -q 'FastX' || ! tail -c 300 "$NEW" | grep -q '</html>'; then
    echo "$NEW" > "$STATE"
    "$TG" "Автопубликация: файл $NAME ($(spaced "$SIZE") байт) не похож на сборку FastX (нет заголовка FastX или закрывающего </html>), не публикую."
    exit 0
  fi

  MD5=$(md5sum "$NEW" | cut -d' ' -f1)
  CUR=$(md5sum "$WWW" 2>/dev/null | cut -d' ' -f1 || true)
  if [ "$MD5" = "$CUR" ]; then
    echo "$NEW" > "$STATE"; echo "already published: $NEW"; continue
  fi

  TS=$(date +%Y%m%d%H%M%S)
  if ! { cp -p "$PUB" "$PUB.bak-$TS" && cp "$NEW" "$PUB" \
      && cp -p "$WWW" "$WWW.bak-$TS" && cp "$NEW" "$WWW"; }; then
    "$TG" "Автопубликация: ошибка копирования $NAME, сборка не опубликована. Проверь журнал fastx-autopublish."
    exit 1
  fi
  echo "$NEW" > "$STATE"
  SERVED=$(curl -s --max-time 60 "$URL" | md5sum | cut -d' ' -f1)
  echo "published: $NEW md5=$MD5 served=$SERVED"
  if [ "$SERVED" = "$MD5" ]; then
    "$TG" "Сборка опубликована автоматически: $NAME от $HHMM ($(spaced "$SIZE") байт, md5 ${MD5:0:8}…). Кнопка «FastX» в боте отдаёт её, открой Mini App заново."
  else
    "$TG" "Автопубликация $NAME: файлы скопированы, но сервер отдаёт другой хеш (${SERVED:0:8}… вместо ${MD5:0:8}…). Проверь стенд."
  fi
done
