#!/bin/bash
# ============================================================================
#  Міні-менеджер TG — вебпанель на ЦЬОМУ маку (список акаунтів + «Відкрити»).
#  Запусти → відкриється http://localhost:8770 у браузері.
#  Акаунти відкриваються ЛОКАЛЬНО на цьому маку. Тримай це вікно відкритим.
#
#  Цей запускач можна ПРОСТО ЗАПУСТИТИ ОДНІЄЮ КОМАНДОЮ з сайту (нічого не
#  качаючи файлом) — див. сторінку https://gram.eimar.digital/mini/setup.
#  І сам запускач, і начинку (core.py + panel.py) він тягне з веб-менеджера при
#  кожному запуску, тож оновлення доходять автоматично. Якщо сервер недоступний —
#  береться начинка з минулого разу.
# ============================================================================
# Робоча папка — завжди в домашній теці. Тож файл однаково працює і коли його
# двічі клікнути, і коли запустити командою з інтернету (bash <(curl …)).
DIR="$HOME/.tgmanager-helper"
CFG="$DIR/config"
VENV="$DIR/venv"
COOKIEJAR="$DIR/cookies.txt"
mkdir -p "$DIR"; chmod 700 "$DIR"

# браузерний підпис — інакше Cloudflare перед сервером блокує не-браузерні запити (помилка 1010)
UA="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36"

clear
echo "==============================================="
echo "   Міні-менеджер TG (вебпанель на цьому маку)"
echo "==============================================="
echo

DEFAULT_SERVER="https://gram.eimar.digital"
PRESET_PASSWORD=""

if [ ! -f "$CFG" ] && [ -z "$TGM_COOKIE" ]; then
  echo "Перший запуск — введи свій логін і пароль дашборда (адреса вже вшита)."
  echo "Якщо входиш без логіна (лише пароль) — просто натисни Enter на логіні."
  echo
  read -p "Логін (Enter — пропустити): " LGN
  if [ -n "$PRESET_PASSWORD" ]; then
    PW="$PRESET_PASSWORD"
  else
    read -s -p "Пароль дашборда: " PW; echo
  fi
  printf 'TGM_SERVER=%s\nTGM_LOGIN=%s\nTGM_PASSWORD=%s\n' "$DEFAULT_SERVER" "$LGN" "$PW" > "$CFG"
  chmod 600 "$CFG"
  echo "✓ збережено"
  echo
fi
ENV_COOKIE="$TGM_COOKIE"                 # ключ, вшитий у команду з кабінету — має пріоритет
set -a; [ -f "$CFG" ] && . "$CFG"; set +a
[ -n "$ENV_COOKIE" ] && TGM_COOKIE="$ENV_COOKIE"   # свіжий ключ із команди перекриває збережений

# Адресу сервера ЗАВЖДИ беремо з цього запускача (він щойно завантажений із правильної адреси).
# Якщо в збереженому конфізі застрягла стара/чужа адреса (інший сервер, порт чи внутрішня IP) —
# вона ламала б вхід (HTTP 000). Тому мовчки виправляємо її на правильну й перезаписуємо конфіг.
if [ "$TGM_SERVER" != "$DEFAULT_SERVER" ]; then
  echo "↻ виправляю збережену адресу сервера: $TGM_SERVER → $DEFAULT_SERVER"
  TGM_SERVER="$DEFAULT_SERVER"
  printf 'TGM_SERVER=%s\nTGM_LOGIN=%s\nTGM_PASSWORD=%s\n' "$TGM_SERVER" "${TGM_LOGIN:-}" "${TGM_PASSWORD:-}" > "$CFG"
  chmod 600 "$CFG"
fi

if [ ! -d "/Applications/Telegram.app" ]; then
  echo "❌ Немає Telegram Desktop у програмах."
  echo "   Встанови з https://telegram.org/dl/macos і запусти цей файл знову."
  echo; read -p "Натисни Enter щоб закрити."; exit 1
