#!/bin/bash
set -u

INSTALL_BASE="$HOME/Library/Application Support/FP Scout"
INSTALL_DIR="$INSTALL_BASE/extension"
CONFIG_FILE="$INSTALL_BASE/install-info.json"

send_json() {
  /usr/bin/perl -e 'binmode STDOUT; my $s = $ARGV[0]; print pack("L<", length($s)); print $s;' "$1"
}

json_escape() {
  printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\r//g; s/\n/ /g'
}

fail() {
  local msg
  msg=$(json_escape "$1")
  send_json "{\"ok\":false,\"error\":\"$msg\"}"
  exit 0
}

read_message() {
  local len
  len=$(dd bs=4 count=1 2>/dev/null | od -An -t u4 | tr -d '[:space:]')
  [ -n "$len" ] || fail "Пустой запрос updater"
  [ "$len" -gt 0 ] || fail "Некорректная длина запроса"
  dd bs="$len" count=1 2>/dev/null
}

json_field() {
  local field="$1"
  printf '%s' "$PAYLOAD" \
    | sed -n "s/.*\"$field\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p" \
    | head -1 \
    | sed 's#\\/#/#g; s/\\"/"/g'
}

is_trusted_url() {
  case "$1" in
    https://fp-scout.ru/update/*.zip|https://fp-scout.ru/download/*.zip|https://api.fp-scout.ru/update/*.zip)
      return 0
      ;;
  esac
  return 1
}

cleanup_old_backups() {
  find "$INSTALL_BASE" -maxdepth 1 -type d -name 'extension.backup-*' -print 2>/dev/null \
    | sort -r \
    | tail -n +4 \
    | while IFS= read -r old_backup; do rm -rf "$old_backup"; done
}

PAYLOAD=$(read_message)
ACTION=$(json_field action)

if [ "$ACTION" = "ping" ]; then
  send_json '{"ok":true,"name":"ru.fpscout.updater","platform":"mac"}'
  exit 0
fi

[ "$ACTION" = "update" ] || fail "Неизвестное действие updater"

URL=$(json_field url)
EXPECTED_VERSION=$(json_field version)

[ -n "$URL" ] || fail "Не указан URL обновления"
is_trusted_url "$URL" || fail "Недоверенный URL обновления"
[ -d "$INSTALL_DIR" ] || fail "Папка расширения не найдена: $INSTALL_DIR"

TMP_DIR=$(mktemp -d "/tmp/fp-scout-update.XXXXXX") || fail "Не удалось создать временную папку"
ZIP_PATH="$TMP_DIR/update.zip"
NEW_DIR="$TMP_DIR/extension"

finish_with_error() {
  local msg="$1"
  rm -rf "$TMP_DIR"
  fail "$msg"
}

/usr/bin/curl -fL --connect-timeout 15 --max-time 180 "$URL" -o "$ZIP_PATH" >/dev/null 2>&1 \
  || finish_with_error "Не удалось скачать ZIP обновления"

ENTRIES=$(unzip -Z1 "$ZIP_PATH" 2>/dev/null) || finish_with_error "Архив обновления не читается"
printf '%s\n' "$ENTRIES" | grep -qx 'manifest.json' || finish_with_error "В архиве нет manifest.json"

while IFS= read -r entry; do
  [ -n "$entry" ] || continue
  case "$entry" in
    /*|*'..'*|*\\*) finish_with_error "Небезопасный путь в архиве: $entry" ;;
  esac
  case "$entry" in
    */|manifest.json|background.js|rules.json|src/*|icons/*|fonts/*|sounds/*)
      ;;
    *) finish_with_error "Лишний файл в архиве: $entry" ;;
  esac
done <<EOF
$ENTRIES
EOF

mkdir -p "$NEW_DIR" || finish_with_error "Не удалось подготовить папку обновления"
unzip -q "$ZIP_PATH" -d "$NEW_DIR" || finish_with_error "Не удалось распаковать ZIP обновления"

NEW_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "$NEW_DIR/manifest.json" | head -1 | sed 's/.*"\([^"]*\)"$/\1/')
[ -n "$NEW_VERSION" ] || finish_with_error "Не удалось прочитать версию из manifest.json"
if [ -n "$EXPECTED_VERSION" ] && [ "$NEW_VERSION" != "$EXPECTED_VERSION" ]; then
  finish_with_error "Версия архива $NEW_VERSION не совпадает с ожидаемой $EXPECTED_VERSION"
fi

BACKUP_DIR="$INSTALL_BASE/extension.backup-$(date -u +"%Y%m%d-%H%M%S")"
mv "$INSTALL_DIR" "$BACKUP_DIR" || finish_with_error "Не удалось создать backup текущей версии"
if ! mv "$NEW_DIR" "$INSTALL_DIR"; then
  rm -rf "$INSTALL_DIR"
  mv "$BACKUP_DIR" "$INSTALL_DIR" 2>/dev/null || true
  finish_with_error "Не удалось заменить папку расширения"
fi

cat > "$CONFIG_FILE" <<EOF
{
  "version": "$NEW_VERSION",
  "installedAt": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
  "installPath": "$INSTALL_DIR",
  "updatedBy": "native-host"
}
EOF

cleanup_old_backups
rm -rf "$TMP_DIR"
send_json "{\"ok\":true,\"version\":\"$NEW_VERSION\"}"
