#!/usr/bin/env bash
# Helper script for python_job in config.yml

# Set defaults if unset or null
: ${ALLOW_FAILURE:=0}
: ${IQ_ENABLED:=0}
: ${MYPY_STRICT:=0}
: ${PHONES_ENABLED:=0}
: ${PYTEST_FAIL_FAST:=0}
: ${PYTEST_MIGRATIONS_MODE:=0}
: ${TEST_RESULTS_DIR:=tmp}
: ${TEST_RESULTS_FILENAME:=}
: ${DATABASE_URL:=sqlite:///db.sqlite3}
: ${TEST_DB_NAME:=test.sqlite3}
: ${TEST_DB_URL:=sqlite:///test.sqlite3}
: ${DATABASE_ENGINE:=sqlite}
: ${GLEAN_OUTPUT_FOLDER:=privaterelay/glean}
: ${GLEAN_INPUT_YAML:=telemetry/glean/relay-server-metrics.yaml}

# Run black to check Python format
function run_black {
    set -x
    black --check .
}

# Run mypy to check type hints
function run_mypy {
    local MYPY_ARGS=("--no-incremental")
    if [ $MYPY_STRICT -ne 0 ]; then MYPY_ARGS+=("--strict"); fi
    if [ -n "$TEST_RESULTS_FILENAME" ]
    then
        MYPY_ARGS+=("--junit-xml" "${TEST_RESULTS_DIR}/${TEST_RESULTS_FILENAME}")
    fi
    MYPY_ARGS+=(".")

    set -x
    mypy "${MYPY_ARGS[@]}"
}

# Run pytest to run test code
# Pass "--skip-results", to skip writing jUnit-style results XML
# Pass "--create-db", to re-create a reusable database with migrations mode
function run_pytest {
    local SKIP_RESULTS=0
    local CREATE_DB=0
    while [ "$#" -gt 0 ]; do
      case "$1" in
        --skip-results) SKIP_RESULTS=1; shift;;
        --create-db) CREATE_DB=1; shift;;
        *) echo "unknown option '$1'"; exit 1;;
      esac
    done

    local PYTEST_ARGS=()
    if [ $PYTEST_FAIL_FAST -ne 0 ]; then PYTEST_ARGS+=("--maxfail=3"); fi
    if [ $PYTEST_MIGRATIONS_MODE -ne 0 ]; then PYTEST_ARGS+=("--reuse-db"); fi
    if [ $CREATE_DB -ne 0 ]; then PYTEST_ARGS+=("--create-db"); fi
    if [ -n "$TEST_RESULTS_FILENAME" ] && [ $SKIP_RESULTS != 1 ]
    then
        PYTEST_ARGS+=("--junit-xml=${TEST_RESULTS_DIR}/$TEST_RESULTS_FILENAME")
    fi
    PYTEST_ARGS+=(".")

    echo "PHONES_ENABLED=${PHONES_ENABLED}, IQ_ENABLED=${IQ_ENABLED}"
    set -x
    pytest ${PYTEST_ARGS[@]}
}

# Run commands to build the email tracker lists
function run_build_email_tracker_lists {
    set -x
    ./manage.py get_latest_email_tracker_lists --skip-checks
    ./manage.py get_latest_email_tracker_lists --skip-checks --tracker-level=2
    mkdir --parents /tmp/workspace/email-trackers
    cp /home/circleci/project/emails/tracker_lists/level-one-trackers.json /tmp/workspace/email-trackers/
    cp /home/circleci/project/emails/tracker_lists/level-two-trackers.json /tmp/workspace/email-trackers/
}



# Run commands to build the backend Glean code
function run_build_glean {
    local OUTPUT_FOLDER=${1:-$GLEAN_OUTPUT_FOLDER}
    local INPUT_YAML=${2:-$GLEAN_INPUT_YAML}
    set -x
    glean_parser translate --format python_server --output ${OUTPUT_FOLDER} ${INPUT_YAML}
    black ${OUTPUT_FOLDER}
    ruff check --fix --ignore E501 ${OUTPUT_FOLDER}
    { set +x; } 2>/dev/null
    case "$OSTYPE" in
        darwin* | bsd*)
            echo "Using BSD sed";
            set -x;
            sed -i '' \
                -e 's/^AUTOGENERATED BY glean_parser \(.* DO NOT EDIT.\) DO NOT COMMIT.$/AUTOGENERATED BY glean_parser \1 To recreate, run:\n\nbash .circleci\/python_job.bash run build_glean/' \
                ${OUTPUT_FOLDER}/server_events.py;
            { set +x; } 2>/dev/null;;
        linux*)
            echo "Using GNU sed";
            set -x;
            sed -i \
                -e 's/^AUTOGENERATED BY glean_parser \(.* DO NOT EDIT.\) DO NOT COMMIT.$/AUTOGENERATED BY glean_parser \1 To recreate, run:\n\nbash .circleci\/python_job.bash run build_glean/' \
                ${OUTPUT_FOLDER}/server_events.py;
            { set +x; } 2>/dev/null;;
        *)
            echo "Unknown OSTYPE '${OSTYPE}'";;
    esac
}

