#!/bin/env bash
set -euo pipefail

echo "Running cardano node ..."

[[ -n ${DEBUG:-} ]] && set -x

# Define a few defaults
CARDANO_CONFIG_BASE="/opt/cardano/config"

if [[ -z ${CARDANO_CONFIG:-} ]]; then
  CARDANO_CONFIG="$CARDANO_CONFIG_BASE/mainnet/config.json"
fi

if [[ -z ${CARDANO_TOPOLOGY:-} ]]; then
  CARDANO_TOPOLOGY="$CARDANO_CONFIG_BASE/mainnet/topology.json"
fi

# Breaking change from the historical default of: /opt/cardano/data
# in order to align both the "scripts" and "custom" modes of image operation.
# Prefer root mountpoints for consistency via symlink /opt/cardano/data -> /data
if [[ -z ${CARDANO_DATABASE_PATH:-} ]]; then
  CARDANO_DATABASE_PATH="/data/db"
fi

# Breaking change from the historical default of: /opt/cardano/ipc/socket
# in order to align both the "scripts" and "custom" modes of image operation.
# Prefer root mountpoints for consistency via symlink /opt/cardano/ipc -> /ipc
if [[ -z ${CARDANO_SOCKET_PATH:-} ]]; then
  CARDANO_SOCKET_PATH="/ipc/node.socket"
fi

if [[ -z ${CARDANO_LOG_DIR:-} ]]; then
  CARDANO_LOG_DIR="/opt/cardano/logs"
fi

if [[ -z ${CARDANO_BIND_ADDR:-} ]]; then
  CARDANO_BIND_ADDR="0.0.0.0"
fi

if [[ -z ${CARDANO_PORT:-} ]]; then
  CARDANO_PORT=3001
fi

if [[ -z ${CARDANO_BLOCK_PRODUCER:-} ]]; then
  CARDANO_BLOCK_PRODUCER=false
fi

# Block producer key defaults -- only relevant when CARDANO_BLOCK_PRODUCER=true
if [[ $CARDANO_BLOCK_PRODUCER == true ]]; then
  # Only default the KES key when not using a KES agent socket
  if [[ -z ${CARDANO_SHELLEY_KES_AGENT_SOCKET:-} && -z ${CARDANO_SHELLEY_KES_KEY:-} ]]; then
    CARDANO_SHELLEY_KES_KEY="$CARDANO_CONFIG_BASE/keys/kes.skey"
  fi

  if [[ -z ${CARDANO_SHELLEY_VRF_KEY:-} ]]; then
    CARDANO_SHELLEY_VRF_KEY="$CARDANO_CONFIG_BASE/keys/vrf.skey"
  fi

  if [[ -z ${CARDANO_SHELLEY_OPERATIONAL_CERTIFICATE:-} ]]; then
    CARDANO_SHELLEY_OPERATIONAL_CERTIFICATE="$CARDANO_CONFIG_BASE/keys/node.cert"
  fi
fi

#####################################################################
#
# Print run environment
#
printRunEnv () {

  echo "CARDANO_BIND_ADDR=$CARDANO_BIND_ADDR"
  echo "CARDANO_BLOCK_PRODUCER=$CARDANO_BLOCK_PRODUCER"
  echo "CARDANO_CONFIG=$CARDANO_CONFIG"
  echo "CARDANO_DATABASE_PATH=$CARDANO_DATABASE_PATH"
  echo "CARDANO_LOG_DIR=$CARDANO_LOG_DIR"
  echo "CARDANO_PORT=$CARDANO_PORT"
  echo "CARDANO_SOCKET_PATH=$CARDANO_SOCKET_PATH"
  echo "CARDANO_TOPOLOGY=$CARDANO_TOPOLOGY"
  [[ -n ${CARDANO_TRACER_SOCKET_NETWORK_ACCEPT:-} ]] && echo "CARDANO_TRACER_SOCKET_NETWORK_ACCEPT=$CARDANO_TRACER_SOCKET_NETWORK_ACCEPT"
  [[ -n ${CARDANO_TRACER_SOCKET_NETWORK_CONNECT:-} ]] && echo "CARDANO_TRACER_SOCKET_NETWORK_CONNECT=$CARDANO_TRACER_SOCKET_NETWORK_CONNECT"
  [[ -n ${CARDANO_TRACER_SOCKET_PATH_ACCEPT:-} ]] && echo "CARDANO_TRACER_SOCKET_PATH_ACCEPT=$CARDANO_TRACER_SOCKET_PATH_ACCEPT"
  [[ -n ${CARDANO_TRACER_SOCKET_PATH_CONNECT:-} ]] && echo "CARDANO_TRACER_SOCKET_PATH_CONNECT=$CARDANO_TRACER_SOCKET_PATH_CONNECT"

  if [[ ${CARDANO_BLOCK_PRODUCER} == true ]]; then
    if [[ -n ${CARDANO_SHELLEY_KES_AGENT_SOCKET:-} ]]; then
      echo "CARDANO_SHELLEY_KES_AGENT_SOCKET=$CARDANO_SHELLEY_KES_AGENT_SOCKET"
    else
      echo "CARDANO_SHELLEY_KES_KEY=$CARDANO_SHELLEY_KES_KEY"
    fi
    echo "CARDANO_SHELLEY_VRF_KEY=$CARDANO_SHELLEY_VRF_KEY"
    echo "CARDANO_SHELLEY_OPERATIONAL_CERTIFICATE=$CARDANO_SHELLEY_OPERATIONAL_CERTIFICATE"
  fi
}

