#!/bin/bash
# ak-enter
#
# Using this tool, we can seek a whole zchain, if available from
# an IPFS CID or an IPNS link.
#
# Default (no arguments) will retrieve the local ZCHAIN starting
# from the IPFS CID stored in the file that is tracked by the
# $AK_ZLATEST environment variable.
#
# ak-enter [-n IPNS_LINK]
# ak-enter [IPFS CID]
# ak-enter -N
# ak-enter -h
# ak-enter
## ak-enter [-N | --no-verify] [-l | --limit <number>] [zblock]
## ak-enter [-N | --no-verify] [-l | --limit <number>] -n <zchain>
## Usage:
##     --help, -h                             Print this help and exit
##     --chain <ipns-link>, -n <ipns-link>    Crawl specified chain
##     --no-verify, -N                        Don't verify signatures
##     <ipfs-link>                            Specify IPFS CID for entrance
##
## Note that combined flags don't work for now
## Running with no flags crawls your chain based on AK_ZLATEST environment
## variable
#
# Returns a JSON array representing the chain retrieved.
# Logs messages to $LOGSFILE.

fullprogrampath="$(realpath $0)"
PROGRAM="$(basename $0)"
descriptionString="Crawl an arching kaos chain"
source $AK_LIBDIR/_ak_log
source $AK_LIBDIR/_ak_script
source $AK_LIBDIR/_ak_ipfs
source $AK_LIBDIR/_ak_gpg

# Start of tests
#entrance="QmW5WVXCJfhb4peHG6cbEdamC24vZzMX2Vz386vpENh38U"
#entrance="QmNjQq7GkuXGF8kFT1z2Mv3i4JhY7sBXVUmHDiR1zkQjoE"
#entrance="QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH"
# End of tests
entrance="$(cat $AK_ZLATEST)"

verify=1
limit=0
fromIpns=0

while [ "$#" ]; do
    case "$1" in
        -h | --help)
            _ak_usage
            ;;
        -l | --limit)
            limit=$2
            shift 2
            ;;
        -N | --no-verify)
            verify=0
            shift
            ;;
        -n | --chain | --ipns)
            fromIpns=1
            ipns=$1
            shift
            ol=$1
            entrance="$(_ak_ipns_resolve $1)"
            if [ "$?" -ne 0 ]
            then
                logit "ERROR" "Could not resolve IPNS name"
                exit 1
            fi
            shift
            ;;
        *)
            test="$1"
            if [ ! -z "$test" ] && [ "$fromIpns" == "0" ]
            then
                _ak_ipfs_cid_v0_check "$test"
                entrance="$test"
            elif [ -z "$entrance" ] && [ "$fromIpns" == "1" ]
            then
                entrance="$(cat $AK_ZLATEST)"
            fi
            break
    esac
done

# We assign the IPFS CIDv0 of an empty file as this is used
# as our GENESIS block, hence the "seed" that the tree grows
# from.
seed="$(cat $AK_ZGENESIS)"

# We assume that we found the entrance inside a block, hence
# ZBLOCK is labeled as previous
zblock="$entrance"

# Enter temp folder
TEMPASSIN="$(ak-tempassin)"
cd $TEMPASSIN
counter=0

# The loop
# We break the loop from inside the loop
while true && [ $limit="0" ]
do
    if [ $counter == 0 ]
    then
        echo -n '['
    fi
    counter=$(expr $counter + 1)
    # Check if $zblock exists as variable
    if [ ! -v $zblock ]
    then
        # Check if it is not our seed cause if it is we skip this part
        if [ "$zblock" != "$seed" ]
        then
            # Reset timestamp since it's introduced later
            timestamp=''
            # Announce to logs which ZBLOCK is being read at the moment
            logit "INFO" "Examining $zblock"

            _ak_ipfs_cid_v0_check "$zblock"

            # We check if any $zblock at all
            _ak_ipfs_cat $zblock | jq -c -M > $AK_ZBLOCKDIR/$zblock
            if [ "$?" -ne 0 ]
            then
                logit "ERROR" "ZBLOCK $zblock READ failed"
                exit 1
            fi
            logit "INFO" "ZBLOCK $zblock READ"
            echo -n '{'
