#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/scheduler-docker-local/internal-functions"

main() {
  declare APP="$1" IMAGE_SOURCE_TYPE="$2" IMAGE="$3" IMAGE_TAG="$4" PROC_TYPE="$5" PROC_COUNT="$6" CONTAINER_INDEX="$7"

  local cid=""
  local port=""
  local ipaddr=""
  local DOKKU_CONTAINER_ID_FILE="$DOKKU_ROOT/$APP/CONTAINER.$PROC_TYPE.$CONTAINER_INDEX"
  local DYNO="$PROC_TYPE.$CONTAINER_INDEX"

  # start the app
  local DOCKER_ARGS
  DOCKER_ARGS=$(: | plugn trigger docker-args-deploy "$APP" "$IMAGE_TAG" "$PROC_TYPE" "$CONTAINER_INDEX")
  DOCKER_ARGS+=" --label=com.dokku.process-type=$PROC_TYPE --label=com.dokku.dyno=$DYNO"
  DOCKER_ARGS+=" --env=DYNO=$DYNO"
  DOCKER_ARGS+=" --name=$APP.$DYNO.upcoming-$RANDOM"
  if [[ "$INJECT_INIT_FLAG" == "true" ]]; then
    DOCKER_ARGS+=" --init"
  fi
  DOCKER_ARGS+=" $DOCKER_RUN_LABEL_ARGS $DOKKU_GLOBAL_RUN_ARGS "
  DOCKER_ARGS+=$(: | plugn trigger docker-args-process-deploy "$APP" "$IMAGE_SOURCE_TYPE" "$IMAGE_TAG" "$PROC_TYPE" "$CONTAINER_INDEX")
  [[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" --env=TRACE=true"

  local START_CMD
  [[ "$DOKKU_HEROKUISH" == "true" ]] && START_CMD="/start $PROC_TYPE"
  [[ "$DOKKU_CNB" == "true" ]] && START_CMD=""
  [[ -n "$DOKKU_START_CMD" ]] && START_CMD="$DOKKU_START_CMD"

  local DOKKU_PORT=""
  if [[ "$PROC_TYPE" == "web" ]]; then
    ports=($(plugn trigger ports-get "$APP"))
    local exposed_ports=()
    for port_map in "${ports[@]}"; do
      local scheme="$(echo "$port_map" | cut -d':' -f1)"
      local container_port="$(echo "$port_map" | cut -d':' -f3)"
      if [[ "$scheme" != "udp" ]]; then
        DOKKU_PORT="${DOKKU_PORT:="$container_port"}"
      fi

      # skip if the exposed_ports array contains container_port
      if fn-in-array "$container_port" "${exposed_ports[@]}"; then
        continue
      fi

      if [[ "$DOKKU_NETWORK_BIND_ALL" == "true" ]]; then
        exposed_ports+=("$container_port")
        DOCKER_ARGS+=" -p $container_port"
      fi
    done
  fi

  DOCKER_ARGS+=" --env=PORT=$DOKKU_PORT"

  local DOKKU_IMAGE_ARCHITECTURE="$("$DOCKER_BIN" image inspect --format '{{.Architecture}}' "$IMAGE")"
  if [[ "$DOKKU_IMAGE_ARCHITECTURE" == "amd64" ]] && [[ "$(dpkg --print-architecture 2>/dev/null || true)" != "amd64" ]]; then
    dokku_log_warn "Detected linux/amd64 image, forcing --platform=linux/amd64"
    DOCKER_ARGS+=" --platform=linux/amd64"
  fi

  START_CMD=$(fn-scheduler-docker-local-extract-start-cmd "$APP" "$PROC_TYPE" "$START_CMD" "$DOKKU_HEROKUISH" "$DOKKU_PORT")
  DOCKER_ARGS+=" $IMAGE"
  DOCKER_ARGS+=" $START_CMD"

  declare -a ARG_ARRAY
  eval "ARG_ARRAY=($DOCKER_ARGS)"
  cid=$(fn-scheduler-docker-local-start-app-container "$APP" "${ARG_ARRAY[@]}")

  plugn trigger post-container-create "app" "$cid" "$APP" "deploy" "$PROC_TYPE"
  "$DOCKER_BIN" container start "$cid" >/dev/null || true

  ipaddr=$(plugn trigger network-get-ipaddr "$APP" "$PROC_TYPE" "$cid")

  kill_new() {
    declare desc="wrapper function to kill newly started app container"
    declare CID="$1" PROC_TYPE="$2" CONTAINER_INDEX="$3"

    plugn trigger scheduler-register-retired "$APP" "$CID" "$DOKKU_WAIT_TO_RETIRE"
    mkdir -p "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP"
    echo "${CID} ${PROC_TYPE}.${CONTAINER_INDEX}" >>"${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/failed-containers"
    "$DOCKER_BIN" container inspect "$CID" &>/dev/null && {
      # Disable the container restart policy
      "$DOCKER_BIN" container update --restart=no "$CID" &>/dev/null || true
      "$DOCKER_BIN" container stop "$CID" >/dev/null && "$DOCKER_BIN" container kill "$CID" &>/dev/null
    }
    trap - INT TERM EXIT
    kill -9 $$
  }

  # run checks first, then post-deploy hooks, which switches proxy traffic
  trap "kill_new $cid $PROC_TYPE $CONTAINER_INDEX" INT TERM EXIT
  if [[ "$DOKKU_CHECKS_DISABLED" == "false" ]]; then
    dokku_log_verbose "Attempting pre-flight checks ($PROC_TYPE.$CONTAINER_INDEX)"
    plugn trigger check-deploy "$APP" "$cid" "$PROC_TYPE" "$DOKKU_PORT" "$ipaddr" "$CONTAINER_INDEX"
  fi
  trap - INT TERM EXIT

  if [[ -f "$DOKKU_CONTAINER_ID_FILE" ]]; then
    # schedule old container for retirement
    dokku_log_verbose "Scheduling old container shutdown in $DOKKU_WAIT_TO_RETIRE seconds ($PROC_TYPE.$CONTAINER_INDEX)"
    plugn trigger scheduler-register-retired "$APP" "$(cat "$DOKKU_CONTAINER_ID_FILE")" "$DOKKU_WAIT_TO_RETIRE"
  fi

  # now using the new container
  [[ -n "$cid" ]] && echo "$cid" >"$DOKKU_CONTAINER_ID_FILE"
  [[ -n "$ipaddr" ]] && plugn trigger network-write-ipaddr "$APP" "$PROC_TYPE" "$CONTAINER_INDEX" "$ipaddr"
  [[ -n "$DOKKU_PORT" ]] && plugn trigger network-write-port "$APP" "$PROC_TYPE" "$CONTAINER_INDEX" "$DOKKU_PORT"

  # cleanup pre-migration files
  rm -f "$DOKKU_ROOT/$APP/CONTAINER" "$DOKKU_ROOT/$APP/IP" "$DOKKU_ROOT/$APP/PORT"
}

fn-scheduler-docker-local-extract-start-cmd() {
  declare APP="$1" PROC_TYPE="$2" START_CMD="$3" DOKKU_HEROKUISH="$4" PORT="$5"
  local DOKKU_DOCKERFILE_START_CMD DOKKU_PROCFILE_START_CMD START_CMD
  if [[ "$DOKKU_HEROKUISH" != "false" ]] && [[ -n "$START_CMD" ]]; then
    echo "$START_CMD"
    return
  fi

  DOKKU_DOCKERFILE_START_CMD=$(config_get "$APP" DOKKU_DOCKERFILE_START_CMD || true)
  DOKKU_PROCFILE_START_CMD=$(plugn trigger procfile-get-command "$APP" "$PROC_TYPE" "$PORT" 2>/dev/null || echo '')
  START_CMD=${DOKKU_DOCKERFILE_START_CMD:-$DOKKU_PROCFILE_START_CMD}
  echo "$START_CMD"
}

main "$@"
