#!/bin/bash
#
# Sugar CLI - Candy Machine automated test
#
# Custom RPC server option can be specified either by the flag -r <url>

CURRENT_DIR=$(pwd)
SCRIPT_DIR=$(cd -- $(dirname -- "${BASH_SOURCE[0]}") &>/dev/null && pwd)
PARENT_DIR="$(dirname "$SCRIPT_DIR")"
ASSETS_DIR=$CURRENT_DIR/assets
CACHE_DIR=$CURRENT_DIR
SUGAR_BIN="cargo run --quiet --bin sugar --"
SUGAR_LOG="sugar.log"
RESUME_FILE="$SCRIPT_DIR/.sugar_resume"

# Remote files to test the upload
PNG_MIN="https://arweave.net/N3LqmO6yURUK1JxV9MJtH8YeqppEtZhKuy3RB0Tqm3A/?ext=png"
PNG="https://arweave.net/yFoNLhe6cBK-wj0n_Wu-XuX7DC75VbMsNKwVbRSz4iQ?ext=png"
GIF="https://arweave.net/-cksjCg70nWw-NE8F-DDR4FGQNfQQrWONWm5TIGt6e8?ext=gif"
JPG="https://arweave.net/X5Czkw4R6EAq5kKW0VgX0oVjLlhn3MV2L0LId0PgZPQ?ext=jpg"
MP4="https://arweave.net/kM6fxv3Qj_Gcn8tcq9dU8wpZAXHNEWvEfVoIpRJzg8c/?ext=mp4"
COLLECTION_PNG="https://arweave.net/Ycr_kDA9ITOTFHDr2W1pgYZxTsf_SsiqiIVwrfiMz4s"

# Metadata URL for large collection tests
COLLECTION_URL="https://arweave.net/V1cFfj1Hl4edgdDMCRZiTm7FbRpbFQm8nyOYo9bCodw"
METADATA_URL="https://arweave.net/uJSdJIsz_tYTcjUEWdeVSj0aR90K-hjDauATWZSi-tQ"
# Media hash (png) for large collection tests
COLLECTION_HASH="6500707cb13044b7d133abb5ad68e0af660b154499229af49419c86a251a2b4d"
MEDIA_HASH="209a200ebea39be9e9e7882da2bc5e652fb690e612abecb094dc13e06db84e54"

METAPLEX_RULE_SET="eBJLFYPxJmMGKuFwpDWkzxZeUrad92kZRC5BJLpzyT9"

# output colours
RED() { echo $'\e[1;31m'$1$'\e[0m'; }
GRN() { echo $'\e[1;32m'$1$'\e[0m'; }
BLU() { echo $'\e[1;34m'$1$'\e[0m'; }
MAG() { echo $'\e[1;35m'$1$'\e[0m'; }
CYN() { echo $'\e[1;36m'$1$'\e[0m'; }

# default test templates
function default_settings() {
    MANUAL_CACHE="n"
    ITEMS=10
    MULTIPLE=1
    TOKEN_STANDARD="nft"
    LIMITED_FILES="n" # creates only one filepair to test hiddenSettings warning

    RESET="Y"
    EXT="png"
    CLOSE="Y"
    CHANGE="n"
    TEST_IMAGE="n"
    HIDDEN="n"

    STORAGE="bundlr"
    ARWEAVE_JWK="null"
    AWS_BUCKET="null"
    AWS_PROFILE="null"
    AWS_DIRECTORY="null"
    AWS_DOMAIN="null"
    PINATA_JWT="null"
    PINATA_API_GATEWAY="null"
    PINATA_CONTENT_GATEWAY="null"
    PINATA_PARALLEL=1
    SDRIVE_API_KEY="null"
}

function max_settings() {
    MANUAL_CACHE="Y"
    MULTIPLE=1

    RESET="Y"
    EXT="png"
    CLOSE="Y"
    CHANGE="n"
    TEST_IMAGE="n"
    HIDDEN="n"

    STORAGE="bundlr"
    ARWEAVE_JWK="null"
    AWS_BUCKET="null"
    AWS_PROFILE="null"
    AWS_DIRECTORY="null"
    AWS_DOMAIN="null"
    PINATA_JWT="null"
    PINATA_API_GATEWAY="null"
    PINATA_CONTENT_GATEWAY="null"
    PINATA_PARALLEL=1
    SDRIVE_API_KEY="null"
}

