#!/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 }\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 "            [--skip-checkrst]\n"
  printf "            [--csslinter]\n"
  printf "            [--jslinter]\n"
  printf "\n"
  printf "Runs all checks for quality assurance. Unneeded checks may be skipped by passing --skip-<check-name> argument.\n"
  printf "csslinter and jslinter checks are skipped by default for backward compatibility. To run them pass --csslinter or --jslinter as an 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 "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"
  printf "ReStructuredText check options:\n"
  printf "  --skip-checkrst\t\t: Skip ReStructuredText check\n"
  printf "CSSlinter check options:\n"
  printf "  --csslinter\t\t\t: Runs stylelint check\n"
  printf "Jslinter check options:\n"
  printf "  --jslinter\t\t\t: Runs jshint 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
}

runstylelintcheck() {
  package='stylelint'
  if which stylelint > /dev/null; then
    stylelint verbose $(find . -type f -name "*.css") &&
      echo "SUCCESS: Stylelint check successful!" ||
      {
        echoerr "ERROR: Stylelint check failed! Hint: did you forget to run openwisp-qa-format?"
        FAILURE=1
      }
  else
    echo "MODULE NOT FOUND: Please install ${package}"
    FAILURE=1
  fi
}

runjshintcheck() {
  package='jshint'
  if which jshint > /dev/null; then
    jshint --verbose $(find . -type f -name "*.js" -a ! -path "*vendor/*.js") &&
      echo "SUCCESS: Jshint check successful!" ||
      {
        echoerr "ERROR: Jshint check failed! Hint: please follow js code conventions. Visit: https://openwisp.io/docs/developer/contributing.html#javascript-code-conventions"
        FAILURE=1
      }
  else
    echo "MODULE NOT FOUND: Please install ${package}"
    FAILURE=1
  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]}"
    [ -n "$ignore" ] || ignore=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
    }
}

runrstcheck() {
  checkrst && echo "SUCCESS: ReStructuredText check successful!" \
    || { echoerr "ERROR: ReStructuredText check failed!"; FAILURE=1; }
}

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

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

runcheckcommit() {
  if [ -z "$COMMIT_MESSAGE" ]; then COMMIT_MESSAGE=$(git log -1 --pretty=%B); fi
  if [ "$TRAVIS" = true ] && [ "$TRAVIS_PULL_REQUEST" = false ]; then
    echo "SKIPPED: Commit message check skipped!"
  else
    checkcommit --message "$COMMIT_MESSAGE" &&
      echo "SUCCESS: Commit message check successful!" ||
      {
        echo -e "Checked commit message:\n\n"
        echo -e "$COMMIT_MESSAGE\n\n"
        echoerr "ERROR: Commit message check failed!"
        FAILURE=1
      }
  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 | grep "No changes detected" &>/dev/null &&
      echo "SUCCESS: Migrations check successful!" ||
      {
        echo $OUTPUT
        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_RSTCHECK=false
SKIP_BLACK=false
SKIP_CHECKCOMMIT=false
SKIP_CSS_LINTER=true
SKIP_JS_LINTER=true
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-checkrst)
    SKIP_RSTCHECK=true
    ;;
  --skip-checkcommit)
    SKIP_CHECKCOMMIT=true
    ;;
  --csslinter)
    SKIP_CSS_LINTER=false
    ;;
  --jslinter)
    SKIP_JS_LINTER=false
    ;;
  --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_CSS_LINTER; then
  runstylelintcheck
fi

if ! $SKIP_JS_LINTER; then
  runjshintcheck
fi

if ! $SKIP_RSTCHECK; then
  runrstcheck
fi

if ! $SKIP_CHECKCOMMIT; then
  runcheckcommit
fi

if ! $SKIP_MAKEMIGRATIONS; then
  runcheckpendingmigrations
fi

exit $FAILURE
