#!/usr/bin/env bash

# Run a two node local net with adder-collator.

set -e

chainspec="rococo-local"

# disabled until we can actually successfully register the chain with polkadot-js-api
# if ! command -v polkadot-js-api > /dev/null; then
#   echo "polkadot-js-api required; try"
#   echo "  sudo yarn global add @polkadot/api-cli"
#   exit 1
# fi

PROJECT_ROOT=$(git rev-parse --show-toplevel)
# shellcheck disable=SC1090
source "$(dirname "$0")"/common.sh

cd "$PROJECT_ROOT"

last_modified_rust_file=$(
  find . -path ./target -prune -o -type f -name '*.rs' -printf '%T@ %p\n' |
  sort -nr |
  head -1 |
  cut -d' ' -f2-
)

polkadot="target/release/polkadot"
adder_collator="target/release/adder-collator"

# ensure the polkadot binary exists and is up to date
if [ ! -x "$polkadot" ] || [ "$polkadot" -ot "$last_modified_rust_file" ]; then
  cargo build --release --features real-overseer
fi
# likewise for the adder collator
if [ ! -x "$adder_collator" ] || [ "$adder_collator" -ot "$last_modified_rust_file" ]; then
  cargo build --release --features real-overseer -p test-parachain-adder-collator
fi

genesis="$(mktemp --directory)"
genesis_state="$genesis/state"
validation_code="$genesis/validation_code"

"$adder_collator" export-genesis-state > "$genesis_state"
"$adder_collator" export-genesis-wasm > "$validation_code"


# setup variables
node_offset=0
declare -a node_pids
declare -a node_pipes

# create a sed expression which injects the node name and stream type into each line
function make_sed_expr() {
  name="$1"
  type="$2"

  printf "s/^/%16s %s: /" "$name" "$type"
}

# turn a string into a flag
function flagify() {
  printf -- '--%s' "$(tr '[:upper:]' '[:lower:]' <<< "$1")"
}

# start a node and label its output
#
# This function takes a single argument, the node name.
# The name must be one of those which can be passed to the polkadot binary, in un-flagged form,
# one of:
#   alice, bob, charlie, dave, eve, ferdie, one, two
function run_node() {
  name="$1"
  # create a named pipe so we can get the node's PID while also sedding its output
  local stdout
  local stderr
  stdout=$(mktemp --dry-run --tmpdir)
  stderr=$(mktemp --dry-run --tmpdir)
  mkfifo "$stdout"
  mkfifo "$stderr"
  node_pipes+=("$stdout")
  node_pipes+=("$stderr")

  # compute ports from offset
  local port=$((30333+node_offset))
  local rpc_port=$((9933+node_offset))
  local ws_port=$((9944+node_offset))
  local prometheus_port=$((9615+node_offset))
  node_offset=$((node_offset+1))

  # start the node
  "$polkadot" \
    --chain "$chainspec" \
    --tmp \
    --port "$port" \
    --rpc-port "$rpc_port" \
    --ws-port "$ws_port" \
    --prometheus-port "$prometheus_port" \
    --rpc-cors all \
    "$(flagify "$name")" \
  > "$stdout" \
  2> "$stderr" \
  &
  local pid=$!
  node_pids+=("$pid")

  # send output from the stdout pipe to stdout, prepending the node name
  sed -e "$(make_sed_expr "$name" "OUT")" "$stdout" >&1 &
  # send output from the stderr pipe to stderr, prepending the node name
  sed -e "$(make_sed_expr "$name" "ERR")" "$stderr" >&2 &
}

# start an adder collator and label its output
#
# This function takes a single argument, the node name. This affects only the tagging.
function run_adder_collator() {
  name="$1"
  # create a named pipe so we can get the node's PID while also sedding its output
  local stdout
  local stderr
  stdout=$(mktemp --dry-run --tmpdir)
  stderr=$(mktemp --dry-run --tmpdir)
  mkfifo "$stdout"
  mkfifo "$stderr"
  node_pipes+=("$stdout")
  node_pipes+=("$stderr")

  # compute ports from offset
  local port=$((30333+node_offset))
  local rpc_port=$((9933+node_offset))
  local ws_port=$((9944+node_offset))
  local prometheus_port=$((9615+node_offset))
  node_offset=$((node_offset+1))

  # start the node
  "$adder_collator" \
    --chain "$chainspec" \
    --tmp \
    --port "$port" \
    --rpc-port "$rpc_port" \
    --ws-port "$ws_port" \
    --prometheus-port "$prometheus_port" \
    --rpc-cors all \
  > "$stdout" \
  2> "$stderr" \
  &
  local pid=$!
  node_pids+=("$pid")

  # send output from the stdout pipe to stdout, prepending the node name
  sed -e "$(make_sed_expr "$name" "OUT")" "$stdout" >&1 &
  # send output from the stderr pipe to stderr, prepending the node name
  sed -e "$(make_sed_expr "$name" "ERR")" "$stderr" >&2 &
}


# clean up the nodes when this script exits
function finish {
  for node_pid in "${node_pids[@]}"; do
    kill -9 "$node_pid"
  done
  for node_pipe in "${node_pipes[@]}"; do
    rm "$node_pipe"
  done
  rm -rf "$genesis"
}
trap finish EXIT

# start the nodes
run_node Alice
run_node Bob
run_adder_collator AdderCollator

# register the adder collator
# doesn't work yet due to https://github.com/polkadot-js/tools/issues/185
# polkadot-js-api \
#   --ws ws://localhost:9944 \
#   --sudo \
#   --seed "//Alice" \
#   tx.registrar.registerPara \
#     100 \
#     '{"scheduling":"Always"}' \
#     "@$validation_code" \
#     "@$genesis_state"

# now wait; this will exit on its own only if both subprocesses exit
# the practical implication, as both subprocesses are supposed to run forever, is that
# this script will also run forever, until killed, at which point the exit trap should kill
# the subprocesses
wait