function mainnet_env() {
    ENV_URL="mainnet-beta"
    RPC="https://api.mainnet-beta.solana.com"
}

function devnet_env() {
    ENV_URL="devnet"
    RPC="https://api.devnet.solana.com"
}

#-----------------------------------------------------------------------------#
# SETUP                                                                       #
#-----------------------------------------------------------------------------#

RESUME=0

echo ""
CYN "Sugar CLI - Candy Machine automated test"
CYN "----------------------------------------"

echo ""
CYN "Test template:"
echo "1. interactive"
echo "2. mainnet-beta"
echo "3. devnet (default)"
echo "4. manual cache"
echo "5. hidden settings"
echo "6. animation"
echo "7. sugar launch"
echo "8. programmable NFT"
echo "9. hidden settings with limited upload"

if [ -f "$RESUME_FILE" ]; then
    echo "10. previous run ($(RED "resume"))"
    echo -n "$(CYN "Select test template [1-10]") (default 3): "
else
    echo -n "$(CYN "Select test template [1-9]") (default 3): "
fi

read Template
case "$Template" in
    1)
        echo ""
        echo "[$(date "+%T")] Starting interactive test"
    ;;
    2)
        mainnet_env
        default_settings
    ;;
    4)
        devnet_env
        max_settings
    ;;
    5)
        devnet_env
        max_settings
        HIDDEN="Y"
        unset CLOSE
    ;;
    6)
        devnet_env
        max_settings
        MANUAL_CACHE="n"
        EXT="mp4"
    ;;
    7)
        devnet_env
        max_settings
        MANUAL_CACHE="n"
        LAUNCH="Y"
    ;;
    8)
        devnet_env
        default_settings
        TOKEN_STANDARD="pnft"
    ;;
    9)
        devnet_env
        max_settings
        HIDDEN="Y"
        LIMITED_FILES="Y"
    ;;
    10)
        source $RESUME_FILE
        RESUME=1
        RESET="n"
    ;;
    *)
        devnet_env
        default_settings
    ;;
esac

# Environment

if [ -z ${ENV_URL+x} ]; then
    echo ""
    CYN "Environment:"
    echo "1. devnet (default)"
    echo "2. mainnet-beta"
    echo -n "$(CYN "Select the environment [1-2]") (default 1): "
    read Input
    case "$Input" in
        2) mainnet_env ;;
        *) devnet_env ;;
    esac
fi

# RPC server can be specified from the command-line with the flag "-r"
# Otherwise the default public one will be used

if [ -z ${RPC+x} ]; then
    RPC="https://api.${ENV_URL}.solana.com"
fi

while getopts r:p flag; do
    case "${flag}" in
        r) RPC=${OPTARG} ;;
        p) SUGAR_BIN="cargo run --release --bin sugar --" ;;
        *) ;;
    esac
done

# Storage

if [ -z ${STORAGE+x} ]; then
    STORAGE="bundlr"

    echo ""
    CYN "Storage type:"
    echo "1. bundlr (default)"
    echo "2. aws"
    echo "3. pinata"
    echo "4. sdrive"
    echo  -n "$(CYN "Select the storage type [1-4]") (default 1): "
    read Input
    case "$Input" in
        1) STORAGE="bundlr" ;;
        2) STORAGE="aws" ;;
        3) STORAGE="pinata" ;;
        4) STORAGE="sdrive" ;;
    esac
fi

# arweave
if [ -z ${ARWEAVE_JWK+x} ]; then
    ARWEAVE_JWK="null"

    if [ "$STORAGE" = "arweave-bundle" ]; then
        echo -n $(CYN "Arweave JWK wallet file: ")
        read ARWEAVE_JWK
    fi
fi