# Run commands to check if the backend Glean code has changed
function run_check_glean {
    GLEAN_TEST_FOLDER=`mktemp -d`
    echo "Created temporary folder $GLEAN_TEST_FOLDER"
    echo "Re-running glean_parser..."
    echo
    run_build_glean $GLEAN_TEST_FOLDER
    { set +x; } 2>/dev/null

    echo
    echo "Checking new files against checked-in files..."
    local HAS_DIFFS=0
    local HAS_FILES=0
    local EXIT_CODE=0
    for FILENAME in `find ${GLEAN_TEST_FOLDER} -type f -name '*.py' -exec basename \{\} \;`
    do
        HAS_FILES=1
        RETVAL=0
        /usr/bin/cmp --silent "${GLEAN_TEST_FOLDER}/${FILENAME}" "${GLEAN_OUTPUT_FOLDER}/${FILENAME}" || RETVAL=$?
        if [ $RETVAL -eq 1 ]
        then
            HAS_DIFFS=1
        elif [ $RETVAL -gt 1 ]
        then
            echo "cmp returned $RETVAL!"
            set -x
            /usr/bin/cmp --silent "${GLEAN_TEST_FOLDER}/${FILENAME}" "${GLEAN_OUTPUT_FOLDER}/${FILENAME}"
            exit 1
        fi
    done
    if [ $HAS_FILES -eq 0 ]
    then
        echo "glean_parser did not generate any files!"
        EXIT_CODE=1
    fi
    if [ $HAS_DIFFS -eq 1 ]
    then
        echo "*** Differences detected - need to re-run glean_parser ***"
        diff --exclude '__pycache__' $GLEAN_OUTPUT_FOLDER $GLEAN_TEST_FOLDER || true
        echo "*** End of differences***"
        EXIT_CODE=1
    fi
    if [ "$GLEAN_TEST_FOLDER" != "" ]
    then
        echo "Removing temporary folder $GLEAN_TEST_FOLDER"
        rm -rf $GLEAN_TEST_FOLDER
    fi
    if [ $EXIT_CODE -eq 0 ]
    then
        echo "✓ Files are identical"
    elif [ $HAS_DIFFS -eq 1 ]
    then
        echo
        echo "To fix, run:"
        echo
        echo "  bash .circleci/python_job.bash run build_glean"
        echo
        echo "and add as a commit to this pull request."
        exit 1
    else
        exit 1
    fi
}

# Run ruff to lint python code
function run_ruff {
    if [ -n "$TEST_RESULTS_FILENAME" ]
    then
        # Run with output to a test results file instead of stdout
        set -x
        ruff check --exit-zero --output-format junit --output-file "${TEST_RESULTS_DIR}/${TEST_RESULTS_FILENAME}" .
        { set +x; } 2>/dev/null
    fi

    set -x
    ruff check .
}


# Run a command by name
# $1 - The command to run - black, mypy, pytest, or build_email_tracker_lists
# Remaining arguments are passed to the run_COMMAND function
function run_command {
    local COMMAND=${1:-}
    case $COMMAND in
        black | mypy | pytest | build_email_tracker_lists | build_glean | check_glean | ruff)
            :;;
        "")
            echo "No command passed - '$COMMAND'"
            exit 1
            ;;
        *)
            echo "Unknown command $COMMAND"
            exit 1
            ;;
    esac

    if [ $ALLOW_FAILURE -eq 0 ]
    then
        "run_$COMMAND" "${@:2}"
    else
        "run_$COMMAND" "${@:2}" || echo  "*** Command $COMMAND failed, but it is allowed to fail. ***"
    fi
}

# Install the dockerize tool
# $1 - The version to install, default v0.6.1
function install_dockerize {
    local DOCKERIZE_VERSION=${1:-v0.6.1}
    set -x
    wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz &&
    sudo tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz &&
    rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
}

# Wait for the PostgreSQL database to respond
function wait_for_the_database {
    dockerize -wait tcp://localhost:5432 -timeout 1m
}

# Get the Docker tag from the production version endpoint
function get_prod_tag {
    echo "$(curl --silent https://relay.firefox.com/__version__ | jq -r '.version')"
}

# Show current migrations for sqlite3 or postgresql
function show_migrations {
  if [ "$DATABASE_ENGINE" == "sqlite" ]
  then
    set -x
    sqlite3 ${TEST_DB_NAME} "SELECT * FROM django_migrations"
  else
    set -x
    psql ${TEST_DB_URL} --command="SELECT * FROM django_migrations;"
  fi
}

# Check out production code and install requirements
function switch_to_production {
    local PROD_TAG=$(get_prod_tag)
    echo "# Production tag is ${PROD_TAG}"
    set -x
    git fetch --force origin tag ${PROD_TAG}
    git checkout ${PROD_TAG}
    git submodule update --init --recursive
    git status
    pip install -r requirements.txt
}

if [ "$1" == "run" ]
then
    run_command "$2"
fi
