#!/bin/sh
command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'pre-push' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; }
git lfs pre-push "$@"

set -eu

. .githooks/load-npm.sh

reset() {
  echo "Cleaning up and return control"
  # the symlinked node_modules must not be followed when removing the throwaway clone
  rm -rf "$flowrtmpdir"
  cd "$curdir"
}

unclean=false
if [ -n "$(git status --porcelain)" ]; then
  # if we directly assign the test set -eu will not approve
  unclean=true
  trap reset EXIT
  echo "Working tree is not clean, so we reset in temporary folder"
  # backwards compatible platform independence
  flowrtmpdir=$(mktemp -d 2>/dev/null || mktemp -d -t 'flowrtmpdir')
  echo "Using temporary folder $flowrtmpdir"

  curdir=$(pwd)

  echo "Cloning copy..." # cloning obeys gitignore
  git clone . "$flowrtmpdir"
  echo "Keep installed packages..."
  # a symlink keeps the push fast, the clone only needs to run the installed tools
  ln -s "$(pwd)/node_modules" "$flowrtmpdir/node_modules" 2>/dev/null || cp -r node_modules/ "$flowrtmpdir/node_modules"
  cd "$flowrtmpdir"

  git reset --hard
  echo "Setup completed."
fi

# check if the latest commit starts with "[release"
# no `grep -q` anywhere in a pipeline: it stops at the first hit and the write side dies of a broken pipe
if git log -1 --pretty=%B | grep -- "\[release" > /dev/null; then
  echo "Latest commit is a release commit, doing full checkup..."
  $NPM_CMD run checkup
else
  echo "Linting project (local mode)..."
  $NPM_CMD run lint-local -- --fix
  if [ -n "$(git status --porcelain)" ]; then
    if $unclean; then
      # we linted a disposable clone, so copy fixes back before it gets removed by the reset trap;
      # skip files you already have uncommitted changes for, to avoid clobbering your edits
      # -z keeps every path whole and unquoted, which "status --porcelain" does not do for a path
      # with a space in it; the newlines are only there so grep and read can work line by line
      dirtyFiles="$({ git -C "$curdir" diff --name-only -z HEAD; git -C "$curdir" ls-files -o --exclude-standard -z; } | tr '\0' '\n')"
      # read line by line, a plain "for f in $(...)" splits paths that contain spaces
      git diff --name-only -z | tr '\0' '\n' | while IFS= read -r f; do
        if printf '%s\n' "$dirtyFiles" | grep -xF -- "$f" > /dev/null; then
          echo "  - skipping $f (you have uncommitted changes to it, fix it manually)"
        else
          mkdir -p "$(dirname "$curdir/$f")"
          cp -f "$f" "$curdir/$f"
          echo "  - copied lint fix for $f back to your working tree"
        fi
      done
    fi
    echo ""
    echo "╔══════════════════════════════════════════════════════════════╗"
    echo "║  lint --fix changed files --- please review, stage, and      ║"
    echo "║  recommit before pushing.                                    ║"
    echo "╚══════════════════════════════════════════════════════════════╝"
    echo ""
    exit 1
  fi
fi


# shellcheck disable=SC2124 # we want the argument splitting
args="$@"
lfspre() {
  if $unclean; then
    reset
  fi
  command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting '.git/hooks/pre-push'.\n"; exit 2; }
  # we want the argument splitting
  git lfs pre-push $args
}

# we register it as a trap after lint so that it 1) triggers only if lint-local succeeded
# but 2) only triggers *after* the directory recovery completed
trap lfspre EXIT
