#!/usr/bin/env sh
set -eu

REPO="${NEWDN_RELEASE_REPO:-DO-SAY-GO/newdn-releases}"
RELEASE_TAG="${NEWDN_RELEASE_TAG:-}"
ARTIFACT_LOCATION="${NEWDN_ARTIFACT:-}"
CHECKSUMS_LOCATION="${NEWDN_CHECKSUMS:-}"
PAGES_DOWNLOAD_BASE="${NEWDN_PAGES_DOWNLOAD_BASE:-https://trees.dosaygo.com/downloads}"
STATE_DIR="${NEWDN_STATE_DIR:-$HOME/.newdn}"
WRAPPER_PATH="$STATE_DIR/newdn-wrapper.sh"
RUNTIME_DIR="$STATE_DIR/runtime"
CHECK_FILE="$STATE_DIR/.last_update_check"
CADENCE="${NEWDN_UPDATE_CADENCE:-3600}"

log() {
  printf '%s\n' "$*"
}

die() {
  printf '%s\n' "$*" >&2
  exit 1
}

ensure_dir() {
  [ -d "$1" ] || mkdir -p "$1"
}

path_contains_dir() {
  case ":$PATH:" in
    *":$1:"*) return 0 ;;
    *) return 1 ;;
  esac
}

is_under_home() {
  case "$1" in
    "$HOME"/*) return 0 ;;
    *) return 1 ;;
  esac
}

dir_is_usable_without_sudo() {
  dir="$1"
  probe="$dir"
  while [ ! -d "$probe" ]; do
    next_probe=$(dirname "$probe")
    [ "$next_probe" != "$probe" ] || break
    probe="$next_probe"
  done
  [ -d "$probe" ] && [ -w "$probe" ]
}

choose_command_dir() {
  if [ -n "$ARTIFACT_LOCATION" ]; then
    old_ifs=$IFS
    IFS=:
    for dir in $PATH; do
      IFS=$old_ifs
      [ -n "$dir" ] || continue
      if dir_is_usable_without_sudo "$dir"; then
        printf '%s\n' "$dir"
        return 0
      fi
      IFS=:
    done
    IFS=$old_ifs
  fi

  for command_name in tree-grower tree-player; do
    existing=$(command -v "$command_name" 2>/dev/null || true)
    if [ -n "$existing" ]; then
      existing_dir=$(dirname "$existing")
      if path_contains_dir "$existing_dir" && dir_is_usable_without_sudo "$existing_dir"; then
        printf '%s\n' "$existing_dir"
        return 0
      fi
    fi
  done

  for dir in /usr/local/bin /opt/homebrew/bin "$HOME/.local/bin" "$HOME/bin" "$STATE_DIR/bin"; do
    if path_contains_dir "$dir" && dir_is_usable_without_sudo "$dir"; then
      printf '%s\n' "$dir"
      return 0
    fi
  done

  printf '%s\n' "$STATE_DIR/bin"
}

resolve_asset() {
  case "$(uname -s)" in
    Darwin) os="macos"; ext="zip" ;;
    Linux) os="linux"; ext="tar.gz" ;;
    *) die "unsupported OS: $(uname -s)" ;;
  esac
  case "$(uname -m)" in
    x86_64|amd64) arch="x64" ;;
    arm64|aarch64) arch="arm64" ;;
    *) die "unsupported architecture: $(uname -m)" ;;
  esac
  printf 'newdn-%s-%s.%s\n' "$os" "$arch" "$ext"
}

fetch_location() {
  location="$1"
  dest="$2"
  case "$location" in
    http://*|https://*) curl -fsSL "$location" -o "$dest" ;;
    *) cp "$location" "$dest" ;;
  esac
}

write_runtime_wrapper() {
  ensure_dir "$STATE_DIR"
  ensure_dir "$RUNTIME_DIR"
  cat > "$WRAPPER_PATH" <<'EOF'
#!/usr/bin/env sh
set -eu

REPO="${NEWDN_RELEASE_REPO:-DO-SAY-GO/newdn-releases}"
RELEASE_TAG="${NEWDN_RELEASE_TAG:-}"
ARTIFACT_LOCATION="${NEWDN_ARTIFACT:-}"
CHECKSUMS_LOCATION="${NEWDN_CHECKSUMS:-}"
PAGES_DOWNLOAD_BASE="${NEWDN_PAGES_DOWNLOAD_BASE:-https://trees.dosaygo.com/downloads}"
STATE_DIR="${NEWDN_STATE_DIR:-$HOME/.newdn}"
RUNTIME_DIR="$STATE_DIR/runtime"
CHECK_FILE="$STATE_DIR/.last_update_check"
CADENCE="${NEWDN_UPDATE_CADENCE:-3600}"

die() {
  printf '%s\n' "$*" >&2
  exit 1
}

log() {
  printf '%s\n' "$*"
}

resolve_asset() {
  case "$(uname -s)" in
    Darwin) os="macos"; ext="zip" ;;
    Linux) os="linux"; ext="tar.gz" ;;
    *) die "unsupported OS: $(uname -s)" ;;
  esac
  case "$(uname -m)" in
    x86_64|amd64) arch="x64" ;;
    arm64|aarch64) arch="arm64" ;;
    *) die "unsupported architecture: $(uname -m)" ;;
  esac
  printf 'newdn-%s-%s.%s\n' "$os" "$arch" "$ext"
}

should_update() {
  [ -n "$ARTIFACT_LOCATION" ] && return 0
  [ -x "$RUNTIME_DIR/tree-grower" ] && [ -x "$RUNTIME_DIR/tree-player" ] || return 0
  [ -f "$CHECK_FILE" ] || return 0
  last_check=$(cat "$CHECK_FILE" 2>/dev/null || printf '0')
  case "$last_check" in
    ''|*[!0-9]*) return 0 ;;
  esac
  now=$(date +%s)
  [ $((now - last_check)) -ge "$CADENCE" ]
}

fetch_location() {
  location="$1"
  dest="$2"
  case "$location" in
    http://*|https://*) curl -fsSL "$location" -o "$dest" ;;
    *) cp "$location" "$dest" ;;
  esac
}

fetch_with_fallback() {
  primary="$1"
  fallback="$2"
  dest="$3"
  if fetch_location "$primary" "$dest"; then
    return 0
  fi
  [ -n "$fallback" ] || return 1
  fetch_location "$fallback" "$dest"
}

sha256_hex() {
  if command -v shasum >/dev/null 2>&1; then
    shasum -a 256 "$1" | awk '{print $1}'
  elif command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$1" | awk '{print $1}'
  else
    die "Need shasum or sha256sum to verify downloads"
  fi
}

download_and_install() {
  asset=$(resolve_asset)
  release_path="latest/download"
  if [ -n "$RELEASE_TAG" ]; then
    release_path="download/${RELEASE_TAG}"
  fi

  if [ -n "$ARTIFACT_LOCATION" ]; then
    artifact_primary="$ARTIFACT_LOCATION"
    artifact_fallback=""
  elif [ -z "$RELEASE_TAG" ]; then
    artifact_primary="$PAGES_DOWNLOAD_BASE/$asset"
    artifact_fallback="https://github.com/$REPO/releases/latest/download/$asset"
  else
    artifact_primary="https://github.com/$REPO/releases/$release_path/$asset"
    artifact_fallback=""
  fi

  if [ -n "$CHECKSUMS_LOCATION" ]; then
    checksums_primary="$CHECKSUMS_LOCATION"
    checksums_fallback=""
  elif [ -z "$RELEASE_TAG" ]; then
    checksums_primary="$PAGES_DOWNLOAD_BASE/SHA256SUMS.txt"
    checksums_fallback="https://github.com/$REPO/releases/latest/download/SHA256SUMS.txt"
  else
    checksums_primary="https://github.com/$REPO/releases/$release_path/SHA256SUMS.txt"
    checksums_fallback=""
  fi

  tmp=$(mktemp -d)
  trap 'rm -rf "$tmp"' EXIT INT HUP TERM
  log "Checking for Newdn updates..."
  fetch_with_fallback "$artifact_primary" "$artifact_fallback" "$tmp/$asset" || die "Could not fetch $asset"
  fetch_with_fallback "$checksums_primary" "$checksums_fallback" "$tmp/SHA256SUMS.txt" || die "Could not fetch SHA256SUMS.txt"

  expected=$(grep "  ${asset}$" "$tmp/SHA256SUMS.txt" | awk '{print $1}' || true)
  [ -n "$expected" ] || die "Missing checksum entry for $asset"
  actual=$(sha256_hex "$tmp/$asset")
  [ "$expected" = "$actual" ] || die "Checksum verification failed for $asset"

  case "$asset" in
    *.tar.gz) tar -xzf "$tmp/$asset" -C "$tmp" ;;
    *.zip)
      command -v unzip >/dev/null 2>&1 || die "unzip is required to extract $asset"
      unzip -q "$tmp/$asset" -d "$tmp"
      ;;
  esac

  grower="$tmp/tree-grower"
  player="$tmp/tree-player"
  [ -f "$grower" ] || die "Archive is missing top-level tree-grower"
  [ -f "$player" ] || die "Archive is missing top-level tree-player"
  mkdir -p "$RUNTIME_DIR"
  install -m 755 "$grower" "$RUNTIME_DIR/tree-grower"
  install -m 755 "$player" "$RUNTIME_DIR/tree-player"
  date +%s > "$CHECK_FILE"
}

if should_update; then
  download_and_install
fi

if [ "${NEWDN_INSTALL_ONLY:-0}" = "1" ]; then
  log "Newdn payloads are ready in $RUNTIME_DIR"
  exit 0
fi

case "${1:-}" in
  tree-grower|tree-player)
    command_name="$1"
    shift
    ;;
  *)
    command_name=$(basename "$0")
    ;;
esac
payload="$RUNTIME_DIR/$command_name"
[ -x "$payload" ] || die "$command_name is not installed. Re-run the installer."
exec "$payload" "$@"
EOF
  chmod 755 "$WRAPPER_PATH"
}

write_command_shim() {
  shim_path="$1"
  command_name="$2"
  cat > "$shim_path" <<EOF
#!/usr/bin/env sh
set -eu
STATE_DIR="\${NEWDN_STATE_DIR:-\$HOME/.newdn}"
exec "\$STATE_DIR/newdn-wrapper.sh" "$command_name" "\$@"
EOF
  chmod 755 "$shim_path"
}

main() {
  command -v curl >/dev/null 2>&1 || die "curl is required"
  command -v tar >/dev/null 2>&1 || die "tar is required"
  ensure_dir "$STATE_DIR"
  write_runtime_wrapper

  target_dir=$(choose_command_dir)
  ensure_dir "$target_dir"
  tmp=$(mktemp -d)
  trap 'rm -rf "$tmp"' EXIT INT HUP TERM

  for command_name in tree-grower tree-player; do
    shim_path="$tmp/$command_name"
    write_command_shim "$shim_path" "$command_name"
    install -m 755 "$shim_path" "$target_dir/$command_name"
  done

  NEWDN_INSTALL_ONLY=1 "$WRAPPER_PATH"
  log "Installed Newdn commands to $target_dir"
  log "Newdn wrapper: $WRAPPER_PATH"
  log "Newdn runtime: $RUNTIME_DIR"
}

main "$@"