fi

PY=$(command -v python3 || true)
if [ -z "$PY" ]; then
  echo "❌ Немає python3. Встанови: xcode-select --install, потім запусти знову."
  echo; read -p "Натисни Enter щоб закрити."; exit 1
fi
if [ ! -x "$VENV/bin/python" ]; then
  echo "… готую середовище (одноразово, ~1 хв, треба інтернет)…"
  "$PY" -m venv "$VENV" || { echo "❌ не вдалось створити venv"; read -p "Enter"; exit 1; }
  "$VENV/bin/pip" -q install --upgrade pip
fi
# бібліотеки (усі чисто-Python — ставляться і на 3.14): opentele + проксі
"$VENV/bin/python" -c "import opentele" >/dev/null 2>&1 \
  || { echo "… встановлюю opentele…"; "$VENV/bin/pip" -q install opentele || { echo "❌ opentele"; read -p "Enter"; exit 1; }; }
if ! "$VENV/bin/python" -c "import python_socks" >/dev/null 2>&1 \
   || ! "$VENV/bin/python" -c "import socks" >/dev/null 2>&1; then
  echo "… додаю підтримку проксі…"
  "$VENV/bin/pip" -q install python-socks PySocks || { echo "❌ проксі-бібліотеки"; read -p "Enter"; exit 1; }
fi
# кореневі сертифікати для HTTPS (інакше Python не довіряє gram.eimar.digital)
"$VENV/bin/python" -c "import certifi" >/dev/null 2>&1 \
  || { echo "… додаю сертифікати…"; "$VENV/bin/pip" -q install certifi || { echo "❌ certifi"; read -p "Enter"; exit 1; }; }

# автопатч opentele під Python 3.13+
UTILS=$(ls "$VENV"/lib/python*/site-packages/opentele/utils.py 2>/dev/null | head -1)
if [ -n "$UTILS" ]; then
  "$VENV/bin/python" - "$UTILS" <<'PATCHEOF'
import sys, pathlib
p = pathlib.Path(sys.argv[1]); s = p.read_text()
old = '["__abstractmethods__", "__module__", "_abc_impl", "__doc__"]'
new = '["__abstractmethods__", "__module__", "_abc_impl", "__doc__", "__firstlineno__", "__static_attributes__"]'
if new not in s and old in s:
    p.write_text(s.replace(old, new)); print("✓ opentele адаптовано під новий Python")
PATCHEOF
fi
if ! "$VENV/bin/python" -c "import opentele" >/dev/null 2>&1; then
  echo "❌ opentele не вантажиться. Постав Python 3.12 з python.org, видали папку .tgmanager-helper і запусти знову."
  echo; read -p "Enter"; exit 1
fi
echo "✓ середовище готове"; echo

# --- префлайт: перевірка логіна/пароля з чітким повідомленням ----------------
# Пробуємо увійти в дашборд; якщо невірно — сервер каже ЩО саме (логін чи пароль),
# і ми перепитуємо, поки не вийде. Успішний вхід зберігає «печиво» (cookie) у файл —
# ним нижче завантажуємо начинку. Так друг не лишиться з порожньою панеллю.
auth_check() {
  local resp code body
  resp="$(curl -s -w $'\n%{http_code}' -c "$COOKIEJAR" -X POST "$TGM_SERVER/auth/login" \
          -A "$UA" \
          --data-urlencode "login=${TGM_LOGIN:-}" \
          --data-urlencode "password=${TGM_PASSWORD:-}" 2>/dev/null)"
  code="${resp##*$'\n'}"; body="${resp%$'\n'*}"
  [ "$code" = "200" ] && return 0
  ERRMSG="$(printf '%s' "$body" | sed -n 's/.*"error"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')"
  [ -z "$ERRMSG" ] && ERRMSG="сервер недоступний або відмовив (HTTP ${code:-?})"
  return 1
}
if [ -n "$TGM_COOKIE" ]; then
  # Вшитий ключ (узятий із залогіненого кабінету) — ні логіна, ні пароля вводити не треба.
  echo "✓ вхід за вшитим ключем — логін і пароль не потрібні"
  AUTHCURL=(-H "Cookie: tgm_session=$TGM_COOKIE")
  printf 'TGM_SERVER=%s\nTGM_COOKIE=%s\n' "$TGM_SERVER" "$TGM_COOKIE" > "$CFG"   # зберегти на майбутнє
  chmod 600 "$CFG"
