#!/bin/bash


# start mongodb replicas on port 27017, 27018 and 27019
start() {
  echo "Starting MongoDB at $path/mongodb"
  mongod --config $path/mongodb/mongod-1.conf --fork >/dev/null
  echo "started mongodb instance 1"
  mongod --config $path/mongodb/mongod-2.conf --fork >/dev/null
  echo "started mongodb instance 2"
  mongod --config $path/mongodb/mongod-3.conf --fork >/dev/null
  echo "started mongodb instance 3"
  
  if [[ "$OSTYPE" = "darwin"* ]]; then
    echo  "MacOS detected. No need to wait"
    echo "... done"
  else
    echo  "not MacOS"
    echo "wait 10 sec ..."
    sleep 10
    echo "... done"
  fi
}

# stop mongodb replicas
stop() {
  echo "Stopping MongoDB at $path/mongodb"
    
  if [[ "$OSTYPE" = "darwin"* ]]; then
    echo "macos detected. using pkill"
    pkill mongod
    sleep 1
  else
    echo  "Not MacOS. Using mongod --shutdown command"
    mongod --dbpath $path/mongodb/data-1 --shutdown >/dev/null
    echo "stopped mongodb instance 1"
    mongod --dbpath $path/mongodb/data-2 --shutdown >/dev/null
    echo "stopped mongodb instance 2"
    mongod --dbpath $path/mongodb/data-3 --shutdown >/dev/null
    echo "stopped mongodb instance 3"
    sleep 1
  fi
}

# start mongodb, create folders and replica sets, restart mongodb
setup() {

  if [[ "$OSTYPE" == darwin* ]]; then
 if command -v brew >/dev/null && brew list --formula | grep -q '^mongodb-community@'; then
      echo "brew + mongod OK."
    else
      echo "missing brew or mongodb-community"
      exit 1
    fi
  fi


  echo "stop running mongo db"
  stop

  echo "Creating data and log folders in $path..."
  mkdir -p $path/mongodb
  mkdir -p $path/mongodb/data-1
  mkdir -p $path/mongodb/data-2
  mkdir -p $path/mongodb/data-3
  mkdir -p $path/mongodb/log
  
  echo "Please enter the following Settings for the setup of a 3 members replica set. Set default (default value) by pressing enter."

  read -p "Enter host name for mongodb access (localhost): " hostname
  if [ -z "$hostname" ]
  then
    hostname="localhost"
  fi
  
  read -p "Enter port of primary replica 0 (27017): " portA
  if [ -n "$portA" ]; then  
    read -p "Enter port of replica 1: " portB
    read -p "Enter port of replica 2: " portC
  else
    portA=27017
    portB=27018
    portC=27019
  fi
  
  echo "Starting mongo db on port $portA"
  mongod --port $portA --dbpath $path/mongodb/data-1 --logpath $path/mongodb/log/repl-1.log --fork >/dev/null
  
  read -p "Enter a new root username to enable authentication (leave empty if you don't want to use authentication): " username
  if [ -n "$username" ]; then
    authorization="enabled"
    
    read -p "Enter new password for user $username: " password
    read -p "Repeat password: " passwordRpt
    
    if [ "$password" != "$passwordRpt" ]; then
      echo "passwords do not match. Restart setup to try again."
      exit 1
    fi
    
    read -p "Allow access from remote IPs? y or n (don't allow remote access): " remote_access
    
    echo "Create root user $username"
    
    mongosh --port $portA --eval "db.getSiblingDB('admin').createUser({user:'$username',pwd:'$password',roles:['root']})" >/dev/null
    
    # create mongodb keyfile
    
    echo "create mongo db keyfile $path/mongodb/mongodb.key"
    openssl rand -base64 741 > $path/mongodb/mongodb.key
    chmod 600 $path/mongodb/mongodb.key
    key_file_line="keyFile: ./mongodb/mongodb.key"

    echo "Authentication enabled"
  else
    key_file_line="# ./mongodb/mongodb.key"
    authorization="disabled"
  fi
  
  # create or overwrite mongod config files based on mongod.conf for all replica sets
  if [ "$remote_access" = "y" ] || [ "$remote_access" = "yes" ]; then
    remoteIP="0.0.0.0"
  else
    remoteIP="127.0.0.1"
  fi
  echo "path variable value: '$path'"
  makeConfig "1" $portA "$remoteIP" $authorization "$key_file_line"
  makeConfig "2" $portB "127.0.0.1" $authorization "$key_file_line"
  makeConfig "3" $portC "127.0.0.1" $authorization "$key_file_line"
  
  #stop single mongodb and start replica set with new config files
  stop
  start
  
  # initiate replica sets
  cfg="{
     '_id' : 'adaptor-repl',
     'members' : [
      {
       '_id' : 0,
       'host' : '$hostname:$portA'
      },
      {
       '_id' : 1,
       'host' : '$hostname:$portB'
      },
      {
       '_id' : 2,
       'host' : '$hostname:$portC'
      }
     ]
  }"
  # echo $cfg
  
  if [ -n "$username" ]
  then
    echo "Try creating mongo replica sets on $hostname:$portA, $hostname:$portB and $hostname:$portC with user $username ..."
    mongosh --port $portA --username $username --password $password --authenticationDatabase admin --eval "JSON.stringify(db.adminCommand({'replSetInitiate' : $cfg}))"
  else
    echo "Try creating mongo replica sets on $hostname:$portA, $hostname:$portB and $hostname:$portC with authorization disabled ..."
    mongosh --port $portA --eval "JSON.stringify(db.adminCommand({'replSetInitiate' : $cfg}))"
  fi
  
  #echo "restart mongo process ..."

  stop
  start
  
  echo "Setup finished"
  echo "Next time you start adaptor:ex, append mongodb options to connect to mongodb:"
  echo ""
  if [ "$authorization" = "enabled" ]; then
    echo "node index.js --database mongodb --mongourl 'mongodb://$username:$password@$hostname:$portA/admin?replicaSet=adaptor-repl'"
  else
    echo "node index.js --database mongodb --mongourl 'mongodb://$hostname:$portA/?replicaSet=adaptor-repl'"
  fi

  echo ""
  echo "to verify the mongod service is running as expected, run:"
  echo ""
  echo "ps aux | grep -v grep | grep mongod"
}

