#!/usr/bin/env bash
# vim:et:ts=2:sts=2:sw=2

# Get absolute repository root (especially when symlinked)
ROOT="$(realpath "$(dirname "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")")")"

# Load accompanying bash library
source "$ROOT/lib/lib.bash"

NAME="$1"

SUBJECT=""
REMOTE=""
DIR=""
REMOTE_PATH_PART=""
TYPE="f"

# Determine paths and arguments based on component type
if [ "$NAME" = "curriculum" ]; then
  SUBJECT="$2"
  REMOTE="$3"

  if [ -z "$SUBJECT" ]; then
    err "A subject must be specified for the curriculum component."
  fi

  DIR="${COMP_DIR:-/srv}/curriculum/$SUBJECT"
  REMOTE_PATH_PART="curriculum/$SUBJECT"
else
  REMOTE="$2"
  DIR="${COMP_DIR:-/srv}/$NAME"
  REMOTE_PATH_PART="$NAME"

  if [ "$NAME" = "snapshots" ]; then
    TYPE="d"
  fi
fi

if [ -z "$NAME" ] || [ -n "$HELP" ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
  say "
  USAGE:
  $(g "${BASH_SOURCE##*/}")  $(c component) [$(c subject)] [$(c remote)]

  DESCRIPTION:
    $(g "${BASH_SOURCE##*/}") updates list of remote versions for $(c component).

    If $(c component) is 'curriculum', a $(c subject) must be provided.

    $(c remote) is the address of a computer to download versions from.
    It can start with $(g "ssh://") or $(g "http://") (default is $(g "ssh://") ).

    EXAMPLES:
      # Looking for desktop updates from the local server
        $(c "$") $(g "${BASH_SOURCE##*/}")  $(c desktop)  $(c server.local)

      # Looking for curriculum updates on another computer
        $(c "$") $(g "${BASH_SOURCE##*/}")  $(c curriculum)  $(c docs)  $(c ssh://tl-0123.local)

    Versions are saved to $(c "/srv/<component>/.v/<remote>") or $(c "/srv/curriculum/<subject>/.v/<remote>")

    If $(c remote) is omitted, only local versions will be synced.

  COMPONENTS:"
  say "$(ls -w 40 -m /srv | sed -e "s;^;    ;")
  "

  exit 1
fi

# Exit now if run as root user
assert-is-user

if ! [ -d "$DIR" ]; then
  if [ -n "$SUBJECT" ]; then
    err "Curriculum subject $c$SUBJECT$r is not installed"
  else
    err "Component $c$NAME$r is not installed"
  fi
  err ""
  err "  ($c$DIR$r is missing)"
  exit 1
fi

mkdir -p "$DIR/.v"

run find "$DIR/" -maxdepth 1 -name "v*.*.*.*" -type "$TYPE" \
  | grep -v "\.tmp" \
  | sed -e 's;.*/v;;' \
  | sed -e 's/\.tar\.gz$//' -e 's/\.iso$//' -e 's/\.sha256$//' \
  | sort -V | uniq \
    >"$DIR/.v/local" || true

if [ -n "$REMOTE" ]; then
  REMOTE_NAME="$(echo "$REMOTE" | awk -F '://' '{print $NF}')"

  # Strip user@ if present for rsync remotes
  PING_TARGET="$REMOTE_NAME"
  if echo "$REMOTE" | grep -qvE '^(http|https)://' && echo "$PING_TARGET" | grep -q '@'; then
    PING_TARGET=$(echo "$PING_TARGET" | cut -d'@' -f2)
  fi

  if ! ping -c 1 -W 1 "$PING_TARGET" >/dev/null 2>&1; then
    err "Remote $c$REMOTE_NAME$r is not reachable"
    exit 1
  fi

  if echo "$REMOTE" | grep -Eq '^(http|https)://'; then
    run curl -s "$REMOTE/$REMOTE_PATH_PART/" \
      | grep -oP '(?<=href=")v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\-]+)?\.(tar\.gz|iso)' \
      | sed -e 's/^v//' -e 's/\.tar\.gz$//' -e 's/\.iso$//' \
      | sort -V \
        >"$DIR/.v/$REMOTE_NAME" || true
  else # ssh
    run ssh "$REMOTE_NAME" find "/srv/$REMOTE_PATH_PART/" -maxdepth 1 -name "v*.*.*.*" -type "$TYPE" \
      | grep -v "\.tmp" \
      | sed -e 's;.*/v;;' \
      | sed -e 's/\.tar\.gz$//' -e 's/\.iso$//' -e 's/\.sha256$//' \
      | sort -V | uniq \
        >"$DIR/.v/$REMOTE_NAME" || true
  fi
fi

date -Iseconds >"$DIR/.v/.synced-at"
