#!/bin/bash

show_help() {
  printf "Usage:\n"
  printf "  openwisp-qa-check --help\n"
  printf "  openwisp-qa-check {--migration-path <path> [--migrations-to-ignore <int>] | --skip-checkmigrations}\n"
  printf "            {[--message <commit-message>] | --skip-checkcommit | --force-checkcommit}\n"
  printf "            {[--migration-module <module>] | --skip-checkmakemigrations}\n"
  printf "            [--skip-checkendline]\n"
  printf "            [--skip-flake8]\n"
  printf "            [--skip-isort]\n"
  printf "            [--skip-black]\n"
  printf "\n"
  printf "Runs all checks for quality assurance. Unneeded checks may be skipped by passing --skip-<check-name> argument.\n"
  printf "\n"
  printf "General options:\n"
  printf "  --help\t\t\t: Show this help text\n"
  printf "Migration check options:\n"
  printf "  --migration-path <path>\t: Path to migrations/ folder\n"
  printf "  --migrations-to-ignore <int>\t: Number of migrations after which checking of migration file names should begin,\n"
  printf "\t\t\t\t  say, if checking needs to start after 0003_auto_20150410_3242.py value should be 3\n"
  printf "  --skip-checkmigrations\t: Skip migration name check\n"
  printf "  You can do multiple migration check by passing the arguments with space-delimited string array.\n"
  printf "Commit message check options:\n"
  printf "  --message <commit-message>\t: Commit message (by default is equal to latest commit name)\n"
  printf "  --migration-module <module>\t: Name of Migration Module\n"
  printf "  --skip-checkmakemigrations\t: Skip make migration check\n"
  printf "  --skip-checkcommit\t\t: Skip commit check\n"
  printf "  --force-checkcommit\t\t: Force commit check\n"
  printf "Blank endlines check options:\n"
  printf "  --skip-checkendline\t\t: Skip blank endlines check\n"
  printf "Flake8 check options:\n"
  printf "  --skip-flake8\t\t\t: Skip flake8 check\n"
  printf "Isort check options:\n"
  printf "  --skip-isort\t\t\t: Skip isort check\n"
  printf "Black check options:\n"
  printf "  --skip-black\t\t\t: Skip black check\n"
}

echoerr() { echo "$@" 1>&2; }

runcheckendline() {
  flag=0
  for i in $(find . -type f ! -path "*/*.egg-info/*" \
    ! -path "./.*" \
    ! -path "*.min.*" \
    ! -path "*.svg" -exec grep -Iq . {} \; -and -print); do
    if [ "$(tail -c 1 $i)" != "" ]; then
      echo "$i needs newline at the end"
      flag=1
    fi
  done
  if [ $flag -ne 0 ]; then
    echoerr "ERROR: Blank endline check failed!"
    FAILURE=1
  else
    echo "SUCCESS: Blank endline check successful!"
  fi
}

runcheckmigrations() {
  if [ "$MIGRATION_PATH" == "" ]; then
    echoerr "SKIPPED: No migration path specified!"
    FAILURE=1
    return
  fi
  for i in "${!MIGRATION_PATH[@]}"
  do
    path="${MIGRATION_PATH[$i]}"
    ignore="${MIGRATIONS_TO_IGNORE[$i]}"
    ignore="`[ $ignore ] && echo \"$ignore\" || echo 0`"
    checkmigrations --migration-path "$path" --migrations-to-ignore "$ignore" \
      && echo "SUCCESS: Migration name check on \"$path\" with migrations-to-ignore: $ignore successful!" \
      || { echoerr "ERROR: Migration name check on \"$path\" with migrations-to-ignore: $ignore failed!"; FAILURE=1; }
  done
}

runflake8() {
  flake8 && echo "SUCCESS: Flake8 check successful!" \
    || { echoerr "ERROR: Flake8 check failed!"; FAILURE=1; }
}

runisort() {
  isort --check-only --recursive --diff \
    && echo "SUCCESS: Isort check successful!" \
    || { echoerr "ERROR: Isort check failed! Hint: did you forget running openwisp-qa-format?"; FAILURE=1; }
}

