#!/bin/bash

# This script performs different checks on the sample-lnd.conf file:
# 1. Checks that all relevant options of lnd are included.
# 2. Verifies that defaults are labeled if there are also further examples.
# 3. Checks that all default values of lnd are mentioned correctly, including
#    empty defaults and booleans which are set to false by default.

set -e

TAGS="$1"
CONF_FILE=${2:-sample-lnd.conf}

# We are reading the default values of lnd from lnd --help. To avoid formatting
# issues the width of the terminal is set to 240. This needs a workaround for
# CI where we don't have an interactive terminal.
FILE_TMP=$(mktemp)
if [ -t 0 ]; then
    size=($(stty size))
    stty cols 240
    go run -tags="$TAGS" github.com/lightningnetwork/lnd/cmd/lnd --help > \
        $FILE_TMP
    stty cols ${size[1]}
else
    tmux new-session -d -s simulated-terminal -x 240 -y 9999
    tmux send-keys -t simulated-terminal.0 "go run -tags=\"$TAGS\" \
        github.com/lightningnetwork/lnd/cmd/lnd --help >"$FILE_TMP"; \
        tmux wait -S run" ENTER
    tmux wait-for run
    tmux kill-session -t simulated-terminal
fi

LND_HELP="$(cat $FILE_TMP) --end"

# LND_OPTIONS is a list of all options of lnd including the equal sign, which
# is needed to distinguish between booleans and other variables.
# It is created by reading the first two columns of lnd --help. 
LND_OPTIONS="$(cat $FILE_TMP | \
    awk '{
        option=""; 
        if ($1 ~ /^--/){option=$1};
        if ($2 ~ /^--/){option=$2}; 
        if (match(option,  /--[^=]+[=]*/))
            {printf "%s ", substr(option, RSTART, RLENGTH)}
        } 
        END { printf "%s", "--end"}')"
rm $FILE_TMP

# OPTIONS_NO_CONF is a list of all options without any expected entries in 
# sample-lnd.conf. There's no validation needed for these options. 
OPTIONS_NO_CONF="help lnddir configfile version end"


# OPTIONS_NO_LND_DEFAULT_VALUE_CHECK is a list of options with default values
# set, but there aren't any returned defaults by lnd --help. Defaults have to be
# included in sample-lnd.conf but no further checks are performed.
OPTIONS_NO_LND_DEFAULT_VALUE_CHECK="channel-max-fee-exposure adminmacaroonpath \
    readonlymacaroonpath invoicemacaroonpath rpclisten restlisten listen \
    backupfilepath maxchansize bitcoin.chaindir bitcoin.defaultchanconfs \
    bitcoin.defaultremotedelay bitcoin.dnsseed signrpc.signermacaroonpath \
    walletrpc.walletkitmacaroonpath chainrpc.notifiermacaroonpath \
    routerrpc.routermacaroonpath" 


# EXITCODE is returned at the end after all checks are performed and set to 1 
# if a validation error occurs. COUNTER counts the checked options.
EXITCODE=0
COUNTER=0

for OPTION in $LND_OPTIONS; do

    # Determination of the clean name of the option without leading -- and 
    # possible = at the end.
    OPTION_NAME=${OPTION##--}
    OPTION_NAME=${OPTION_NAME%=}


    # Skip if there is no expected entry in sample-lnd.conf.
    echo "$OPTIONS_NO_CONF" | grep -qw $OPTION_NAME && continue
    COUNTER=$((COUNTER+1))

    # Determine the default value of lnd. If the option has no equal sign, 
    # it is boolean and set to false. 
    # For other options we grep the text between the current option and the next
    # option from LND_HELP. The default value is given in brackets (default: xx)
    # In the case of durations expressed in hours or minutes, the indications of 
    # '0m0s' and '0s' are removed, as they provide redundant information.
    # HOME and HOSTNAME are replaced with general values.
    if [[ "$OPTION" == *"="* ]]; then
        OPTION_NEXT="$(echo "$LND_OPTIONS" | sed -E -e "s/.*$OPTION //" \
            -e "s/([^ ]*).*/\1/")"
        DEFAULT_VALUE_LND="$(echo $LND_HELP | \
            sed -E -e "s/.*--${OPTION##--}//" \
            -e "s/--${OPTION_NEXT##--}.*//" \
            -e '/(default:.*)/ {' \
                -e 's/.*\(default: ([^)]*)\).*/\1/' -e 't end' -e '}' \
            -e 's/.*//' -e ':end' \
            -e "s#m0s#m#g" \
            -e "s#h0m#h#g" \
            -e "s#$HOME/Library/Application Support/Lnd#~/.lnd#g" \
            -e "s#$HOME/Library/Application Support/Bitcoin#~/.bitcoin#g" \
            -e "s#$HOME/Library/Application Support/Btcd#~/.btcd#g" \
            -e "s#$HOME#~#g" \
            -e "s#$HOSTNAME#example.com#g")"
    else
        DEFAULT_VALUE_LND="false"
    fi


    # An option is considered included in the sample-lnd.conf if there is
    # a match of the following regex. 
    OPTION_REGEX="^;[ ]*$OPTION_NAME=[^ ]*$"


    # Perform the different checks now. If one fails we move to
    # the next option.
    # 1. check if the option is included in the sample-lnd.conf.
    if [ $(grep -c "$OPTION_REGEX" $CONF_FILE) -eq 0 ]; then
        echo "Option $OPTION_NAME: no default or example included in \
            sample-lnd.conf"
        EXITCODE=1
        continue
    fi
    
    # Skip if no default value check should be performed.
    echo "$OPTIONS_NO_LND_DEFAULT_VALUE_CHECK" | grep -wq $OPTION_NAME && continue

    # 2. Check that the default value is labeled if it is included multiple 
    # times.
    if [ $(grep -c "$OPTION_REGEX" $CONF_FILE) -ge 2 ]; then
        
        # For one option there has to be a preceding line "; Default:" 
        # If it matches we grep the default value from the file.
        if grep -A 1 "^; Default:" $CONF_FILE  | grep -q "$OPTION_REGEX"; then
            DEFAULT_VALUE_CONF="$(grep -A 1 "^; Default:" $CONF_FILE  | \
               grep "$OPTION_REGEX" | cut -d= -f2)"

        else
            echo "Option $OPTION_NAME: mentioned multiple times in \
                sample-lnd.conf but without a default value"
            
            EXITCODE=1
            continue
        fi
    else
        # If there is only one entry in sample-lnd.conf we grep the default 
        # value.
        DEFAULT_VALUE_CONF=$(grep "$OPTION_REGEX" $CONF_FILE | cut -d= -f2)
    fi
    
    # 3. Compare the default value of lnd --help with the value in the
    # sample-lnd.conf file. If lnd doesn't provide a default value, it is
    # allowed for the value in the file to be '0' or '0s'.
    if [ ! "$DEFAULT_VALUE_LND" == "$DEFAULT_VALUE_CONF" ]; then
        
        if [ -z "$DEFAULT_VALUE_LND" ] && [ "$DEFAULT_VALUE_CONF" == "0" ]; then
            true

        elif [ -z "$DEFAULT_VALUE_LND" ] && \
                [ "$DEFAULT_VALUE_CONF" == "0s" ]; then
            true

        else
            echo "Option $OPTION_NAME: defaults don't match - sample-lnd.conf: \
                '$DEFAULT_VALUE_CONF', lnd: '$DEFAULT_VALUE_LND'"
            
            EXITCODE=1
            continue
        fi
    fi
    
done

echo "$COUNTER options were checked"
exit $EXITCODE
