#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
APP="${SLOWCRAFT_APP_DIR:-/opt/slowcraft-post}"
if [[ -n "${SLOWCRAFT_HOME:-}" ]]; then
  DATA="$SLOWCRAFT_HOME"
elif [[ -d "${XDG_DATA_HOME:-$HOME/.local/share}/slowcraft-post" ]]; then
  DATA="${XDG_DATA_HOME:-$HOME/.local/share}/slowcraft-post"
elif [[ -d "$HOME/.slowcraft" ]]; then
  DATA="$HOME/.slowcraft"
else
  DATA="${XDG_DATA_HOME:-$HOME/.local/share}/slowcraft-post"
fi
PID=''
notice() {
  printf '%s\n' "$1" >&2
  if [[ -z "${SLOWCRAFT_NO_DIALOG:-}" && ( -n "${DISPLAY:-}" || -n "${WAYLAND_DISPLAY:-}" ) ]]; then
    if command -v zenity >/dev/null 2>&1; then
      zenity --error --title='SlowCraft POST' --text="$1" >/dev/null 2>&1 || true
    elif command -v xmessage >/dev/null 2>&1; then
      xmessage -center -title 'SlowCraft POST' "$1" >/dev/null 2>&1 || true
    fi
  fi
}
fail() { notice "$1"; exit 1; }
stop_backend() { if [[ -n "$PID" ]]; then kill "$PID" 2>/dev/null || true; wait "$PID" 2>/dev/null || true; fi; }
unexpected() { local code=$?; trap - ERR; stop_backend; notice "Не удалось запустить SlowCraft (код $code). Журнал: $DATA/launcher/logs/linux-launcher.log"; exit "$code"; }
trap unexpected ERR
trap 'stop_backend; exit 130' INT TERM
[[ "$DATA" = /* ]] || fail 'Папка данных должна иметь абсолютный путь.'
[[ "$(uname -m)" == x86_64 ]] || fail 'Для этой сборки нужен Linux x86_64 (amd64).'
mkdir -p "$DATA/launcher/logs" "$DATA/natives" "$DATA/seed/versions/0.0.6" "$DATA/music/tracks" "$DATA/skins"
LOG="$DATA/launcher/logs/linux-launcher.log"
mode="${1:-}"
case "$mode" in ''|--prepare-only|--diagnose|--game|--swing|--web-url) ;; *) fail 'Использование: slowcraft-post [--diagnose|--prepare-only|--game|--swing|--web-url]' ;; esac
open_browser() {
  local url="$1" browser
  if command -v xdg-open >/dev/null 2>&1 && xdg-open "$url" >/dev/null 2>&1; then return 0; fi
  if command -v gio >/dev/null 2>&1 && gio open "$url" >/dev/null 2>&1; then return 0; fi
  for browser in firefox chromium chromium-browser google-chrome microsoft-edge brave-browser; do
    if command -v "$browser" >/dev/null 2>&1; then "$browser" "$url" >/dev/null 2>&1 & return 0; fi
  done
  return 1
}
# Reopening a running launcher brings back its existing UI instead of failing on its lock.
if [[ -z "$mode" && -f "$DATA/launcher/ui.pid" && -f "$LOG" ]]; then
  old_pid=$(cat "$DATA/launcher/ui.pid")
  if [[ "$old_pid" =~ ^[0-9]+$ ]] && kill -0 "$old_pid" 2>/dev/null; then
    old_url=$(sed -nE 's@^SLOWCRAFT_UI=(http://127\.0\.0\.1:[0-9]+/[a-f0-9]{32}/).*@\1@p' "$LOG" | head -n 1)
    if [[ -n "$old_url" ]] && open_browser "$old_url"; then exit 0; fi
    fail "Лаунчер уже работает. Его адрес: $old_url"
  fi
fi
JAVA=''
usable_java() {
  local candidate="$1" version
  [[ -x "$candidate" ]] || return 1
  version=$("$candidate" -XshowSettings:properties -version 2>&1 | sed -n 's/^[[:space:]]*java.specification.version = //p' | head -n 1) || return 1
  [[ "$version" =~ ^[0-9]+$ ]] && (( version >= 21 )) || return 1
  JAVA="$candidate"
}
choose_java() {
  local candidate
  for candidate in "${SLOWCRAFT_JAVA:-}" "$DATA/runtime/bin/java" "$APP/runtime/bin/java" "${JAVA_HOME:-/no-java-home}/bin/java" "$(command -v java || true)"; do
    if [[ -n "$candidate" ]] && usable_java "$candidate"; then return 0; fi
  done
  shopt -s nullglob
  for candidate in /usr/lib/jvm/*/bin/java /opt/java/*/bin/java; do
    if usable_java "$candidate"; then shopt -u nullglob; return 0; fi
  done
  shopt -u nullglob
  return 1
}
property() { sed -n "s/^$1=//p" "$APP/runtime-linux.properties" | head -n 1; }
download_runtime() {
  local url expected staging archive actual candidate progress=''
  [[ -f "$APP/runtime-linux.properties" ]] || fail 'Не найден список файлов Java. Распакуй portable целиком или переустанови пакет.'
  url=$(property url); expected=$(property sha256)
  [[ "$url" == https://github.com/adoptium/temurin21-binaries/releases/download/* && "$expected" =~ ^[a-f0-9]{64}$ ]] || fail 'Неверный список файлов Java.'
  printf '%s\n' 'Подготавливаем Java 21 для SlowCraft…' >&2
  staging=$(mktemp -d "$DATA/runtime-stage.XXXXXX"); archive="$staging/java.tar.gz"
  if [[ -z "${SLOWCRAFT_NO_DIALOG:-}" && ( -n "${DISPLAY:-}" || -n "${WAYLAND_DISPLAY:-}" ) ]] && command -v zenity >/dev/null 2>&1; then
    zenity --progress --pulsate --no-cancel --auto-close --title='SlowCraft POST' --text='Подготавливаем Java 21. При первом запуске нужен интернет.' < <(while :; do echo '#Загружаем Java 21…'; sleep 2; done) >/dev/null 2>&1 & progress=$!
  fi
  local downloaded=0
  if command -v curl >/dev/null 2>&1; then
    if curl --fail --location --retry 2 --connect-timeout 20 --output "$archive" "$url" >>"$LOG" 2>&1; then downloaded=1; fi
  elif command -v wget >/dev/null 2>&1; then
    if wget --timeout=60 --tries=2 --output-document="$archive" "$url" >>"$LOG" 2>&1; then downloaded=1; fi
  elif command -v python3 >/dev/null 2>&1; then
    if python3 - "$url" "$archive" >>"$LOG" 2>&1 <<'PY'
import sys,urllib.request,shutil
with urllib.request.urlopen(sys.argv[1],timeout=60) as source,open(sys.argv[2],'wb') as target:
    shutil.copyfileobj(source,target,1024*1024)
PY
    then downloaded=1; fi
  fi
  if [[ -n "$progress" ]]; then kill "$progress" 2>/dev/null || true; wait "$progress" 2>/dev/null || true; fi
  if (( downloaded == 0 )); then rm -rf -- "$staging"; fail "Не удалось загрузить Java 21. Проверь интернет или установи Java 21+. Журнал: $LOG"; fi
  actual=$(sha256sum "$archive" | cut -d' ' -f1)
  if [[ "$actual" != "$expected" ]]; then rm -rf -- "$staging"; fail 'Проверка Java не пройдена. Запусти лаунчер ещё раз.'; fi
  tar -xzf "$archive" -C "$staging"
  candidate=$(find "$staging" -mindepth 3 -maxdepth 3 -type f -path '*/bin/java' -print -quit)
  if [[ -z "$candidate" ]] || ! usable_java "$candidate"; then rm -rf -- "$staging"; fail 'Архив Java не подходит для этой системы.'; fi
  local unpacked="${candidate%/bin/java}"
  if [[ -e "$DATA/runtime" ]]; then mv "$DATA/runtime" "$DATA/runtime-backup-$(date +%s)-$$"; fi
  mv "$unpacked" "$DATA/runtime"; rm -rf -- "$staging"; JAVA="$DATA/runtime/bin/java"
}
if ! choose_java; then download_runtime; fi
copy_managed() {
  local source="$1" target="$2" temporary
  mkdir -p "$(dirname "$target")"
  if [[ -f "$target" ]] && cmp -s "$source" "$target"; then return 0; fi
  temporary=$(mktemp "${target}.XXXXXX")
  if ! cp "$source" "$temporary" || ! mv -f "$temporary" "$target"; then rm -f "$temporary"; return 1; fi
}
copy_managed "$APP/launcher.jar" "$DATA/launcher.jar"
while IFS= read -r -d '' source; do copy_managed "$source" "$DATA/${source#"$APP/"}"; done < <(find "$APP/launcher" "$APP/seed" -type f -print0)
for filename in liblwjgl.so libglfw.so liblwjgl_opengl.so; do
  expected=$(awk -v f="$filename" '$2==f {print $1}' "$APP/natives/SHA256SUMS")
  actual=$(sha256sum "$APP/natives/$filename" | cut -d' ' -f1)
  [[ -n "$expected" && "$actual" == "$expected" ]] || fail "Повреждена библиотека $filename. Переустанови пакет."
  copy_managed "$APP/natives/$filename" "$DATA/natives/$filename"
done
export SLOWCRAFT_HOME="$DATA"
export LD_LIBRARY_PATH="$DATA/natives${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
if ! "$JAVA" -Djava.awt.headless=true -Dfile.encoding=UTF-8 "-Dslowcraft.assets=$DATA" -jar "$DATA/launcher.jar" --home "$DATA" --prepare-only >>"$LOG" 2>&1; then fail "Не удалось подготовить игру. Журнал: $LOG"; fi
case "$mode" in
  --prepare-only) echo 'Slowcraft prepared'; exit 0 ;;
  --diagnose)
    "$JAVA" -version
    native_status=0
    "$JAVA" "-Dorg.lwjgl.librarypath=$DATA/natives" -cp "$DATA/versions/0.0.6/game.jar" slowcraft.PostDiagnostics || native_status=1
    "$JAVA" -Djava.awt.headless=true "-Dslowcraft.assets=$APP" -cp "$APP/launcher/launcher-1.00.1.jar" slowcraft.launcher.PostHealth "$DATA" || native_status=1
    exit "$native_status" ;;
  --game)
    mkdir -p "$DATA/versions/0.0.6/data"; cd "$DATA/versions/0.0.6/data"
    exec "$JAVA" -Dfile.encoding=UTF-8 "-Dslowcraft.home=$DATA" "-Dslowcraft.assets=$DATA" "-Dorg.lwjgl.librarypath=$DATA/natives" -jar ../game.jar ;;
  --swing) exec "$JAVA" -Dfile.encoding=UTF-8 "-Dslowcraft.assets=$DATA" -jar "$DATA/launcher.jar" --home "$DATA" --swing ;;
