#!/bin/sh

GITHUB_REPO='node-cache'
SUBDIR='node_modules'

set -eu
cd "$(realpath -m "$0"/../..)"
. tools/git-utils.sh

cmd_remove() {
    # if we did this for ourselves the rm is enough, but it might be the case
    # that someone actually used git-submodule to fetch this, so clean up after
    # that as well.  NB: deinit nicely recreates the empty directory for us.
    message REMOVE node_modules
    rm -rf node_modules
    git submodule deinit node_modules
    rm -rf "$(git rev-parse --absolute-git-dir)/modules/node_modules"
}

cmd_checkout() {
    # we default to check out the node_modules corresponding to the gitlink in the index
    local sha="${1-$(get_index_gitlink node_modules)}"

    # fetch by sha to prevent us from downloading something we don't want
    fetch_sha_to_cache "${sha}"

    # verify that our package.json is equal to the one the cached node_modules
    # was created with, unless --force is given
    if [ "${1-}" != "--force" ]; then
        if ! cmp_from_cache "${sha}" '.package.json' 'package.json'; then
            cat >&2 <<EOF

*** node_modules ${sha} doesn't match our package.json
*** refusing to automatically check out node_modules

Options:

    - tools/node-modules checkout --force     # disable this check

    - tools/node-modules rebuild              # npm install with our package.json

$0: *** aborting

EOF
            exit 1
        fi
    fi

    # we're actually going to do this; let's remove the old one
    cmd_remove

    # and check out the new one
    # we need to use the tag name here, unfortunately
    clone_from_cache "${sha}"
}

cmd_rebuild() {
    for file in npm-shrinkwrap.json package-lock.json yarn.lock; do
        if [ -e "${top_srcdir}/${file}" ]; then
            echo "Please delete ${file} from ${top_srcdir} and start again"
            exit 1
        fi
    done

    cmd_remove

    npm install

    # try to keep this vaguely in sync with what .github/workflows/node_modules-* do
    cp package.json node_modules/.package.json
    cp package-lock.json node_modules/.package-lock.json
    echo /.cache > node_modules/.gitignore

    git -C node_modules init -b main
    git -C node_modules add .
    git -C node_modules -c gc.autoDetach=false commit -a -m "$(sha256sum package.json)"

    cat <<EOF
Next steps:

  - git add node_modules && git commit

EOF
}

# called from tools/test-static-code
cmd_test_static_code() {
    node_modules_update=$(git log --format=%H -n 1 node_modules)
    if ! git --no-pager log --stat --exit-code "${node_modules_update}".. package.json; then
        cat <<EOF
#
# *** The above commits modify package.json without updating node_modules
#
# Try running:
#
#   tools/node-modules rebuild
#
EOF
        exit 1
    fi
}

# called from Makefile.am
cmd_make_package_lock_json() {
    # Run from make to ensure package-lock.json is up to date

    # package-lock.json is used as the stamp file for all things that use
    # node_modules (mostly webpack), so this is the main bit of glue that
    # drives the entire process

    # We try our best not to touch package-lock.json unless it actually changes

    # This isn't going to work for a tarball, but as long as
    # package-lock.json is already there, and newer than package.json,
    # we're OK
    if [ ! -e .git ]; then
        if [ package-lock.json -nt package.json ]; then
            exit 0
        fi

        echo "*** Can't update node modules unless running from git" >&2
        exit 1
    fi

    # Otherwise, our main goal is to ensure that the node_modules from
    # the index is the one that we actually have.
    local sha="$(get_index_gitlink node_modules)"
    if [ ! -e node_modules/.git ]; then
        # nothing there yet...
        cmd_checkout
    elif [ "$(git -C node_modules rev-parse HEAD)" != "${sha}" ]; then
        # wrong thing there...
        cmd_checkout
    fi

    # This check is more about catching local changes to package.json than
    # about validating something we just checked out:
    if ! cmp -s node_modules/.package.json package.json; then
        cat 2>&1 <<EOF
*** package.json is out of sync with node_modules
*** If you modified package.json, please run:
***
***    tools/node-modules rebuild
***
*** and add the result to the index.
EOF
        exit 1
    fi

    # Only copy the package-lock.json if it differs from the one we have
    if ! cmp -s node_modules/.package-lock.json package-lock.json; then
        message COPY package-lock.json
        cp node_modules/.package-lock.json package-lock.json
    fi

    # We're now in a situation where:
    #  - the checked out node_modules is equal to the gitlink in the index
    #  - the package.json in the tree is equal to the one in node_modules
    #  - ditto package-lock.json
    exit 0
}

main() {
    local top_srcdir="$(realpath -m "$0"/../..)"
    cd "${top_srcdir}"

    local cmd="${1-}"

    if [ -z "${cmd}" ]; then
        # don't list the "private" ones
        echo 'This command requires a subcommand: remove checkout rebuild'
        exit 1
    elif ! type -t "cmd_${cmd}" | grep -q function; then
        echo "Unknown subcommand ${cmd}"
        exit 1
    fi

    shift
    [ -n "${quiet}" ] || set -x
    "cmd_$cmd" "$@"
}

main "$@"
