#!/usr/bin/env bash
# gxpm-update-check — periodic remote version check.
#
# Output (one line, or nothing):
#   JUST_UPGRADED <old> <new>
#   UPGRADE_AVAILABLE <old> <new>
#   (nothing)
#
# Env overrides:
#   GXPM_DIR         — override gxpm install root
#   GXPM_REMOTE_URL  — override remote package.json URL
#   GXPM_STATE_DIR   — override ~/.gxpm state directory
#
# GXPM-173: both local and remote versions are read from package.json
# (single source of truth). The legacy $GXPM_DIR/VERSION file was removed
# in 0.2.0; we still fall back to it for the duration of one release cycle
# so older installs keep getting update notifications.
set -euo pipefail

if [ -z "${GXPM_DIR:-}" ]; then
  SOURCE="${BASH_SOURCE[0]}"
  while [ -L "$SOURCE" ]; do
    TARGET="$(readlink "$SOURCE")"
    if [[ "$TARGET" = /* ]]; then
      SOURCE="$TARGET"
    else
      SOURCE="$(cd -P "$(dirname "$SOURCE")" && pwd)/$TARGET"
    fi
  done
  GXPM_DIR="$(cd -P "$(dirname "$SOURCE")/.." && pwd)"
fi
STATE_DIR="${GXPM_STATE_DIR:-$HOME/.gxpm}"
CACHE_FILE="$STATE_DIR/last-update-check"
MARKER_FILE="$STATE_DIR/just-upgraded-from"
SNOOZE_FILE="$STATE_DIR/update-snoozed"
PACKAGE_JSON="$GXPM_DIR/package.json"
LEGACY_VERSION_FILE="$GXPM_DIR/VERSION"
REMOTE_URL="${GXPM_REMOTE_URL:-https://raw.githubusercontent.com/laozhong86/gxpm/main/package.json}"

read_local_version() {
  if [ -f "$PACKAGE_JSON" ]; then
    sed -n 's/^[[:space:]]*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*$/\1/p' "$PACKAGE_JSON" \
      | head -n 1 \
      | tr -d '[:space:]'
    return
  fi
  if [ -f "$LEGACY_VERSION_FILE" ]; then
    cat "$LEGACY_VERSION_FILE" 2>/dev/null | tr -d '[:space:]'
  fi
}

extract_version_from_payload() {
  # Accepts either a raw version string (legacy VERSION file content) or a
  # JSON blob (package.json) and emits the version. Tolerates both for
  # backward compatibility with custom GXPM_REMOTE_URL overrides.
  local payload="$1"
  local from_json
  from_json="$(printf '%s' "$payload" | sed -n 's/^[[:space:]]*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*$/\1/p' | head -n 1 | tr -d '[:space:]')"
  if [ -n "$from_json" ]; then
    printf '%s' "$from_json"
    return
  fi
  printf '%s' "$payload" | tr -d '[:space:]'
}

FORCE=0
if [ "${1:-}" = "--force" ]; then
  FORCE=1
  rm -f "$CACHE_FILE"
  rm -f "$SNOOZE_FILE"
fi

CONFIG_VALUE="$("$GXPM_DIR/bin/gxpm" config get update_check --raw 2>/dev/null || true)"
if [ "$CONFIG_VALUE" = "false" ]; then
  exit 0
fi

check_snooze() {
  local remote_ver="$1"
  if [ ! -f "$SNOOZE_FILE" ]; then
    return 1
  fi

  local snoozed_ver snoozed_level snoozed_epoch
  snoozed_ver="$(awk '{print $1}' "$SNOOZE_FILE" 2>/dev/null || true)"
  snoozed_level="$(awk '{print $2}' "$SNOOZE_FILE" 2>/dev/null || true)"
  snoozed_epoch="$(awk '{print $3}' "$SNOOZE_FILE" 2>/dev/null || true)"

  if [ -z "$snoozed_ver" ] || [ -z "$snoozed_level" ] || [ -z "$snoozed_epoch" ]; then
    return 1
  fi
  case "$snoozed_level" in *[!0-9]*) return 1 ;; esac
  case "$snoozed_epoch" in *[!0-9]*) return 1 ;; esac

  if [ "$snoozed_ver" != "$remote_ver" ]; then
    return 1
  fi

  local duration
  case "$snoozed_level" in
    1) duration=86400 ;;
    2) duration=172800 ;;
    *) duration=604800 ;;
  esac

  local now expires
  now="$(date +%s)"
  expires=$((snoozed_epoch + duration))
  if [ "$now" -lt "$expires" ]; then
    return 0
  fi

  return 1
}

fetch_remote_version() {
  case "$REMOTE_URL" in
    file://*)
      cat "${REMOTE_URL#file://}" 2>/dev/null || true
      ;;
    /*|./*|../*)
      cat "$REMOTE_URL" 2>/dev/null || true
      ;;
    *)
      curl -sf --max-time 5 "$REMOTE_URL" 2>/dev/null || true
      ;;
  esac
}

LOCAL="$(read_local_version)"
if [ -z "$LOCAL" ]; then
  exit 0
fi

if [ -f "$MARKER_FILE" ]; then
  OLD="$(cat "$MARKER_FILE" 2>/dev/null | tr -d '[:space:]')"
  rm -f "$MARKER_FILE"
  rm -f "$SNOOZE_FILE"
  if [ -n "$OLD" ]; then
    echo "JUST_UPGRADED $OLD $LOCAL"
  fi
fi

if [ "$FORCE" -eq 0 ] && [ -f "$CACHE_FILE" ]; then
  CACHED="$(cat "$CACHE_FILE" 2>/dev/null || true)"
  case "$CACHED" in
    UP_TO_DATE*) CACHE_TTL=60 ;;
    UPGRADE_AVAILABLE*) CACHE_TTL=720 ;;
    *) CACHE_TTL=0 ;;
  esac

  STALE=$(find "$CACHE_FILE" -mmin +"$CACHE_TTL" 2>/dev/null || true)
  if [ -z "$STALE" ] && [ "$CACHE_TTL" -gt 0 ]; then
    case "$CACHED" in
      UP_TO_DATE*)
        CACHED_VER="$(echo "$CACHED" | awk '{print $2}')"
        if [ "$CACHED_VER" = "$LOCAL" ]; then
          exit 0
        fi
        ;;
      UPGRADE_AVAILABLE*)
        CACHED_OLD="$(echo "$CACHED" | awk '{print $2}')"
        if [ "$CACHED_OLD" = "$LOCAL" ]; then
          CACHED_NEW="$(echo "$CACHED" | awk '{print $3}')"
          if check_snooze "$CACHED_NEW"; then
            exit 0
          fi
          echo "$CACHED"
          exit 0
        fi
        ;;
    esac
  fi
fi

mkdir -p "$STATE_DIR"
REMOTE_RAW="$(fetch_remote_version)"
REMOTE="$(extract_version_from_payload "$REMOTE_RAW")"

# GXPM-173: semver-shape gate. Mirrors the strict pattern in scripts/version.ts
# so a malformed remote payload (e.g. `1.4`, `01.2.3`) can't emit a bogus
# UPGRADE_AVAILABLE notification.
if ! echo "$REMOTE" | grep -qE '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$'; then
  echo "UP_TO_DATE $LOCAL" > "$CACHE_FILE"
  exit 0
fi

if [ "$LOCAL" = "$REMOTE" ]; then
  echo "UP_TO_DATE $LOCAL" > "$CACHE_FILE"
  exit 0
fi

echo "UPGRADE_AVAILABLE $LOCAL $REMOTE" > "$CACHE_FILE"
if check_snooze "$REMOTE"; then
  exit 0
fi

echo "UPGRADE_AVAILABLE $LOCAL $REMOTE"
