#!/bin/bash
# Общее для planerka.sh и morning.sh.
#
# Оба скрипта делают одно и то же вокруг своей настоящей работы: пишут в лог,
# шлют предупреждения в телеграм, тянут волт до прогона и пушат после с
# ретраями. До 29.07.2026 это лежало двумя копиями, и копии уже начали
# расходиться. Прецедент, чем такое кончается, у нас свой: в finsync общий код
# разъехался между Маком и Пи, и три дня молча терялись 55 000 ₽.
#
# Файл только определяет функции — ничего не выполняет и никуда не пишет при
# подключении. Скрипт перед `source` обязан задать:
#   LOG                 — куда писать (свой файл у каждого)
#   LOG_DIR             — где держать отметки дедупа алертов
#   VAULT               — корень волта
#   NOTIFY_PREFIX       — как подписывать сообщения («планёрка», «утренний прогон»)
#   TELEGRAM_BOT_TOKEN / TELEGRAM_OWNER_USER_ID — из .env
# Необязательное:
#   PLANNER_GIT_SYNC=1  — включает работу с git (на Маке волт не клон)
#   NOTIFY_DEDUP_MIN    — окно дедупа в минутах (по умолчанию 1200 = 20 часов)

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG"; }

# --- телеграм -------------------------------------------------------------

tg_api() { echo "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}"; }
_tg_url() { echo "$(tg_api)/sendMessage"; }

# Отправить файл. Нужно ровно в одном месте — когда Telegraph не отдал
# страницу и план недели приходится слать вложением. BOM в начале обязателен:
# просмотрщик Telegram на iOS показывает UTF-8 без него кракозябрами.
tg_send_document() {   # $1 — файл, $2 — подпись
  local src="$1" caption="$2" copy
  copy="$LOG_DIR/$(basename "$src")"
  printf '\xEF\xBB\xBF' > "$copy" && cat "$src" >> "$copy" || return 1
  curl -s -o /dev/null --max-time 60 -X POST "$(tg_api)/sendDocument" \
    -F "chat_id=$TELEGRAM_OWNER_USER_ID" -F "document=@$copy" \
    -F "caption=$caption"
  rm -f "$copy"
}

# Отправить текст и вернуть HTTP-код. Единственная функция, чей код кто-то
# проверяет: от него зависит, можно ли закрывать идеи в TickTick.
tg_send() {
  curl -s -o /dev/null -w '%{http_code}' --max-time 30 -X POST "$(_tg_url)" \
    --data-urlencode "chat_id=$TELEGRAM_OWNER_USER_ID" \
    --data-urlencode "text=$1"
}

# Предупреждение «что-то не так», без ожидания ответа.
#
# Второй аргумент — ключ дедупа, и он не косметика. У утреннего прогона
# причины живут долго (протухший логин, конфликт в волте), а сам он бегает
# каждый день: без дедупа один и тот же алерт приходил бы каждое утро и очень
# быстро стал бы фоном. Окно 20 часов, а не 24: прогон ежедневный, и к
# следующему утру отметке ровно около суток — окно в 1440 минут глушило бы
# алерт через раз, по случайности времени старта.
#
# Ключ не передан — дедупа нет (недельной планёрке он не нужен).
tg_notify() {
  [ -n "${TELEGRAM_BOT_TOKEN:-}" ] && [ -n "${TELEGRAM_OWNER_USER_ID:-}" ] || return 0
  local text="$1" key="${2:-}" stamp window
  window="${NOTIFY_DEDUP_MIN:-1200}"
  if [ -n "$key" ]; then
    stamp="$LOG_DIR/.alert-$key"
    if [ -f "$stamp" ] && [ -n "$(find "$stamp" -mmin "-$window" 2>/dev/null)" ]; then
      log "алерт «$key» уже уходил меньше $((window / 60)) ч назад — молчу"
      return 0
    fi
    touch "$stamp"
  fi
  curl -s -o /dev/null --max-time 15 -X POST "$(_tg_url)" \
    --data-urlencode "chat_id=$TELEGRAM_OWNER_USER_ID" \
    --data-urlencode "text=⚠️ ${NOTIFY_PREFIX}: $text" >/dev/null 2>&1
}

# --- волт -----------------------------------------------------------------

