#!/usr/bin/env nix-shell
#!nix-shell -i ysh -p common-updater-scripts -p coreutils -p curl -p oils-for-unix

source $LIB_YSH/args.ysh

proc usage {
  echo "USAGE: addon-version-lister [--max-versions N] [-v] [-vv] --old-version SEMVER URL"
  echo ""
  echo "--max-versions N  (default: 10)"
  echo "  only show up to this many of the most recent valid versions."
  echo "  the lower this value, the faster this script will complete."
  echo "  many use cases can set this to '1'."
  echo ""
  echo "-v --verbose: more logging"
  echo ""
  echo "-vv --really-verbose: even more logging"
  echo ""
  echo "--old-version SEMVER"
  echo "  version which yielded the provided url, used to recognize how the URL needs to be updated per version."
  echo ""
  echo "URL"
  echo "  URL at which to expect a .xpi file."
  echo "  combined with '--old-version', this is treated as a template for discovering newer versions."
}

parser (&spec) {
  flag "" --max-versions (Int, default=10)
  flag -v --verbose (Bool, default=false)
  flag -vv --really-verbose (Bool, default=false)
  flag "" --old-version (Str)
  flag -h --help (Bool, default=false)
  arg url
}

func numeric_version (tag) {
  # TODO: consider `b<n>` or `rc<n>` suffixes?
  return ($(echo "$tag" | egrep --only-matching "[0-9.]+" | head -n1))
}

func sort_versions (versions) {
  var numerics = []
  for v in (versions) {
    var row = [numeric_version(v), v] => join(" ")
    call numerics->append (row)
  }
  var lines = numerics => join($'\n')
  var sorted = $(echo "$lines" | sort --version-sort --reverse | cut -d" " -f 2)
  return (sorted => split ($'\n'))
}

proc log (; ...stmts; level, context) {
  for s in (stmts) {
    var prefix = " $context:" if context else ""
    var formatted = "$(pp value (s))"
    echo "[$level]$prefix $formatted" >&2
  }
}

proc info (context=""; ...stmts) {
  log (level="INFO", context=context, ...stmts)
}

proc debug (context=""; ...stmts) {
  if (VERBOSE) {
    log (level="DEBUG", context=context, ...stmts)
  }
}

var CURL_FLAGS = []

try {
  var args = parseArgs(spec, ARGV)
}
if failed {
  usage
  exit 1
}

var MAX_VERSIONS = args['max-versions']
var OLD_VERSION = args['old-version']
var URL = args.url
var VERBOSE = args.verbose or args['really-verbose']

if (args['really-verbose']) {
  call CURL_FLAGS->append("--verbose")
}

debug "invoked" (ARGV)

if (args.help) {
  usage
  exit 0
}

# we need the bare git URL.
# strip `https://github.com/OWNER/NAME/releases/download/...` -> `https://github.com/OWNER/NAME`
var repo_url = URL.replace(/ '/releases/' .* $ /, "")
debug "extracted" (repo_url)

var all_tags = $(list-git-tags --url="$repo_url") => split($'\n')
debug "extracted tags" (all_tags)
setvar all_tags = sort_versions (all_tags)
debug "sorted tags" (all_tags)

# # filter to the versions for which we can actually download an artifact.
# # some packages (uBlock) publish releases even before all artifacts are available.
var online_versions = []

for v in (all_tags) {
  var url_to_test = URL => replace (OLD_VERSION, v);
  debug "testing url" (url_to_test)
  if curl @CURL_FLAGS --fail "$url_to_test" {
    info "found online tag" (v)
    call online_versions -> append (v)
    if (len(online_versions) >= MAX_VERSIONS) {
      break
    }
  }
}

var pretty_versions = online_versions => join(" ")
echo "$pretty_versions"