#####################################################################
#
# Write root env file
#
writeRootEnv () {

cat << EOF > /usr/local/bin/env
#!/usr/bin/env bash

# Docker run ENV vars
EOF

if [[ -n ${CARDANO_SHELLEY_KES_AGENT_SOCKET:-} ]]; then
  echo "CARDANO_SHELLEY_KES_AGENT_SOCKET=\"$CARDANO_SHELLEY_KES_AGENT_SOCKET\"" \
    >> /usr/local/bin/env
fi

if [[ -n ${CARDANO_TRACER_SOCKET_NETWORK_ACCEPT:-} ]]; then
  echo "CARDANO_TRACER_SOCKET_NETWORK_ACCEPT=\"$CARDANO_TRACER_SOCKET_NETWORK_ACCEPT\"" \
    >> /usr/local/bin/env
fi

if [[ -n ${CARDANO_TRACER_SOCKET_NETWORK_CONNECT:-} ]]; then
  echo "CARDANO_TRACER_SOCKET_NETWORK_CONNECT=\"$CARDANO_TRACER_SOCKET_NETWORK_CONNECT\"" \
    >> /usr/local/bin/env
fi

if [[ -n ${CARDANO_TRACER_SOCKET_PATH_ACCEPT:-} ]]; then
  echo "CARDANO_TRACER_SOCKET_PATH_ACCEPT=\"$CARDANO_TRACER_SOCKET_PATH_ACCEPT\"" \
    >> /usr/local/bin/env
fi

if [[ -n ${CARDANO_TRACER_SOCKET_PATH_CONNECT:-} ]]; then
  echo "CARDANO_TRACER_SOCKET_PATH_CONNECT=\"$CARDANO_TRACER_SOCKET_PATH_CONNECT\"" \
    >> /usr/local/bin/env
fi

cat << EOF >> /usr/local/bin/env
CARDANO_BIND_ADDR="$CARDANO_BIND_ADDR"
CARDANO_BLOCK_PRODUCER=$CARDANO_BLOCK_PRODUCER
CARDANO_CONFIG="$CARDANO_CONFIG"
CARDANO_DATABASE_PATH="$CARDANO_DATABASE_PATH"
CARDANO_LOG_DIR="$CARDANO_LOG_DIR"
CARDANO_PORT=$CARDANO_PORT
CARDANO_SOCKET_PATH="$CARDANO_SOCKET_PATH"
CARDANO_TOPOLOGY="$CARDANO_TOPOLOGY"

CARDANO_PUBLIC_IP="${CARDANO_PUBLIC_IP:-}"
CARDANO_CUSTOM_PEERS="${CARDANO_CUSTOM_PEERS:-}"

# Mapping for topologyUpdater
CNODE_HOSTNAME="${CARDANO_PUBLIC_IP:-}"
CNODE_PORT=$CARDANO_PORT
CUSTOM_PEERS="${CARDANO_CUSTOM_PEERS:-}"

# Derived from CARDANO_CONFIG to support non-mainnet deployments
GENESIS_JSON="$(dirname "$CARDANO_CONFIG")/shelley-genesis.json"

TOPOLOGY="$CARDANO_TOPOLOGY"
LOG_DIR="$CARDANO_LOG_DIR"
EOF
}

