#!/usr/bin/env bash
# نصب و راه‌اندازی کامل آموزش مدل دسته‌بندی زنبیل.
#
#   curl -fsSL http://38.54.13.36:8000/bootstrap.sh | bash
#
# همه چیز را از VPS آلمان می‌گیرد، وابستگی‌ها را نصب می‌کند، و آموزش را زیر
# systemd می‌گذارد -- پس قطع شدن ssh، بستن ترمینال یا حتی ریبوت سرور کار را
# متوقف نمی‌کند و از همان‌جا ادامه می‌دهد.
set -euo pipefail

SRC="${SRC:-http://38.54.13.36:8000}"
DATA="${DATA:-/data/zambil}"
SERVICE=zambil-train

say() { printf '\n\033[1m== %s\033[0m\n' "$*"; }

say "بررسی محیط"
echo "  $(. /etc/os-release && echo "$PRETTY_NAME")  kernel $(uname -r)"
echo "  cpu=$(nproc)  ram=$(free -g | awk '/^Mem:/{print $2}')GB  disk_free=$(df -h / | awk 'NR==2{print $4}')"
if command -v nvidia-smi >/dev/null 2>&1; then
  nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader | sed 's/^/  GPU: /'
else
  echo "  !! nvidia-smi نیست — بدون GPU این کار روزها طول می‌کشد."
  echo "     اگر کارت داری ولی درایور نصب نیست، اول درایور را نصب کن."
  exit 2
fi

say "تست دسترسی شبکه (هر دو لازم است)"
hf_ok=0; sh_ok=0
if curl -fsS --max-time 20 -o /dev/null -w '' https://huggingface.co/api/models/BAAI/bge-m3 2>/dev/null; then
  echo "  HuggingFace  : در دسترس"; hf_ok=1
else
  echo "  HuggingFace  : در دسترس نیست"
fi
if curl -fsS --max-time 20 -o /dev/null "$SRC/shards/shard_00000.tar" 2>/dev/null; then
  echo "  سرور شاردها  : در دسترس"; sh_ok=1
else
  echo "  سرور شاردها  : در دسترس نیست ($SRC)"
fi
[ "$sh_ok" = 1 ] || { echo "  بدون شاردها نمی‌شود ادامه داد."; exit 3; }
if [ "$hf_ok" = 0 ]; then
  echo "  وزن مدل‌ها از HuggingFace نمی‌آید. آینه را از همان سرور شاردها می‌گیرم."
  export HF_ENDPOINT="$SRC/hf"
fi

say "نصب وابستگی‌ها"
export DEBIAN_FRONTEND=noninteractive
apt-get -qq update >/dev/null 2>&1 || true
apt-get -qq install -y python3-pip python3-venv curl >/dev/null 2>&1 || true
python3 -m venv /opt/zambil-venv 2>/dev/null || true
V=/opt/zambil-venv/bin
$V/pip install -q -U pip >/dev/null
# torch اگر از قبل با CUDA هست، دست نزن: نصب دوباره ۲.۵ گیگ دانلود بی‌فایده است
if ! $V/python -c 'import torch,sys; sys.exit(0 if torch.cuda.is_available() else 1)' 2>/dev/null; then
  echo "  نصب torch (cu121) ..."
  $V/pip install -q torch --index-url https://download.pytorch.org/whl/cu121
fi
$V/pip install -q 'transformers>=4.46,<5' sentencepiece pillow requests numpy
$V/python -c 'import torch,transformers;print("  torch",torch.__version__,"cuda",torch.cuda.is_available(),"| transformers",transformers.__version__)'

say "گرفتن داده‌ها"
mkdir -p "$DATA"
for f in bsl_train.csv bsl_holdout.csv bsl_img_labels.csv bsl_img_titles.csv.gz \
         bsl_classes.json zambil_train.csv zambil_testset200.csv \
         zambil_testset200_images.zip train_local.py; do
  if [ ! -s "$DATA/$f" ]; then
    echo "  $f"
    curl -fsS --max-time 900 -o "$DATA/$f.part" "$SRC/data/$f"
    mv "$DATA/$f.part" "$DATA/$f"
  fi
done
ls -la "$DATA" | tail -n +2 | awk '{printf "  %-34s %8.1f MB\n", $9, $5/1048576}'

say "ساخت سرویس systemd"
cat > /etc/systemd/system/$SERVICE.service <<UNIT
[Unit]
Description=Zambil category model training
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=$DATA
# ازسرگیری داخل خود اسکریپت است: هر مرحله چک‌پوینت دارد، پس ری‌استارت
# یعنی ادامه از همان‌جا، نه شروع دوباره.
ExecStart=$V/python $DATA/train_local.py --data $DATA --shards $SRC/shards
Restart=on-failure
RestartSec=30
StandardOutput=append:$DATA/train.log
StandardError=append:$DATA/train.log
TimeoutStopSec=60
Environment=PYTHONUNBUFFERED=1
Environment=HF_HOME=$DATA/hf
${HF_ENDPOINT:+Environment=HF_ENDPOINT=$HF_ENDPOINT}

[Install]
WantedBy=multi-user.target
UNIT

systemctl daemon-reload
systemctl enable --now $SERVICE
sleep 6

say "وضعیت"
systemctl --no-pager -l status $SERVICE | head -8 || true
echo
echo "  پیشرفت      : tail -f $DATA/train.log"
echo "  وضعیت       : systemctl status $SERVICE"
echo "  توقف        : systemctl stop $SERVICE"
echo "  خروجی نهایی : $DATA/out/zambil_category_bsl.npz"
echo "                $DATA/out/zambil_title_index.npz"
echo "                $DATA/out/result.json"