runblack() {
  black -S --check --diff . \
    && echo "SUCCESS: Black check successful!" \
    || { echoerr "ERROR: Black check failed! Hint: did you forget running openwisp-qa-format?"; FAILURE=1; }
}

# This check is run when any of the following conditions is true:
# 1. --force-checkcommit is specified
# 2. This function is invoked from Travis building a Pull Request
runcheckcommit() {
  [ -n "$TRAVIS_PULL_REQUEST" ] || TRAVIS_PULL_REQUEST=false
  if [[ $FORCE_CHECKCOMMIT = true ]] || [[ $TRAVIS_PULL_REQUEST = true ]]; then
    echo "Running commit message check"
    checkcommit --message "$COMMIT_MESSAGE" \
    && echo "SUCCESS: Commit message check successful!" \
    || { printf "Checking commit message:\n\n"; printf "%s\n\n" "$COMMIT_MESSAGE"; echoerr "ERROR: Commit message check failed!"; FAILURE=1; }
  else
    echo "SKIPPED: Commit message check"
  fi
}

runcheckpendingmigrations() {
  if [ ! -f "./tests/manage.py" ]; then
    echo "File manage.py not found, skipping Make Migration Check."
  else
    OUTPUT=$(python tests/manage.py makemigrations --dry-run $MODULE)
    echo $OUTPUT
    echo $OUTPUT | grep "No changes detected" &> /dev/null \
      && echo "SUCCESS: Migrations check successful!" \
      || { echoerr "ERROR: Migrations check failed! Models' changes not migrated, please run './manage.py makemigrations' to solve the issue!"; FAILURE=1; }
  fi
}

## Main

SKIP_CHECKENDLINE=false
SKIP_CHECKMIGRATIONS=false
SKIP_MAKEMIGRATIONS=false
SKIP_FLAKE8=false
SKIP_ISORT=false
SKIP_BLACK=false
SKIP_CHECKCOMMIT=false
FORCE_CHECKCOMMIT=false
MIGRATION_PATH=""
MIGRATIONS_TO_IGNORE="0"
COMMIT_MESSAGE=$(git log $TRAVIS_PULL_REQUEST_SHA --format=%B -n 1)
FAILURE=0
MODULE=""

while [ "$1" != "" ]; do
  case "$1" in
  --skip-checkendline)
    SKIP_CHECKENDLINE=true
    ;;
  --skip-checkmigrations)
    SKIP_CHECKMIGRATIONS=true
    ;;
  --migration-path)
    shift
    MIGRATION_PATH=($1)
    ;;
  --migrations-to-ignore)
    shift
    MIGRATIONS_TO_IGNORE=($1)
    ;;
  --skip-flake8)
    SKIP_FLAKE8=true
    ;;
  --skip-isort)
    SKIP_ISORT=true
    ;;
  --skip-black)
    SKIP_BLACK=true
    ;;
  --skip-checkcommit)
    SKIP_CHECKCOMMIT=true
    ;;
  --force-checkcommit)
    FORCE_CHECKCOMMIT=true
    ;;
  --message)
    shift
    COMMIT_MESSAGE="$1"
    ;;
  --skip-checkmakemigrations)
    SKIP_MAKEMIGRATIONS=true
    ;;
  --migration-module)
    shift
    MODULE="$1"
    ;;
  --help)
    show_help
    exit
    ;;
  *)
    printf "Unknown argument: %s\n" "$1"
    printf "\n"
    show_help
    exit 1
    ;;
  esac
  shift
done

set -e

if ! $SKIP_CHECKENDLINE; then
  runcheckendline
fi

if ! $SKIP_CHECKMIGRATIONS; then
  runcheckmigrations
fi

if ! $SKIP_ISORT; then
  runisort
fi

if ! $SKIP_BLACK; then
  runblack
fi

if ! $SKIP_FLAKE8; then
  runflake8
fi

if ! $SKIP_CHECKCOMMIT; then
  runcheckcommit
fi

if ! $SKIP_MAKEMIGRATIONS; then
  runcheckpendingmigrations
fi

exit $FAILURE
