#!/bin/bash

set -u

fail() {
  printf "%s\n" "$@" >&2
  exit 1
}

# require bash
if [ -z "${BASH_VERSION:-}" ]; then
  fail "bash required"
fi

if [ $# -lt 4 ]; then
  fail "usage: $0 api_key api_endpoint agent_version onboarding_id [autoDownloadConfig=1]"
fi

API_KEY_ENCODED=$1
API_ENDPOINT=$2
ELASTIC_AGENT_VERSION=$3
ONBOARDING_ID=$4
AUTO_DOWNLOAD_CONFIG=${5:-}

# require curl
[ $(builtin type -P curl) ] || fail "curl required"

# check OS
OS="$(uname)"
ARCH="$(uname -m)"
os=linux
arch=x86_64
cfg=/opt/Elastic/Agent/elastic-agent.yml
if [ "${OS}" == "Linux" ]; then
  if [ "${ARCH}" == "aarch64" ]; then
    arch=arm64
  fi
elif [ "${OS}" == "Darwin" ]; then
  os=darwin
  if [ "${ARCH}" == "arm64" ]; then
    arch=aarch64
  fi
  cfg=/Library/Elastic/Agent/elastic-agent.yml
else
  fail "this script is only supported on linux and macOS"
fi

artifact=elastic-agent-${ELASTIC_AGENT_VERSION}-${os}-${arch}

# https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-8.8.2-darwin-x86_64.tar.gz
# https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-8.8.2-darwin-aarch64.tar.gz
# https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-8.8.2-linux-x86_64.tar.gz
# https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-8.8.2-linux-arm64.tar.gz

updateStepProgress() {
  local STEPNAME="$1"
  local STATUS="$2" # "incomplete" | "complete" | "disabled" | "loading" | "warning" | "danger" | "current"
  local MESSAGE=${3:-}
  curl --request POST \
    --url "${API_ENDPOINT}/flow/${ONBOARDING_ID}/step/${STEPNAME}" \
    --header "Authorization: ApiKey ${API_KEY_ENCODED}" \
    --header "Content-Type: application/json" \
    --header "kbn-xsrf: true" \
    --header "x-elastic-internal-origin: Kibana" \
    --data "{\"status\":\"${STATUS}\", \"message\":\"${MESSAGE}\"}" \
    --output /dev/null \
    --no-progress-meter
}

ELASTIC_AGENT_DOWNLOAD_URL="https://artifacts.elastic.co/downloads/beats/elastic-agent/${artifact}.tar.gz"
echo "Downloading Elastic Agent archive from ${ELASTIC_AGENT_DOWNLOAD_URL}"
updateStepProgress "ea-download" "loading"
curl -L -O $ELASTIC_AGENT_DOWNLOAD_URL --fail
if [ "$?" -eq 0 ]; then
  echo "Downloaded Elastic Agent"
  updateStepProgress "ea-download" "complete"
else
  updateStepProgress "ea-download" "danger" "Failed to download Elastic Agent, see script output for error."
  fail "Failed to download Elastic Agent"
fi

echo "Extracting Elastic Agent"
updateStepProgress "ea-extract" "loading"
tar -xzf ${artifact}.tar.gz
if [ "$?" -eq 0 ]; then
  echo "Elastic Agent extracted"
  updateStepProgress "ea-extract" "complete"
else
  updateStepProgress "ea-extract" "danger" "Failed to extract Elastic Agent, see script output for error."
  fail "Failed to extract Elastic Agent"
fi

echo "Installing Elastic Agent"
updateStepProgress "ea-install" "loading"
cd ${artifact}
./elastic-agent install -f
if [ "$?" -eq 0 ]; then
  echo "Elastic Agent installed"
  updateStepProgress "ea-install" "complete"
else
  updateStepProgress "ea-install" "danger" "Failed to install Elastic Agent, see script output for error."
  fail "Failed to install Elastic Agent"
fi

waitForElasticAgentStatus() {
  local MAX_RETRIES=10
  local i=0
  echo -n "."
  elastic-agent status >/dev/null
  local ELASTIC_AGENT_STATUS_EXIT_CODE="$?"
  while [ "$ELASTIC_AGENT_STATUS_EXIT_CODE" -ne 0 ] && [ $i -le $MAX_RETRIES ]; do
    sleep 1
    echo -n "."
    elastic-agent status >/dev/null
    ELASTIC_AGENT_STATUS_EXIT_CODE="$?"
    ((i++))
  done
  echo ""
  return $ELASTIC_AGENT_STATUS_EXIT_CODE
}

echo "Checking Elastic Agent status"
updateStepProgress "ea-status" "loading"
waitForElasticAgentStatus
if [ "$?" -ne 0 ]; then
  updateStepProgress "ea-status" "warning" "Unable to determine agent status"
fi

# https://www.elastic.co/guide/en/fleet/current/elastic-agent-cmd-options.html#elastic-agent-status-command
ELASTIC_AGENT_STATES=(STARTING CONFIGURING HEALTHY DEGRADED FAILED STOPPING UPGRADING ROLLBACK)

# Get elastic-agent status in json format | removing extra states in the json | finding "state":value | removing , | removing "state": | trimming the result
ELASTIC_AGENT_STATE="$(elastic-agent status --output json | sed -n '/components/q;p' | grep state | sed 's/\(.*\),/\1 /' | sed 's/"state": //' | sed 's/\s//g')"
# Get elastic-agent status in json format | removing extra states in the json | finding "message":value | removing , | removing "message": | trimming the result | removing ""
ELASTIC_AGENT_MESSAGE="$(elastic-agent status --output json | sed -n '/components/q;p' | grep message | sed 's/\(.*\),/\1 /' | sed 's/"message": //' | sed 's/\s//g' | sed 's/\"//g')"
if [ "${ELASTIC_AGENT_STATE}" = "2" ] && [ "${ELASTIC_AGENT_MESSAGE}" = "Running" ]; then
  echo "Elastic Agent running"
  echo "Download and save configuration to ${cfg}"
  updateStepProgress "ea-status" "complete"
else
  updateStepProgress "ea-status" "warning" "Expected agent status HEALTHY / Running but got ${ELASTIC_AGENT_STATES[ELASTIC_AGENT_STATE]} / ${ELASTIC_AGENT_MESSAGE}"
fi

downloadElasticAgentConfig() {
  echo "Downloading elastic-agent.yml"
  updateStepProgress "ea-config" "loading"
  curl --request GET \
    --url "${API_ENDPOINT}/elastic_agent/config?onboardingId=${ONBOARDING_ID}" \
    --header "Authorization: ApiKey ${API_KEY_ENCODED}" \
    --header "Content-Type: application/json" \
    --header "kbn-xsrf: true" \
    --header "x-elastic-internal-origin: Kibana" \
    --no-progress-meter \
    --output ${cfg}

  if [ "$?" -eq 0 ]; then
    echo "Downloaded elastic-agent.yml"
    updateStepProgress "ea-config" "complete"
  else
    updateStepProgress "ea-config" "warning" "Failed to write elastic-agent.yml on host automatically, try manually setting the configuration"
    fail "Failed to download elastic-agent.yml"
  fi
}

if [ "${AUTO_DOWNLOAD_CONFIG}" == "autoDownloadConfig=1" ]; then
  downloadElasticAgentConfig
  echo "Done with standalone Elastic Agent setup. Look for streaming logs to arrive in Kibana"
else
  echo "Done with standalone Elastic Agent setup. Make sure to add your configuration to ${cfg}, then look for streaming logs to arrive in Kibana"
fi
