#!/usr/bin/env bash

# Utility to check whether we're in the main project
# directory or in the tests dir.
in_project_root() {
    PARENTDIR=$(basename "$PWD")
    [[ 'tests' != "${PARENTDIR##*/}" ]] && return
    false
}

POSITIONAL_ARGS=()
while [[ $# -gt 0 ]]; do
    case $1 in
    -b|--branch)
        BRANCH="$2"
        shift
        shift
        ;;
    -C|--code-coverage-directory)
        CODECOVERAGE_DIR="$2"
        shift
        shift
        ;;
    -h|--host)
        DB_HOST="$2"
        shift
        shift
        ;;
    -n|--name)
        DB_NAME="$2"
        shift # past argument
        shift # past value
        ;;
    -P|--package-name)
        PACKAGE_NAME="$2"
        shift
        shift
        ;;
    -p|--pass)
        DB_PASS="$2"
        shift
        shift
        ;;
    -s|--slug)
        SLUG="$2"
        shift
        shift
        ;;
    -t|--tmpdir)
        TMPDIR="$2"
        shift
        shift
        ;;
    -u|--user)
        DB_USER="$2"
        shift
        shift
        ;;
    -v|--version)
        VERSION="$2"
        shift
        shift
        ;;
    --fresh)
        FRESH=true
        shift
        ;;
    -H|--help)
        SHOW_HELP=true
        shift # past argument
        ;;
    --skip-db-create)
        SKIP_DB_CREATE=true
        shift
        ;;
    -*|--*)
        echo "Unknown option $1"
        exit 1
        ;;
    *)
        POSITIONAL_ARGS+=("$1") # save positional arg
        shift
        ;;
    esac
done

SCRIPT="./vendor/bin/cspf-tests-php"
COMMAND=${POSITIONAL_ARGS[0]}

#
# Downloads a remote file and stores it in the specified location.
#
# @example download "https://example.com/file.zip" $TMPDIR/file.zip)
#
# @param string $1 The remote URL of the file
# @param string $2 The path to store the file on the local machine.
#
download() {
    if [ `which curl` ]; then
        curl -s -L "$1" > "$2";
    elif [ `which wget` ]; then
        wget -nv -O "$2" "$1"
    fi
}

#
# Retrieves the index of a string within another string.
#
# @example STR_INDEX=$(strindex "haystack" "needle")
#
# @param string $1 The string to find the substring within.
# @param string $2 The substring to find within the string.
# @return int The index of the string or -1 if the string isn't found.
function strindex {
    x="${1%%$2*}"
    [[ "$x" = "$1" ]] && echo -1 || echo "${#x}"
}

if in_project_root; then
    SLUG=${SLUG-$(basename "$PWD")};
    PROJECTDIR_REL="./"
    TMPDIR=${TMPDIR-./tmp/}
else
    PROJECTDIR_REL="../"
    SLUG=${SLUG-$(basename $(dirname -- "$PWD"))}
    # If in ./tests/, the TMPDIR will be ../tests/tmp/.
    TMPDIR=${TMPDIR-${PROJECTDIR_REL}$(basename "$PWD")/tmp/}
fi
# Tralingslashit the TMPDIR.
TMPDIR="${TMPDIR%/}/"

if ([[ true == $SHOW_HELP && "" == "$COMMAND" ]]) || ([[ "help" == "$COMMAND" ]]); then

    echo "Manages testing dependencies for testing WordPress PHP Projects with PHPUnit."
    echo ""

    echo "USAGE"
    echo "  $SCRIPT <command> [options]"
    echo ""

    echo "COMMANDS"
    echo "  help            Show this help message."
    echo "  install-plugin  Installs a WordPress plugin as a test dependency."
    echo "  install-wp      Install WordPress testing dependencies and setup a testing database."
    echo "  scaffold        Creates required and sample tests files for a new project."
    echo ""

