#!/bin/bash

set -o errexit
set -o nounset
set -o pipefail

no_dep_exit_code=3
no_structure_file_exit_code=4
no_base_point_exit_code=5

where() {
  local cmd
  cmd="$(command -v "$1")"
  echo "$cmd"
}

e() {
  >&2 echo "$1"
}

# Get script directory
SCRIPT_DIR=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd)

# Get structure file
STRUCTURE_FILE="$SCRIPT_DIR/structure.json"

# Get command locations
JQ_CMD="$(where jq)"
PERL_CMD="$(where perl)"

# Test for `jq` dependency
if ! [ -x "${JQ_CMD}" ]; then
  e "required dependency not found: jq not found in the path or not executable"
  exit ${no_dep_exit_code}
fi

# Test for `perl` dependency
if ! [ -x "${PERL_CMD}" ]; then
  e "required dependency not found: perl not found in the path or not executable"
  exit ${no_dep_exit_code}
fi

# Test for `structure.json` file
if [ ! -f "$STRUCTURE_FILE" ]; then
    echo "Error: No structure.json file" was found
    exit ${no_structure_file_exit_code}
fi

# Get remote base point
BASE_POINT=$("$JQ_CMD" -r .baseDirectory "$SCRIPT_DIR/structure.json")

# Test for `baseDirectory` in `structure.json`
if [ "$BASE_POINT" = "null" ]; then
    echo "Error: No base point in structure.json"
    exit ${no_base_point_exit_code}
fi

echo "Checks passed! Starting ..."

# Setup logging
if [ ! -d "$SCRIPT_DIR/.logs" ]; then
    echo "Done: Creating logs directory"
    mkdir "$SCRIPT_DIR/.logs" && printf "\n"
fi

LOG_ENTRY="$SCRIPT_DIR/.logs/$(date +'%d_%m_%Y_%H-%M-%N').log"
touch "$LOG_ENTRY"

#
# [Remote SSH data]
#
# Remember to set up ControlMaster:
#   @see: https://docs.rc.fas.harvard.edu/kb/using-ssh-controlmaster-for-single-sign-on/
#
SSH_KEY="~/.ssh_keys/key.pem"
SSH_REMOTE="192.0.0.1"
SSH_USER="admin"

# Count total size and files
TOTAL_SIZE=0
TOTAL_FILES=0

# Iterate over entry points
while IFS= read -r KEY; do
    # Get entry value (remote relative path)
    VALUE=$("$JQ_CMD" -r .points.\"$KEY\" "$SCRIPT_DIR/structure.json")
    # Get local directory
    DIR="$SCRIPT_DIR/$KEY"

    if [ -d "$DIR" ]; then
        [ -L "${DIR%/}" ] && continue
        echo "> $KEY => [$BASE_POINT/$VALUE]"

        for FILE in "$DIR"/*; do
            if [ ! -d "$FILE" ] && [ -f "$FILE" ]; then
                FILE_NAME=$(basename "$FILE")
                REMOTE_DEST="$BASE_POINT/$VALUE/$FILE_NAME"

                if ! ssh -n -i "$SSH_KEY" "${SSH_USER}@${SSH_REMOTE}" "ls \"$REMOTE_DEST\" >/dev/null 2>&1"; then
                    echo " > Uploading: $FILE_NAME ..."
                    scp -p -i "$SSH_KEY" "$FILE" "${SSH_USER}@${SSH_REMOTE}:\"$REMOTE_DEST\""
                    if [ $? -eq 0 ]; then
                        FILE_SIZE=$(du -k "$FILE" | cut -f1)

                        TOTAL_SIZE=$((TOTAL_SIZE + FILE_SIZE))
                        TOTAL_FILES=$((TOTAL_FILES + 1))

                        rm "$FILE" && echo " > /$VALUE/$FILE_NAME (+$FILE_SIZE kB)" >> "$LOG_ENTRY"
                    fi
                else
                    rm "$FILE"
                fi
            fi
        done
    fi
done <<< "$("$JQ_CMD" -r '.points | keys[]' "$SCRIPT_DIR/structure.json")"

#
# [Create master.log]
#
# This is a messy way of concentrating the recent logs into a single, master file
# that we will upload to the server as an available status file resource
#
if [ -s "$LOG_ENTRY" ]; then
    echo -e "$(date --utc +%FT%TZ) ($(date +'%:z %Z'))\n\n$(cat "$LOG_ENTRY")" > "$LOG_ENTRY"
    if [ "$TOTAL_SIZE" -gt 0 ]; then
        echo -e "\nTotal Size: +$TOTAL_SIZE kB over $TOTAL_FILES file(s)" >> "$LOG_ENTRY"
    fi
    echo $("$PERL_CMD" -E 'say "=" x 43') >> "$LOG_ENTRY"

    # Get the 10 most recent logs
    LOGS_LATEST=$(ls -Art "$SCRIPT_DIR/.logs/" | tail -n 10 | tac)

    # Create `master.log` if it doesn't exist
    rm "$SCRIPT_DIR/master.log" && touch "$SCRIPT_DIR/master.log"

    # Log header
    echo -e "========= SCHEDULED RECENT UPLOADS ========" >> "$SCRIPT_DIR/master.log"
    echo -e $("$PERL_CMD" -E 'say "=" x 43') >> "$SCRIPT_DIR/master.log"
    echo -e "Updated: $(date --utc +%FT%TZ) ($(date +'%:z %Z'))\n" >> "$SCRIPT_DIR/master.log"
    echo -e "Showing the ten most recent queued batches\n" >> "$SCRIPT_DIR/master.log"
    echo -e $("$PERL_CMD" -E 'say "=" x 43') >> "$SCRIPT_DIR/master.log"

    # Iterate over logs, add them to `master.log`
    while IFS= read -r LOG; do
        cat "$SCRIPT_DIR/.logs/$LOG" >> "$SCRIPT_DIR/master.log"
    done <<< "$LOGS_LATEST"

    # Upload `master.log`
    scp -i "$SSH_KEY" "$SCRIPT_DIR/master.log" "${SSH_USER}@${SSH_REMOTE}:\"$BASE_POINT/recent.txt\""
else
    rm "$LOG_ENTRY"
fi

# Clean up (remove empty log files)
if [ -d "$SCRIPT_DIR/.logs/" ]; then
    for FILE in "$SCRIPT_DIR/.logs/"/*; do
        if [ -f "$FILE" ] && [ ! -s "$FILE" ]; then
            rm "$FILE"
        fi
    done
fi