esac
"$JAVA" -Djava.awt.headless=true -Dfile.encoding=UTF-8 "-Dslowcraft.assets=$DATA" -jar "$DATA/launcher.jar" --home "$DATA" --web-preview >"$LOG" 2>&1 &
PID=$!; printf '%s\n' "$PID" >"$DATA/launcher/ui.pid"
URL=''
for ((i=0;i<150;i++)); do
  URL=$(sed -nE 's@^SLOWCRAFT_UI=(http://127\.0\.0\.1:[0-9]+/[a-f0-9]{32}/).*@\1@p' "$LOG" | head -n 1)
  [[ -z "$URL" ]] || break
  kill -0 "$PID" 2>/dev/null || break
  sleep 0.2
done
if [[ -z "$URL" ]]; then stop_backend; fail "Не удалось открыть лаунчер. Журнал: $LOG"; fi
if [[ "$mode" == --web-url ]]; then
  printf 'SLOWCRAFT_UI=%s\n' "$URL"
elif ! open_browser "$URL"; then
  if [[ -n "${DISPLAY:-}" || -n "${WAYLAND_DISPLAY:-}" ]]; then
    stop_backend; PID=''
    printf '%s\n' 'Браузер не открылся. Запускаем резервное окно лаунчера.' >>"$LOG"
    exec "$JAVA" -Dfile.encoding=UTF-8 "-Dslowcraft.assets=$DATA" -jar "$DATA/launcher.jar" --home "$DATA" --swing >>"$LOG" 2>&1
  else
    printf 'Открой лаунчер в браузере: %s\n' "$URL"
  fi
fi
status=0; wait "$PID" || status=$?
rm -f "$DATA/launcher/ui.pid"
if (( status != 0 )); then fail "Лаунчер завершился с ошибкой. Журнал: $LOG"; fi