# replica set id, port, ip, authorization (enbled/disabled)
makeConfig() {
  echo "write config file $path/mongodb/mongod-$1.conf setting port to $2, ip to $3 and authorization $4"
  awk -v p="$2" \
    -v db="$path/mongodb/data-$1" \
    -v ip="$3" \
    -v auth="$4" \
    -v logpath="$path/mongodb/log/repl-$1.log" \
    -v keyfile="$5" '
  /^[ ]*port:/          { sub(/.*/, "  port: " p) }
  /^[ ]*dbPath:/        { sub(/.*/, "  dbPath: " db) }
  /^[ ]*bindIp:/        { sub(/.*/, "  bindIp: " ip) }
  /^[ ]*authorization:/ { sub(/.*/, "  authorization: " auth) }
  /^[ ]*path:/          { sub(/.*/, "  path: " logpath) }
  /^[ ]*#? keyFile:/    { sub(/.*/, keyfile) }
  { print }
' ./mongod.conf > "$path/mongodb/mongod-$1.conf"

  sleep 0.2
  
  # add or remove keyFile path
  keyfile_line="  keyFile: $path/mongodb/mongodb.key"
  if [ "$4" != "enabled" ]; then
    keyfile_line="  # $keyfile_line"
  fi

  awk -v keyfile="$keyfile_line" '
    /^#? ?keyFile:/ { print keyfile; next }
    { print }
  ' "$path/mongodb/mongod-$1.conf" > "$path/mongodb/mongod-$1.conf.tmp" && \
  mv "$path/mongodb/mongod-$1.conf.tmp" "$path/mongodb/mongod-$1.conf"

}

manual() {
  echo "Please use in one of the following ways: "
  echo "sh mongo.sh setup   <- run once to setup mongodb replicas and authorization"
  echo "sh mongo.sh start   <- run whenever you want to start mongodb"
  echo "sh mongo.sh stop    <- run whenever you want to stop mongodb"
  echo "append path if your adaptor:ex directory is not './adaptorex'"
}

# decide on function based on provided option
cmd=""
path="./adaptorex"  # default path

if [ "$#" -ge 1 ]; then
  cmd=$1
  
  # If a second argument is provided, use it as the path
  if [ "$#" -ge 2 ]; then
    path=$2
  fi
  
  case $cmd in
    setup)
      setup
      ;;
    start)
      start
      ;;
    stop)
      stop
      ;;
    *)
      echo "$cmd is not a valid option"
      manual
      exit 1
      ;;
  esac
else
  echo "Usage: $0 {setup|start|stop} [path]"
  manual
  exit 1
fi