elif [[ "install-wp" == "$COMMAND" ]]; then

    DEFAULT_DB_NAME="${SLUG}_tests"

    if [[ true == $SHOW_HELP ]]; then
        echo "Install WordPress testing dependencies and setup a testing database."
        echo ""

        echo "USAGE"
        echo "  $SCRIPT $COMMAND [options]"
        echo ""

        echo "OPTIONS"
        echo "  -H, --help            Show this help message."
        echo "  -n, --name            The database name. Default: \"$DEFAULT_DB_NAME\""
        echo "  -u, --user            The database username. Default: \"root\""
        echo "  -p, --pass            The database users password. Default: \"password\""
        echo "  -h, --host            The database host name and, optionally port. Default: \"localhost:3306\""
        echo "  -s, --slug            The slug of the WordPress plugin to be tested. Used as prefix for the default database name. Default: \"${SLUG}\"".
        echo "  -v, --version         The WordPress core version to download. Default: \"latest\""
        echo "  -t, --tmpdir          The relative path, relative to the project's directory, to the temporary directory where dependencies are stored. Default: \"${TMPDIR}\"."
        echo "      --fresh           If provided, clears the --tmpdir and redownloads all dependencies."
        echo "      --skip-db-create  If provided, skips database creation."
        echo ""
        exit 0
    fi

    DB_NAME=${DB_NAME-$DEFAULT_DB_NAME}
    DB_USER=${DB_USER-root}
    DB_PASS=${DB_PASS-password}
    DB_HOST=${DB_HOST-localhost}
    WP_VERSION=${VERSION-latest}
    SKIP_DB_CREATE=${SKIP_DB_CREATE-false}

    if [[ true == $FRESH ]]; then
        read -s -n 1 -p "You are about to delete the contents of temporary directory \"$TMPDIR\". Do you wish to proceed [Y/n]" PROCEED
        PROCEED=${PROCEED-:""}
        if [[ "Y" == "$PROCEED" || "y" == "$PROCEED" || "" == "$PROCEED" ]]; then
            echo ""
            rm -rf $TMPDIR
        else
            exit 0
        fi
    fi

    export TMPDIR
    ./vendor/bin/install-wp-tests "$DB_NAME" "$DB_USER" "$DB_PASS" "$DB_HOST" "$WP_VERSION" "$SKIP_DB_CREATE"