# Подтянуть свежий волт перед прогоном.
#
# `rebase --abort` обязателен: без него неудавшийся rebase оставляет клон в
# полуразобранном состоянии, и следом падают все, кто тянет волт после. На Пи
# таких четверо подряд — feedwatch, enwatch, утро, планёрка.
vault_pull() {
  [ "${PLANNER_GIT_SYNC:-0}" = "1" ] || return 0
  if ! git -C "$VAULT" pull --rebase >> "$LOG" 2>&1; then
    git -C "$VAULT" rebase --abort >> "$LOG" 2>&1
    log "WARN: git pull --rebase не прошёл — откатил rebase, работаю на локальном состоянии волта"
  fi
}

# vault_push <сообщение коммита> <что сказать в алерте> <путь> [путь...]
#
# Пока прогон идёт (у планёрки это ~8 минут), волт мог уехать вперёд: автосинк
# с Мака, правки с телефона, соседний бот. Тогда push отлетает — тянем и
# пробуем снова, до трёх раз. Без этого результат тихо оставался лежать на Пи.
#
# Пути добавляются по одному: `git add a b` при отсутствующем `a` падает на
# pathspec и не добавляет ничего, включая существующие.
#
# Ключ дедупа для алертов о неудаче — в NOTIFY_DEDUP_KEY (пусто = без дедупа).
vault_push() {
  [ "${PLANNER_GIT_SYNC:-0}" = "1" ] || return 0
  local msg="$1" what="$2"; shift 2
  local key="${NOTIFY_DEDUP_KEY:-}"
  local p attempt

  for p in "$@"; do
    git -C "$VAULT" add -- "$p" >> "$LOG" 2>&1 || true
  done
  if ! git -C "$VAULT" commit -m "$msg" >> "$LOG" 2>&1; then
    log "git: коммитить нечего"
    return 0
  fi

  for attempt in 1 2 3; do
    if git -C "$VAULT" push >> "$LOG" 2>&1; then
      [ "$attempt" -gt 1 ] && log "git: push прошёл с попытки $attempt"
      return 0
    fi
    log "WARN: push не прошёл (попытка $attempt) — тяну волт и пробую снова"
    if ! git -C "$VAULT" pull --rebase >> "$LOG" 2>&1; then
      git -C "$VAULT" rebase --abort >> "$LOG" 2>&1
      log "ERROR: pull --rebase не прошёл — коммит остаётся локальным"
      tg_notify "волт не синкнулся (конфликт при rebase), $what лежит на Пи" "$key"
      return 0
    fi
    sleep 3
  done

  log "ERROR: push не прошёл после 3 попыток"
  tg_notify "волт не синкнулся после 3 попыток, $what лежит на Пи" "$key"
  return 0
}

# --- идеи из TickTick -----------------------------------------------------

# Собрать идеи. Первый аргумент — окно свежести в часах; пусто = все.
# Разница между прогонами ровно в нём: планёрке раз в неделю уместен весь
# список, утру нужны сутки, иначе одни и те же идеи приезжали бы каждое утро.
# Всё остальное (обход списков, разбор ответа, живучесть к отвалам) — в
# ticktick.py, под тестами.
ticktick_ideas() {
  local since="${1:-}" markers="${2:-}" args=()
  [ -n "$since" ] && args+=(--since-hours "$since")
  [ "$markers" = "markers" ] && args+=(--with-markers)
  # "${args[@]+"${args[@]}"}" вместо "${args[@]}": на bash 3.2 (системный на
  # Маке) под `set -u` разыменование ПУСТОГО массива падает с
  # «unbound variable» — известный баг, живущий до bash 4.4. insta.sh зовёт
  # эту функцию как ticktick_ideas "" (оба аргумента пустые → args пуст) и
  # напарывался на это молча: подшелл IDEAS=$(...) умирал, идеи
  # подменялись фолбэком «идей нет», а сам прогон не падал и не сообщал.
  # На Pi (bash 5.x) баг не воспроизводится — тем не менее фикс общий, чтобы
  # поведение не зависело от версии bash у вызывающего.
  python3 "$SCRIPT_DIR/ticktick.py" list --lists "${TICKTICK_LISTS:-}" "${args[@]+"${args[@]}"}" 2>>"$LOG"
}