# AWS
if [ -z ${AWS_BUCKET+x} ]; then
    AWS_BUCKET="null"

    if [ "$STORAGE" = "aws" ]; then
        echo -n $(CYN "AWS bucket name: ")
        read AWS_BUCKET
    fi
fi

if [ -z ${AWS_PROFILE+x} ]; then
    AWS_PROFILE="null"

    if [ "$STORAGE" = "aws" ]; then
        echo -n $(CYN "AWS profile name: ")
        read AWS_PROFILE
    fi
fi

if [ -z ${AWS_DIRECTORY+x} ]; then
    AWS_DIRECTORY="null"

    if [ "$STORAGE" = "aws" ]; then
        echo -n $(CYN "AWS directory name: ")
        read AWS_DIRECTORY
    fi
fi

if [ -z ${AWS_DOMAIN+x} ]; then
    AWS_DOMAIN="https://$AWS_BUCKET.s3.amazonaws.com"

    if [ "$STORAGE" = "aws" ]; then
        echo -n "$(CYN "AWS custom domain") (default $AWS_DOMAIN): "
        read Domain

        if [ ! -z "$Domain" ]; then
             AWS_DOMAIN=$Domain
        fi
    fi
fi

# pinata ipfs
if [ -z ${PINATA_JWT+x} ]; then
    PINATA_JWT="null"

    if [ "$STORAGE" = "pinata" ]; then
        echo -n $(CYN "Pinata JWT token: ")
        read PINATA_JWT
    fi
fi

if [ -z ${PINATA_API_GATEWAY+x} ]; then
    PINATA_API_GATEWAY="https://api.pinata.cloud"

    if [ "$STORAGE" = "pinata" ]; then
        echo -n $(CYN "Pinata gateway [$PINATA_API_GATEWAY]: ")
        read Gateway
        if [ ! -z "$Gateway" ]; then
            PINATA_API_GATEWAY=$Gateway
        fi
    fi
fi

if [ -z ${PINATA_CONTENT_GATEWAY+x} ]; then
    PINATA_CONTENT_GATEWAY="https://gateway.pinata.cloud"

    if [ "$STORAGE" = "pinata" ]; then
        echo -n $(CYN "Pinata content gateway [$PINATA_CONTENT_GATEWAY]: ")
        read Content
        if [ ! -z "$Content" ]; then
            PINATA_CONTENT_GATEWAY=$Content
        fi
    fi
fi

if [ -z ${PINATA_PARALLEL+x} ]; then
    PINATA_PARALLEL=1

    if [ "$STORAGE" = "pinata" ]; then
        echo -n $(CYN "Pinata parallel limit [1]: ")
        read Parallel
        if [ ! -z "$Parallel" ]; then
            PINATA_PARALLEL=$(($Parallel + 0))
        fi
    fi
fi

# sdrive
if [ -z ${SDRIVE_API_KEY+x} ]; then
    SDRIVE_API_KEY="null"

    if [ "$STORAGE" = "sdrive" ]; then
        echo -n $(CYN "Sdrive API key: ")
        read SDRIVE_API_KEY
    fi
fi

# Asset type

ANIMATION=0

if [ -z ${EXT+x} ]; then
    IMAGE=$PNG
    EXT="png"
    echo ""
    CYN "Asset type:"
    echo "1. PNG (default)"
    echo "2. JPG"
    echo "3. GIF"
    echo "4. MP4"
    echo -n "$(CYN "Select the file type [1-4]") (default 1): "
    read Input
    case "$Input" in
    1)
        IMAGE=$PNG
        EXT="png"
        ;;
    2)
        IMAGE=$JPG
        EXT="jpg"
        ;;
    3)
        IMAGE=$GIF
        EXT="gif"
        ;;
    4)
        IMAGE=$PNG
        EXT="png"
        ANIMATION=1
        ;;
    esac