else
  while ! auth_check; do
    echo
    echo "❌ Вхід не вдався: $ERRMSG"
    echo "   Спробуй ще раз (адреса: $TGM_SERVER). Логін порожній — якщо входиш лише паролем."
    read -p "Логін (Enter — пропустити): " LGN
    read -s -p "Пароль: " PWX; echo
    TGM_LOGIN="$LGN"; TGM_PASSWORD="$PWX"
    printf 'TGM_SERVER=%s\nTGM_LOGIN=%s\nTGM_PASSWORD=%s\n' "$TGM_SERVER" "$LGN" "$PWX" > "$CFG"
    chmod 600 "$CFG"
  done
  echo "✓ вхід у дашборд ок"
  AUTHCURL=(-b "$COOKIEJAR")
fi
echo

# --- завантаження начинки з веб-менеджера ------------------------------------
# core.py + panel.py тягнемо з сервера (з «печивом» від входу). Якщо завантаження
# не вдалося, але є копія з минулого разу — працюємо на ній. Якщо копії немає — стоп.
fetch_brain() {                 # $1 = ім'я файлу, $2 = слово-маркер, яке має бути у справжньому коді
  local f="$1" marker="$2" tmp="$DIR/$f.new"
  if curl -fsSL "${AUTHCURL[@]}" -A "$UA" "$TGM_SERVER/mini/$f" -o "$tmp" 2>/dev/null \
     && grep -q "$marker" "$tmp" 2>/dev/null; then
    mv "$tmp" "$DIR/$f"; return 0
  fi
  rm -f "$tmp"
  [ -f "$DIR/$f" ] && return 0  # завантаження впало, але є збережена копія → нею й скористаємось
  return 1
}
echo "… завантажую свіжу начинку з веб-менеджера…"
if fetch_brain core.py "_realistic_api" && fetch_brain panel.py "ThreadingHTTPServer"; then
  echo "✓ начинку отримано"
else
  echo "❌ Не вдалося завантажити начинку з сервера, і немає збереженої копії."
  echo "   Перевір інтернет і що сервер працює, потім запусти цей файл знову."
  echo; read -p "Enter"; exit 1
fi
echo

# --- запуск панелі ----------------------------------------------------------
echo "Відкриваю панель у браузері: http://localhost:8770"
echo "⚠️  НЕ закривай це вікно, поки користуєшся панеллю (воно тримає сервер)."
echo "   Щоб зупинити — просто закрий це вікно."
echo
# localhost (а не 127.0.0.1) — Safari показує favicon у вкладці лише за іменем хоста, не за голим IP
( sleep 2; open "http://localhost:8770" ) &
cd "$DIR"
# Самооновлення: панель сама стежить за новою версією начинки на сервері й, коли та зʼявляється,
# виходить з кодом 42. Тоді ми ТУТ докачуємо свіжу начинку й запускаємо її знову — тож другові
# більше НІЧОГО не треба робити руками. Будь-який інший код виходу = справжнє завершення.
while :; do
  "$VENV/bin/python" panel.py
  rc=$?
  [ "$rc" = "42" ] || break
  echo
  echo "↻ Знайшлось оновлення помічника — підтягую свіжу версію…"
  fetch_brain core.py "_realistic_api"
  fetch_brain panel.py "ThreadingHTTPServer"
  echo "✓ оновлено, перезапускаю"
  echo
done