#####################################################################
#
# Run the node (relay or block producer depending on CARDANO_BLOCK_PRODUCER)
#
runNode () {

  effopts=(
    "--config" "$CARDANO_CONFIG"
    "--topology" "$CARDANO_TOPOLOGY"
    "--database-path" "$CARDANO_DATABASE_PATH"
    "--socket-path" "$CARDANO_SOCKET_PATH"
    "--host-addr" "$CARDANO_BIND_ADDR"
    "--port" "$CARDANO_PORT"
  )

  if [[ $CARDANO_BLOCK_PRODUCER == true ]]; then
    if [[ -n ${CARDANO_SHELLEY_KES_AGENT_SOCKET:-} ]]; then
      effopts+=(
        "--shelley-kes-agent-socket" "$CARDANO_SHELLEY_KES_AGENT_SOCKET"
      )
    else
      effopts+=(
        "--shelley-kes-key" "$CARDANO_SHELLEY_KES_KEY"
      )
    fi
    effopts+=(
      "--shelley-vrf-key" "$CARDANO_SHELLEY_VRF_KEY"
      "--shelley-operational-certificate" "$CARDANO_SHELLEY_OPERATIONAL_CERTIFICATE"
    )
  fi
  [[ -n ${CARDANO_TRACER_SOCKET_NETWORK_ACCEPT:-} ]] && effopts+=("--tracer-socket-network-accept" "$CARDANO_TRACER_SOCKET_NETWORK_ACCEPT")
  [[ -n ${CARDANO_TRACER_SOCKET_NETWORK_CONNECT:-} ]] && effopts+=("--tracer-socket-network-connect" "$CARDANO_TRACER_SOCKET_NETWORK_CONNECT")
  [[ -n ${CARDANO_TRACER_SOCKET_PATH_ACCEPT:-} ]] && effopts+=("--tracer-socket-path-accept" "$CARDANO_TRACER_SOCKET_PATH_ACCEPT")
  [[ -n ${CARDANO_TRACER_SOCKET_PATH_CONNECT:-} ]] && effopts+=("--tracer-socket-path-connect" "$CARDANO_TRACER_SOCKET_PATH_CONNECT")

  effopts+=("${filteredOpts[@]}")

  echo "cardano-node run ${effopts[*]}"
  exec /usr/local/bin/cardano-node run "${effopts[@]}"
}

# Discard the leading subcommand argument (e.g. "run") passed by the entrypoint
shift

# Override default values with explicit options
options=("$@")

for i in "${!options[@]}"
do
    j=$((i + 1))
    key=${options[i]}
    val=${options[j]:-}
    found=false

    # echo "$i/$j: ${key} ${val}"

    case ${key} in
      --config) CARDANO_CONFIG=${val}; found=true;;
      --topology) CARDANO_TOPOLOGY=${val}; found=true;;
      --database-path) CARDANO_DATABASE_PATH=${val}; found=true;;
      --socket-path) CARDANO_SOCKET_PATH=${val}; found=true;;
      --host-addr) CARDANO_BIND_ADDR=${val}; found=true;;
      --port) CARDANO_PORT=${val}; found=true;;
      --shelley-kes-agent-socket) CARDANO_SHELLEY_KES_AGENT_SOCKET=${val}; found=true;;
      --shelley-kes-key) CARDANO_SHELLEY_KES_KEY=${val}; found=true;;
      --shelley-vrf-key) CARDANO_SHELLEY_VRF_KEY=${val}; found=true;;
      --shelley-operational-certificate) CARDANO_SHELLEY_OPERATIONAL_CERTIFICATE=${val}; found=true;;
      --tracer-socket-network-accept) CARDANO_TRACER_SOCKET_NETWORK_ACCEPT=${val}; found=true;;
      --tracer-socket-network-connect) CARDANO_TRACER_SOCKET_NETWORK_CONNECT=${val}; found=true;;
      --tracer-socket-path-accept) CARDANO_TRACER_SOCKET_PATH_ACCEPT=${val}; found=true;;
      --tracer-socket-path-connect) CARDANO_TRACER_SOCKET_PATH_CONNECT=${val}; found=true;;
    esac

    if [[ $found == true ]]; then
      options[i]="";
      options[j]="";
    fi
done

# Filter blank args from match removal above
filteredOpts=()
for arg in "${options[@]}"; do
  [[ -n $arg ]] && filteredOpts+=("$arg")
done

if [[ -n ${CARDANO_SHELLEY_KES_KEY:-} && -n ${CARDANO_SHELLEY_KES_AGENT_SOCKET:-} ]]; then
  echo "ERROR: CARDANO_SHELLEY_KES_KEY and CARDANO_SHELLEY_KES_AGENT_SOCKET are mutually exclusive; use one or the other, not both."
  exit 1
fi

printRunEnv
writeRootEnv

# Verify required files exist before launching
for f in "$CARDANO_CONFIG" "$CARDANO_TOPOLOGY"; do
  [[ -f $f ]] || { echo "ERROR: required file not found: $f"; exit 1; }
done
if [[ $CARDANO_BLOCK_PRODUCER == true ]]; then
  if [[ -z ${CARDANO_SHELLEY_KES_AGENT_SOCKET:-} ]]; then
    [[ -f $CARDANO_SHELLEY_KES_KEY ]] || { echo "ERROR: required block producer key file not found: $CARDANO_SHELLEY_KES_KEY"; exit 1; }
  fi
  for f in "$CARDANO_SHELLEY_VRF_KEY" "$CARDANO_SHELLEY_OPERATIONAL_CERTIFICATE"; do
    [[ -f $f ]] || { echo "ERROR: required block producer key file not found: $f"; exit 1; }
  done
fi

# The IPC socket dir is not created on demand
mkdir -p "$(dirname "$CARDANO_SOCKET_PATH")"

runNode