elif [[ "install-plugin" == "$COMMAND" ]]; then

    if [[ true == $SHOW_HELP ]]; then
        echo "Installs a WordPress plugin as a test dependency."
        echo ""

        echo "USAGE"
        echo "  $SCRIPT $COMMAND <source> [options]"
        echo ""

        echo "ARGUMENTS"
        echo "  source  The remote source for the plugin's code."
        echo "          To install a plugin from WordPress.org, provide the plugin's slug prefixed with \"wp:\"."
        echo "          To install a plugin from a git repository, provide the plugin's remote URL prefixed with \"git:\"."
        echo ""

        echo "OPTIONS"
        echo "  -H, --help     Show this help message."
        echo "  -b, --branch   If installing from a git repository use this to specify the source branch. If omitted,"
        echo "                 uses the repository's default branch."
        echo "  -v, --version  The plugin version to download. Only applicable when installing from WordPress.org. If"
        echo "                 ommitted, uses the plugin's latest version."
        echo "  -t, --tmpdir   The relative path, relative to the project's directory, to the temporary directory where dependencies are stored. Default: \"${TMPDIR}\"."
        echo ""

        echo "EXAMPLES"
        echo "  $ $SCRIPT $COMMAND wp:gutenberg"
        echo "  $ $SCRIPT $COMMAND wp:gutenberg --version 15.0.0"
        echo "  $ $SCRIPT $COMMAND git:https://github.com/WordPress/gutenberg"
        echo "  $ $SCRIPT $COMMAND git:https://github.com/WordPress/gutenberg --branch develop"
        echo ""
        exit 0
    fi

    SOURCE_URL=${POSITIONAL_ARGS[1]}
    ZIP=""

    # Download plugin from WordPress.org.
    if [[ 0 == $(strindex "$SOURCE_URL" "wp:") ]]; then

        WP_PLUGIN_SLUG=${SOURCE_URL:3}
        WP_DOWNLOAD_URL="https://downloads.wordpress.org/plugin/${WP_PLUGIN_SLUG}"

        if [[ "" != "$VERSION" ]]; then
            WP_DOWNLOAD_URL="$WP_DOWNLOAD_URL.$VERSION";
        fi

        WP_DOWNLOAD_URL="$WP_DOWNLOAD_URL.zip";
        download "$WP_DOWNLOAD_URL" "${TMPDIR}${WP_PLUGIN_SLUG}.zip"

        ZIP="${TMPDIR}${WP_PLUGIN_SLUG}.zip"
        echo "Unzipping $ZIP..."
        unzip -qo $ZIP -d "${TMPDIR}wordpress/wp-content/plugins/"
        rm $ZIP

    # Clone from a git repo.
    elif [[ 0 == $(strindex "$SOURCE_URL" "git:") ]]; then

        GIT_URL=${SOURCE_URL:4}
        REPO_BRANCH=""
        PLUGIN_SLUG=$(basename ${SOURCE_URL} .${SOURCE_URL##*.})
        if [[ "" != "$BRANCH" ]]; then
            REPO_BRANCH="-b $BRANCH"
        fi

        git clone $REPO_BRANCH $GIT_URL "${TMPDIR}wordpress/wp-content/plugins/$PLUGIN_SLUG"
    fi


elif [[ "scaffold" == "$COMMAND" ]]; then

    PACKAGE_NAME="${PACKAGE_NAME-${SLUG}}"
    # Sanitize the Package Name to be used so that it's suitable to be used
    # as namespace as well.
    # Replace any "-" or "_" with spaces.
    PACKAGE_NAME="${PACKAGE_NAME//[-|_]/ }"
    # Then capitilize each word.
    PACKAGE_NAME=( $PACKAGE_NAME )
    PACKAGE_NAME="${PACKAGE_NAME[@]^}"
    # Then remove spaces.
    PACKAGE_NAME="${PACKAGE_NAME// /}"

    CODECOVERAGE_DIR=${CODECOVERAGE_DIR-"app"}

    if [[ true == $SHOW_HELP ]]; then
        echo "Creates required and sample tests files for a new project."
        echo ""

        echo "USAGE"
        echo "  $SCRIPT $COMMAND [options]"
        echo ""


        echo "OPTIONS"
        echo "  -H, --help                     Show this help message."
        echo "  -P, --package-name             Customize the package's name. Default: \"${PACKAGE_NAME}\"."
        echo "  -C, --code-coverage-directory  Specify the code coverage directory path relative to the project directory. Default: \"app\"."
        echo "  -s, --slug                     The slug of the WordPress plugin to be tested. Default: \"${SLUG}\"."
        echo "  -t, --tmpdir                   The relative path, relative to the project's directory, of the temporary directory where the tests cache results are stored. Default: \"${TMPDIR}\"."
        echo ""
        exit 0
        exit 0
    fi

    FILES="bootstrap.php bootstrap-extra.php phpunit.xml.dist Framework/TestCase.php Framework/WPTestCase.php TestCases/SampleTest.php"

    # Are we in the project root? If so, maybe create the tests directory.
    TESTSDIR="${PROJECTDIR_REL}tests"
    if in_project_root; then
        mkdir -p "$TESTSDIR";
    fi

    BASEDIR=$(dirname -- "$0")
    TEMPLATE_DIR="${BASEDIR}/../templates"

    # Tralingslashit the testdir for uniformity.
    TESTSDIR="${TESTSDIR%/}/"
    mkdir -p "${TESTSDIR}Framework"
    mkdir -p "${TESTSDIR}TestCases"

    # portable in-place argument for both GNU sed and MacOS sed
    if [[ $(uname -s) == "Darwin" ]]; then
        ioption="-i.scaffoldbackup"
    else
        ioption="-i"
    fi

    for FILENAME in $FILES
    do
        DESTDIR=$TESTSDIR
        # The phpunit.xml.dist file must be copied in the composer.json dir.
        if [[ in_project_root && "phpunit.xml.dist" == $FILENAME ]]; then
            DESTDIR="${PWD}/"
        fi

        echo "Creating \"${FILENAME}\""
        cp "${TEMPLATE_DIR}/${FILENAME}" "${DESTDIR}${FILENAME}"
        sed $ioption "s/{{PACKAGE_NAME}}/${PACKAGE_NAME}/g" "${DESTDIR}${FILENAME}"
        sed $ioption "s/{{SLUG}}/${SLUG}/g" "${DESTDIR}${FILENAME}"

        if [[ "phpunit.xml.dist" == $FILENAME ]]; then
            sed $ioption "s#{{TESTSDIR}}#${TESTSDIR}#g" "${DESTDIR}${FILENAME}"
            sed $ioption "s#{{PROJECTDIR}}#${PROJECTDIR_REL}#g" "${DESTDIR}${FILENAME}"
            sed $ioption "s#{{COVERAGEDIR}}#${CODECOVERAGE_DIR}#g" "${DESTDIR}${FILENAME}"
            sed $ioption "s#{{TMPDIR}}#${TMPDIR}#g" "${DESTDIR}${FILENAME}"
        fi

        # MacOS sed in-place argument creates a backup, remove it
        if [ -f "${DESTDIR}${FILENAME}.scaffoldbackup" ] ; then
            rm "${DESTDIR}${FILENAME}.scaffoldbackup"
        fi

    done

else

    echo "Invalid command."
    exit 1

fi

exit 0