else
    case "$EXT" in
    png)
        IMAGE=$PNG
        ;;
    png_min)
        IMAGE=$PNG_MIN
        EXT="png"
        ;;
    jpg)
        IMAGE=$JPG
        ;;
    gif)
        IMAGE=$GIF
        ;;
    mp4)
        IMAGE=$PNG
        EXT="png"
        ANIMATION=1
        ;;
    *)
        RED "[$(date "+%T")] Aborting: invalid asset type ${EXT}"
        exit 1
        ;;
    esac
fi

# Token standard

if [ -z ${TOKEN_STANDARD+x} ]; then
    echo ""
    CYN "Token Standard:"
    echo "1. Non-Fungible (default)"
    echo "2. Programmable Non-Fungible"
    echo -n "$(CYN "Select the token standard [1-2]") (default 1): "
    read Input
    case "$Input" in
        2) TOKEN_STANDARD="pnft" ;;
        *) TOKEN_STANDARD="nft" ;;
    esac
fi

# Collection size

if [ -z ${ITEMS+x} ]; then
    echo ""
    echo -n "$(CYN "Number of items") (default 10): "
    read Number

    if [ -z "$Number" ]; then
        ITEMS=10
    else
        # make sure we are dealing with a number
        ITEMS=$(($Number + 0))
    fi
fi

# Mint tokens

if [ -z ${MULTIPLE+x} ]; then
    echo ""
    echo -n "$(CYN "Number of tokens to mint") (default 1): "
    read Number

    if [ -z "$Number" ]; then
        MULTIPLE=1
    else
        # make sure we are dealing with a number
        MULTIPLE=$(($Number + 0))
    fi
fi

# Enable hidden settings

if [ -z ${HIDDEN+x} ]; then
    echo ""
    echo -n "$(CYN "Enable hidden settings [Y/n]") (default 'n'): "
    read HIDDEN
    if [ -z "$HIDDEN" ]; then
        HIDDEN="n"
    fi
fi

# Test image.extension instead of index

if [ -z ${TEST_IMAGE+x} ]; then
    echo ""
    echo -n "$(CYN "Test image.ext replacement [Y/n]") (default 'n'): "
    read TEST_IMAGE
    if [ -z "$TEST_IMAGE" ]; then
        TEST_IMAGE="n"
    fi
fi

# Test reupload

if [ -z ${CHANGE+x} ]; then
    echo ""
    echo -n "$(CYN "Test re-deploy [Y/n]") (default 'n'): "
    read CHANGE
    if [ -z "$CHANGE" ]; then
        CHANGE="n"
    fi
fi

# Clean up

if [ -z ${RESET+x} ]; then
    echo ""
    echo -n "$(CYN "Remove previous cache and assets [Y/n]") (default 'Y'): "
    read RESET
    if [ -z "$RESET" ]; then
        RESET="Y"
    fi
fi

if [ -z ${CLOSE+x} ]; then
    echo ""
    echo -n "$(CYN "Close candy machine and withdraw funds at the end [Y/n]") (default 'Y'): "
    read CLOSE
    if [ -z "$CLOSE" ]; then
        CLOSE="Y"
    fi
fi

echo ""

#-----------------------------------------------------------------------------#
# SETTING UP                                                                  #
#-----------------------------------------------------------------------------#

# Wallet keypair file

WALLET_KEY="$(solana config get keypair | cut -d : -f 2)"
CACHE_NAME="sugar-test"
CACHE_FILE="$CACHE_DIR/cache-${CACHE_NAME}.json"
LAST_INDEX=$((ITEMS - 1))

TIMESTAMP=`date "+%d/%m/%y %T"`

# removes temporary files
function clean_up {
    rm $CONFIG_FILE 2>/dev/null
    rm -rf $ASSETS_DIR 2>/dev/null
    rm -rf $CACHE_FILE 2>/dev/null
    rm -rf $SUGAR_LOG 2>/dev/null
    rm -rf test_item 2>/dev/null
}

if [ "${RESET}" = "Y" ]; then
    echo "[$(date "+%T")] Removing previous cache and assets"
    clean_up
fi

