#!/usr/bin/env bash
set -e

# --- Configuration ---
LAYEROPS_HOME_DIR=/opt/layerops
LAYEROPS_DATA_DIR=/data/layerops
LAYEROPS_BIN_DIR=${LAYEROPS_HOME_DIR}/bin
LAYEROPS_WORKER_PATH=${LAYEROPS_BIN_DIR}/worker
SERVICE_BASE="layerops-worker"

function check_envvars() {
  MISSING=""
  for envvar in ENVIRONMENT_GROUP_UUID LAYEROPS_WORKER_URL LAYEROPS_WORKER_VERSION_CHECK
  do
    [ -z "${!envvar}" ] && MISSING="$envvar $MISSING"
  done

  if [ ! -z "$MISSING" ]
  then
    echo "Missing following environment variables:"
    for var in $MISSING
    do
      echo "  $var"
    done
    exit 1
  fi
}

function _get_worker_version() {
  REMOTE_VERSION=$(curl -s --max-time 10 "$LAYEROPS_WORKER_VERSION_CHECK")
  if [ -z "$REMOTE_VERSION" ]; then
    echo "0.0.0"
    return
  fi

  echo "$REMOTE_VERSION"
}

# Verify worker binary GPG signature
# Arguments: $1 = path to worker binary, $2 = download URL of worker
function verify_worker_signature() {
  local WORKER_PATH="$1"
  local WORKER_URL="$2"

  # Check if LAYEROPS_WORKER_SIGNATURE_PUBLIC_KEY is set
  if [ -z "$LAYEROPS_WORKER_SIGNATURE_PUBLIC_KEY" ]; then
    echo "No GPG public key URL configured, skipping signature verification"
    return 0
  fi

  # Get the public key
  PUBLIC_KEY=$(curl -s --max-time 10 "$LAYEROPS_WORKER_SIGNATURE_PUBLIC_KEY")

  # If no public key returned, skip verification
  if [ -z "$PUBLIC_KEY" ]; then
    echo "No GPG public key returned, skipping signature verification"
    return 0
  fi

  # Try to download the signature file
  SIGNATURE_URL="${WORKER_URL}.asc"
  SIGNATURE_FILE="${WORKER_PATH}.asc"

  HTTP_CODE=$(curl -s -w "%{http_code}" -o "$SIGNATURE_FILE" --max-time 10 "$SIGNATURE_URL")

  # If signature file doesn't exist (404 or other error), skip verification
  if [ "$HTTP_CODE" != "200" ] || [ ! -s "$SIGNATURE_FILE" ]; then
    echo "No signature file found at $SIGNATURE_URL, skipping signature verification"
    rm -f "$SIGNATURE_FILE"
    return 0
  fi

  # Import the public key and verify signature
  GPG_HOME=$(mktemp -d)
  echo "$PUBLIC_KEY" | gpg --homedir "$GPG_HOME" --batch --quiet --import 2>/dev/null

  if gpg --homedir "$GPG_HOME" --batch --verify "$SIGNATURE_FILE" "$WORKER_PATH" 2>/dev/null; then
    echo "GPG signature verification successful"
    rm -f "$SIGNATURE_FILE"
    rm -rf "$GPG_HOME"
    return 0
  else
    echo "Error: GPG signature verification failed!"
    rm -f "$SIGNATURE_FILE"
    rm -rf "$GPG_HOME"
    return 1
  fi
}

check_envvars

# 1. Find the current version via Systemd
# Look for an active service matching layerops-worker@SOMETHING.service
CURRENT_UNIT=$(systemctl list-units --full --all | grep -o "${SERVICE_BASE}@.*\.service" | head -n 1)

if [ -z "$CURRENT_UNIT" ]; then
    echo "No active worker instance detected via systemd."
    exit 1
else
    # Properly extract the version from the string "layerops-worker@1.2.4.service"
    # Extracts everything between "@" and ".service"
    CURRENT_VERSION=$(echo "$CURRENT_UNIT" | sed -n "s/^${SERVICE_BASE}@\(.*\)\.service$/\1/p")
fi

# 2. Retrieve the remote version
REMOTE_VERSION=$(_get_worker_version)

echo "Local version (systemd) : $CURRENT_VERSION"
echo "Remote version          : $REMOTE_VERSION"

if [ "$REMOTE_VERSION" == "0.0.0" ]; then
    echo "No remote version detected. Exiting..."
    exit 1
fi

# 3. Compare versions
if [ "$CURRENT_VERSION" != "$REMOTE_VERSION" ]; then
    echo "Version mismatch detected! Updating in progress..."

    TMP_BIN="/tmp/layerops-worker.new"

    # Install layerops worker
    URL_DOWNLOAD="${LAYEROPS_WORKER_URL}/worker-${REMOTE_VERSION}"

    # 4. Download
    echo "Downloading $URL_DOWNLOAD..."
    if ! curl -s -L -o "$TMP_BIN" "$URL_DOWNLOAD"; then
        echo "Error during download."
        exit 1
    fi
    chmod +x "$TMP_BIN"

    # 4.1. Verify GPG signature if available
    if ! verify_worker_signature "$TMP_BIN" "$URL_DOWNLOAD"; then
        echo "Error: Signature verification failed. Aborting update."
        rm -f "$TMP_BIN"
        exit 1
    fi

    # 5. Security: Basic test of the binary
    # (Optional: check if the binary can be executed, even just for help)
    if ! "$TMP_BIN" --help > /dev/null 2>&1; then
       echo "Error: The downloaded binary seems invalid."
       rm "$TMP_BIN"
       exit 1
    fi

    # 6. Replace the binary
    # Note: On Linux, we can overwrite the file of a running process.
    # The old process continues to run on the old inode (file deleted virtually).
    mv "$TMP_BIN" "$LAYEROPS_WORKER_PATH"

    # 7. Orchestration of the restart (SIGTERM -> Wait -> Start)
    
    # Stop the old (if exists)
    if [ -n "$CURRENT_UNIT" ]; then
        echo "Stopping the old instance: $CURRENT_UNIT"

        # Disable the old unit 
        systemctl disable "$CURRENT_UNIT" || true

        # Stop the old unit
        systemctl stop --no-block "$CURRENT_UNIT"
        
        echo "Waiting for 100ms for port release..."
        sleep 0.1
    fi

    # Start the new with the VERSION NAME as ID
    NEW_UNIT="${SERVICE_BASE}@${REMOTE_VERSION}"
    echo "Starting the new instance: $NEW_UNIT"
    systemctl start "$NEW_UNIT"

    echo "Update completed: $CURRENT_VERSION -> $REMOTE_VERSION"

else
    # No logs to avoid spamming systemd if nothing happens
    exit 0
fi