#            echo -n '"id":"'$counter'",'
            echo -n '"zblock":"'$zblock'",'

            # If it's JSON formated
            cat $AK_ZBLOCKDIR/$zblock | jq -M > /dev/null 2>&1
            if [ "$?" -ne 0 ]
            then
                logit "ERROR" "ZBLOCK $zblock is not JSON"
                cat /dev/null > $AK_ZBLOCKDIR/$zblock > /dev/null 2>&1
                exit 1
            fi
            logit "INFO" "ZBLOCK $zblock is JSON"

            # Be sure that there are the expected values
            # We need 'block' and 'block_signature' inside a 'zblock'
            # Exit if any is missing
            block="$(cat $AK_ZBLOCKDIR/$zblock | jq -M -r .block)"
            if [ "$block" == "null" ]
            then
                logit "ERROR" "ZBLOCK $zblock has no block"
                exit 1
            fi
            _ak_ipfs_cid_v0_check "$block"
            logit "INFO" "ZBLOCK $zblock has block"

            block_signature="$(cat $AK_ZBLOCKDIR/$zblock | jq -M -r .block_signature)"
            if [ "$block_signature" == "null" ]
            then
                logit "ERROR" "ZBLOCK $zblock doesn't contain a block_signature"
                exit 1
            fi
            _ak_ipfs_cid_v0_check "$block_signature"
            logit "INFO" "ZBLOCK $zblock contains a block_signature"

            # Same as above applies to BLOCK and DATA subparts of each ZBLOCK
            # BLOCKS
            echo -n '"block":"'$block'",'
            _ak_ipfs_cat $block | jq -c -M > $AK_BLOCKDIR/$block
            cat $AK_BLOCKDIR/$block | jq -M > /dev/null 2>&1
            if [ "$?" -ne 0 ]
            then
                logit "ERROR" "BLOCK $block READ failed"
                exit 1
            fi

            grep -e 'timestamp' -e 'gpg' -e 'data' -e 'action' -e 'detach' -e 'previous' $AK_BLOCKDIR/$block > /dev/null 2>&1
            if [ "$?" -ne 0 ]
            then
                logit "ERROR" "BLOCK $block is NOT a valid block"
                exit 1
            fi
            logit "INFO" "BLOCK $block is a block"

            action="$(cat $AK_BLOCKDIR/$block | jq -M -r .action)"
            module="$(echo $action | sed -e 's/\// /g' | awk '{ print $1 }')"
            logit "INFO" "DATA is $module module."

            command="$(echo $action | sed -e 's/\// /g' | awk '{ print $2 }')"
            logit "INFO" "COMMAND is $command"

            timestamp="$(cat $AK_BLOCKDIR/$block | jq -M -r .timestamp)"
            if [ "$timestamp" != "null" ]
            then
                echo -n '"timestamp":"'$timestamp'",'
            fi

            echo -n '"block_signature":"'$block_signature'",'

            detach="$(cat $AK_BLOCKDIR/$block | jq -M -r .detach)"
            echo -n '"detach":"'$detach'",'

            echo -n '"module":"'$module'",'

            echo -n '"action":"'$command'",'

            gpg="$(cat $AK_BLOCKDIR/$block | jq -M -r .gpg)"
            echo -n '"gpg":"'$gpg'",'

            if [ $verify == 1 ]
            then
                _ak_ipfs_get $gpg > /dev/null 2>&1
                if [ "$?" -ne 0 ]
                then
                    logit "ERROR" "Could not get GPG key: $gpg ."
                    exit 1
                fi
                _ak_gpg_key_import_from_file $gpg > /dev/null 2>&1
                if [ "$?" -ne 0 ]
                then
                    logit "ERROR" "Could not import GPG key: $gpg ."
                    exit 1
                fi
                _ak_ipfs_get $block_signature > /dev/null 2>&1
                if [ "$?" -ne 0 ]
                then
                    logit "ERROR" "Error while getting $block_signature for $block"
                    exit 1
                fi
                mv $block_signature $block.asc
                logit "INFO" "Block signature downloaded"

                _ak_ipfs_get $block > /dev/null 2>&1
                if [ "$?" -ne 0 ]
                then
                    logit "ERROR" "Could not get $block block"
                    exit 1
                fi
                logit "INFO" "Downloaded block $block."

                _ak_gpg_verify_signature $block.asc $block > /dev/null 2>&1
                if [ "$?" -ne 0 ]
                then
                    logit "ERROR" "Could not verify $block with GPG key $gpg."
                    exit 1
                fi
                logit "GPG" "$gpg signature of $block is verified."
            fi

            data="$(cat $AK_BLOCKDIR/$block | jq -M -r .data)"
            _ak_ipfs_cid_v0_check "$data"
            ak-data-expand $data $gpg
            if [ "$?" -ne 0 ]
            then
                logit "ERROR" "Failed on data signature verification [data: $data, gpg: $gpg, zblock: $zblock]"
                exit 1
            fi

            # DATA
            # Only print to stdout
            # _ak_ipfs_cat $data
            touch $AK_DATADIR/$data

            # Now, since we sourced the BLOCK to our terminal, we can search
            # for $previous variable. In case we don't find one, we append one
            # and we exit.
            previous="$(cat $AK_BLOCKDIR/$block | jq -M -r .previous)"
            if [ -v $previous ]
            then
                logit "WARNING" "Block $block has no previous zblock, appending pseudo genesis to exit with 2."
                echo -n '"previous":"'$seed'"},{"genesis":"genesis"}]'
                logit "INFO" "Reached pseudo-genesis, counted $counter zblocks."
                exit 2

            # Otherwise, we inform of the sequence
            else
                #echo "$zblock after $previous"
                logit "INFO" "Found a previous block for $zblock: $previous"
                echo -n '"previous":"'$previous'"}'
                zblock=$previous
            fi
            if [ "$limit" != "0" ] && [ "$limit" == "$counter" ]
            then
                echo -n ']'
                exit 0
            else
                echo -n ','
            fi

        # Now check if it is equal to the seed
        # which apparently means we reached the seed.
        elif [ "$zblock" == "$seed" ]
        then
            echo -n '{"genesis":"genesis"}]'
            logit "INFO" "Reached $seed, counted $counter zblocks."
            exit 0
        fi
    # And finally, if nothing is there exit with error
    else
        echo "Check not passed... No previous IPFS CID"
        exit 1
    fi
done