# preparing the assets metadata
read -r -d $'\0' METADATA <<-EOM
{
    "name": "[$TIMESTAMP] Test #%s",
    "symbol": "TEST",
    "description": "Sugar CLI Test #%s",
    "seller_fee_basis_points": 500,
    "image": "%s"%b
    "attributes": [{"trait_type": "Flavour", "value": "Sugar"}],
    "properties": {
        "files": [
        {
            "uri": "%s",
            "type": "%s"
        }%b
        "category": "%s"
    }
}
EOM

read -r -d $'\0' COLLECTION <<-EOM
{
    "name": "[$TIMESTAMP] Collection",
    "symbol": "TEST",
    "description": "Sugar CLI Collection",
    "seller_fee_basis_points": 500,
    "image": "collection.png",
    "attributes": [{"trait_type": "Flavour", "value": "Sugar"}],
    "properties": {
        "files": [
        {
            "uri": "collection.png",
            "type": "image/png"
        }],
        "category": "image"
    }
}
EOM

if [ $RESUME -eq 0 ]; then
    echo "[$(date "+%T")] Creating assets"

    # Creation of the collection. This will generate ITEMS x (json, image)
    # files in the ASSETS_DIR

    if [ ! -d $ASSETS_DIR ]; then
        mkdir $ASSETS_DIR
        # loads the animation asset
        if [ "$ANIMATION" -eq 1 ]; then
            curl -L -s $MP4 >"$ASSETS_DIR/template_animation.mp4"
            SIZE=$(wc -c "$ASSETS_DIR/template_animation.mp4" | grep -oE '[0-9]+' | head -n 1)

            if [ $SIZE -eq 0 ]; then
                RED "[$(date "+%T")] Aborting: could not download sample mp4"
                exit 1
            fi
        fi

        curl -L -s $IMAGE >"$ASSETS_DIR/template_image.$EXT"
        SIZE=$(wc -c "$ASSETS_DIR/template_image.$EXT" | grep -oE '[0-9]+' | head -n 1)

        if [ $SIZE -eq 0 ]; then
            RED "[$(date "+%T")] Aborting: could not download sample image"
            exit 1
        fi

        # initialises the assets - this will be multiple copies of the same
        # image/json pair with a new index
        INDEX="image"
        TEMP_ITEMS=$ITEMS
        if [ "$LIMITED_FILES" = "Y" ]; then
            TEMP_ITEMS=$ITEMS
            ITEMS=1
            printf "TEMP_ITEMS updated to $TEMP_ITEMS"
        fi

        for ((i = 0; i < $ITEMS; i++)); do
            if [ ! "$TEST_IMAGE" = "Y" ]; then
                INDEX=$i
            fi
            NAME=$(($i + 1))
            MEDIA_NAME="$INDEX.$EXT"
            MEDIA_TYPE="image/$EXT"
            ANIMATION_URL=","
            ANIMATION_FILE="],"
            CATEGORY="image"
            cp "$ASSETS_DIR/template_image.$EXT" "$ASSETS_DIR/$i.$EXT"
            if [ "$ANIMATION" = 1 ]; then
                cp "$ASSETS_DIR/template_animation.mp4" "$ASSETS_DIR/$i.mp4"
                ANIMATION_URL=",\n\t\"animation_url\": \"$i.mp4\","
                ANIMATION_FILE=",\n\t\t{\n\t\t\t\"uri\": \"$i.mp4\",\n\t\t\t\"type\": \"video/mp4\"\n\t\t}],"
                CATEGORY="video"
            fi
            printf "$METADATA" "$NAME" "$NAME" "$MEDIA_NAME" "$ANIMATION_URL" "$MEDIA_NAME" "$MEDIA_TYPE" "$ANIMATION_FILE" "$CATEGORY" > "$ASSETS_DIR/$i.json"
        done

        ITEMS=$TEMP_ITEMS
        rm "$ASSETS_DIR/template_image.$EXT"
        # quietly removes the animation template (it might not exist)
        rm -f "$ASSETS_DIR/template_animation.mp4"

        # creates the collection nft assets
        curl -L -s $COLLECTION_PNG >"$ASSETS_DIR/collection.png"
        SIZE=$(wc -c "$ASSETS_DIR/collection.png" | grep -oE '[0-9]+' | head -n 1)

        if [ $SIZE -eq 0 ]; then
            RED "[$(date "+%T")] Aborting: could not download collection sample image"
            exit 1
        fi
        printf "$COLLECTION" > "$ASSETS_DIR/collection.json"
    fi

    if [ "$MANUAL_CACHE" == "Y" ]; then
        echo -n "{\"program\":{\"candyMachine\":\"\", \"candyGuard\":\"\", \"candyMachineCreator\":\"\", \"collectionMint\":\"\"}, \"items\":{" >> $CACHE_FILE

        NAME="Collection"
        METADATA_HASH=`sha256sum "$ASSETS_DIR/collection.json" | cut -d ' ' -f 1`
        echo "\"-1\":{\"name\":\"[$TIMESTAMP] $NAME\",\"image_hash\":\"$COLLECTION_HASH\",\"image_link\":\"$COLLECTION_PNG\",\"metadata_hash\":\"$METADATA_HASH\",\"metadata_link\":\"$COLLECTION_URL\",\"onChain\":false}," >> $CACHE_FILE
        
        TEMP_ITEMS=$ITEMS
        if [ "$LIMITED_FILES" = "Y" ]; then
            TEMP_ITEMS=$ITEMS
            ITEMS=1
            printf "TEMP_ITEMS updated to $TEMP_ITEMS"
        fi
        for ((i = 0; i < $ITEMS; i++)); do
            if [ "$i" -gt "0" ]; then
                echo -n "," >> $CACHE_FILE
            fi
            INDEX=$(($i + 1))

            if [ "$HIDDEN" == "Y" ]; then
                NAME="Reveal Item #$INDEX"
            else
                NAME="[$TIMESTAMP] Test #$INDEX"
            fi

            METADATA_HASH=`sha256sum "$ASSETS_DIR/$i.json" | cut -d ' ' -f 1`
            echo -n "\"$i\":{\"name\":\"$NAME\",\"image_hash\":\"$MEDIA_HASH\",\"image_link\":\"$PNG\",\"metadata_hash\":\"$METADATA_HASH\",\"metadata_link\":\"$METADATA_URL\",\"onChain\":false}" >> $CACHE_FILE
        done
        ITEMS=$TEMP_ITEMS

        echo -n "}}" >> $CACHE_FILE
    fi
fi

# Candy Machine configuration

CONFIG_FILE="config.json"

if [ "$HIDDEN" = "Y" ]; then
    HIDDEN_SETTINGS="{\"name\":\"Hidden Item #\$ID+1\$\",\"uri\":\"$METADATA_URL\",\"hash\":\"44kiGWWsSgdqPMvmqYgTS78Mx2BKCWzd\"}"
else
    HIDDEN_SETTINGS="null"
fi

cat >$CONFIG_FILE <<-EOM
{
    "tokenStandard": "${TOKEN_STANDARD}",
    "number": $ITEMS,
    "symbol": "TEST",
    "sellerFeeBasisPoints": 500,
    "isMutable": true,
    "isSequential": false,
    "creators": [
        {
            "address": "$(solana address)",
            "share": 100
        }
    ],
    "uploadMethod": "${STORAGE}",
    "ruleSet": "${METAPLEX_RULE_SET}",
    "awsConfig": {
        "bucket": "${AWS_BUCKET}",
        "profile": "${AWS_PROFILE}",
        "directory": "${AWS_DIRECTORY}",
        "domain": "${AWS_DOMAIN}"
    },
    "pinataConfig": {
        "jwt": "${PINATA_JWT}",
        "apiGateway": "${PINATA_API_GATEWAY}",
        "contentGateway": "${PINATA_CONTENT_GATEWAY}",
        "parallelLimit": ${PINATA_PARALLEL}
    },
    "sdriveApiKey": "${SDRIVE_API_KEY}",
    "hiddenSettings": $HIDDEN_SETTINGS
}
EOM

# Resume checkpoint

cat >$RESUME_FILE <<-EOM
#!/bin/bash

MANUAL_CACHE="$MANUAL_CACHE"
ITEMS=$ITEMS
MULTIPLE=$MULTIPLE
TOKEN_STANDARD="$TOKEN_STANDARD"

RESET="$RESET"
EXT="$EXT"
CLOSE="$CLOSE"
CHANGE="$CHANGE"
TEST_IMAGE="$TEST_IMAGE"
HIDDEN="$HIDDEN"

ARWEAVE_JWK="$ARWEAVE_JWK"
AWS_BUCKET="$AWS_BUCKET"
AWS_PROFILE="$AWS_PROFILE"
AWS_DIRECTORY="$AWS_DIRECTORY"
AWS_DOMAIN="$AWS_DOMAIN"
PINATA_JWT="$PINATA_JWT"
PINATA_API_GATEWAY="$PINATA_API_GATEWAY"
PINATA_CONTENT_GATEWAY="$PINATA_CONTENT_GATEWAY"
PINATA_PARALLEL=$PINATA_PARALLEL
SDRIVE_API_KEY="$SDRIVE_API_KEY"

ENV_URL="$ENV_URL"
RPC="$RPC"
STORAGE="$STORAGE"
EOM

#-----------------------------------------------------------------------------#
# AUXILIARY FUNCTIONS                                                         #
#-----------------------------------------------------------------------------#

# edit cache file for reupload
function change_cache {
    cat $CACHE_FILE | jq -c ".items.\"0\".onChain=false|.items.\"0\".name=\"Changed #0\"|del(.items.\""$LAST_INDEX"\")" \
        >$CACHE_FILE.tmp && mv $CACHE_FILE.tmp $CACHE_FILE
    if [[ $(cat $CACHE_FILE | grep "Changed #0") ]]; then
        GRN "Success: cache file changed"
    else 
        RED "Failure: cache file was not changed"
    fi
}

# run the upload command
function upload {
    $SUGAR_BIN upload -c ${CONFIG_FILE} --keypair $WALLET_KEY --cache $CACHE_FILE -r $RPC $ASSETS_DIR
    EXIT_CODE=$?
    if [ ! $EXIT_CODE -eq 0 ]; then
        MAG "<<<"
        RED "[$(date "+%T")] Aborting: upload failed"
        exit 1
    fi
}

# run the deploy command
function deploy {
    $SUGAR_BIN deploy -c ${CONFIG_FILE} --keypair $WALLET_KEY --cache $CACHE_FILE -r $RPC
    EXIT_CODE=$?
    if [ ! $EXIT_CODE -eq 0 ]; then
        MAG "<<<"
        RED "[$(date "+%T")] Aborting: deploy failed"
        exit 1
    fi
}

# run the verify upload command
function verify {
    $SUGAR_BIN verify --keypair $WALLET_KEY --cache $CACHE_FILE -r $RPC
    EXIT_CODE=$?
    if [ ! $EXIT_CODE -eq 0 ]; then
        MAG "<<<"
        RED "[$(date "+%T")] Aborting: verify failed"
        exit 1
    fi
}

# extracts the collection mint from the output of show command
function collection_mint() {
    local RESULT=`$SUGAR_BIN show --keypair $WALLET_KEY --cache $CACHE_FILE -r $RPC | grep "collection" | cut -d ':' -f 3 | tr -d '"'`
    EXIT_CODE=$?
    if [ ! $EXIT_CODE -eq 0 ]; then
        MAG "<<<"
        RED "[$(date "+%T")] Aborting: collection mint lookup failed"
        exit 1
    fi
    echo "$RESULT"
}

#-----------------------------------------------------------------------------#
# COMMAND EXECUTION                                                           #
#-----------------------------------------------------------------------------#

if [ "${CHANGE}" = "Y" ] && [ "$(command -v jq)" = "" ]; then
    echo "[$(date "+%T")] $(RED "Required 'jq' command could not be found, skipping reupload test")"
    CHANGE="n"
fi

echo "[$(date "+%T")] Deploying Candy Machine with $ITEMS items"
echo "[$(date "+%T")] Environment: ${ENV_URL}"
echo "[$(date "+%T")] RPC URL: ${RPC}"
echo "[$(date "+%T")] Testing started using '${STORAGE}' storage"
echo "[$(date "+%T")] Building sugar binary..."

# builds the binary (cargo run is quiet)
cargo build
echo ""

if [ "${HIDDEN}" = "Y" ]; then
    echo "[$(date "+%T")] Config with hidden settings"
fi

if [ "$LAUNCH" = "Y" ]; then
    echo ""
    CYN "Executing Sugar launch: steps [1, 2, 3, 4]"
    echo ""
    MAG ">>>"
    $SUGAR_BIN launch -c ${CONFIG_FILE} --keypair $WALLET_KEY --cache $CACHE_FILE -r $RPC $ASSETS_DIR --skip-collection-prompt
    EXIT_CODE=$?
    MAG "<<<"
    
    if [ ! $EXIT_CODE -eq 0 ]; then
        RED "[$(date "+%T")] Aborting: launch failed"
        exit 1
    fi
else
    echo ""
    CYN "1. Validating JSON metadata files"
    echo ""
    MAG ">>>"
    $SUGAR_BIN validate $ASSETS_DIR --skip-collection-prompt
    EXIT_CODE=$?
    MAG "<<<"

    if [ ! $EXIT_CODE -eq 0 ]; then
        RED "[$(date "+%T")] Aborting: validation failed"
        exit 1
    fi

    echo ""
    CYN "2. Uploading assets"
    echo ""
    MAG ">>>"
    upload
    MAG "<<<"
    echo ""

    echo ""
    CYN "3. Deploying Candy Machine"
    echo ""
    MAG ">>>"
    deploy
    MAG "<<<"
    echo ""

    echo ""
    CYN "4. Verifying deployment"
    echo ""
    MAG ">>>"
    verify
    MAG "<<<"
fi

echo ""
if [ ! "$MANUAL_CACHE" == "Y" ]; then
    CYN "5. Verifying collection mint"
    echo ""
    COLLECTION_PDA=$(collection_mint)

    if [ -z ${COLLECTION_PDA} ]; then
        RED "[$(date "+%T")] Aborting: collection mint not found"
        exit 1
    fi

    echo "Collection mint:$(GRN "$COLLECTION_PDA")"
else
    CYN "5. Verifying collection mint (Skipped)"
fi

echo ""
if [ "${CHANGE}" = "Y" ]; then
    CYN "6. Editing cache and testing re-deploy"
    echo ""
    MAG ">>>"
    change_cache
    deploy
    verify
    MAG "<<<"
else
    CYN "6. Editing cache and testing re-deploy (Skipped)"
fi

echo ""
CYN "7. Minting"
echo ""
MAG ">>>"
$SUGAR_BIN mint --keypair $WALLET_KEY --cache $CACHE_FILE -r $RPC -n $MULTIPLE
EXIT_CODE=$?
MAG "<<<"

if [ ! $EXIT_CODE -eq 0 ]; then
    RED "[$(date "+%T")] Aborting: mint failed"
    exit 1
fi

if [ "${CLOSE}" = "Y" ]; then
    CANDY_MACHINE_ID=`cat $CACHE_FILE | sed -n -e 's/\(\"candyMachine\": \"\)\([a-zA-Z0-9]*\)\(.*\)/\2/p'`
    echo ""
    CYN "8. Withdrawing Candy Machine funds and clean up"
    echo ""
    MAG ">>>"
    $SUGAR_BIN withdraw --keypair $WALLET_KEY -r $RPC --candy-machine $CANDY_MACHINE_ID
    EXIT_CODE=$?
    MAG "<<<"
    
    if [ ! $EXIT_CODE -eq 0 ]; then
        RED "[$(date "+%T")] Aborting: withdraw failed"
        exit 1
    fi

    echo ""
    echo "[$(date "+%T")] Removing generated files"

    clean_up
else
    echo ""
fi

# save to delete the resume checkpoint
rm -rf $RESUME_FILE 2>/dev/null

echo "[$(date "+%T")] Test completed"