#!/bin/sh
set -eu

log() {
  printf '%s\n' "$*" >&2
}

is_enabled() {
  case "${1:-}" in
    1|true|TRUE|yes|YES|on|ON) return 0 ;;
    *) return 1 ;;
  esac
}

wait_for_http() {
  name="$1"
  url="$2"
  timeout="$3"
  interval="$4"
  mode="${5:-strict}"
  start_ts="$(date +%s)"

  while :; do
    if [ "$mode" = "connect" ]; then
      if curl -sS --max-time 3 "$url" >/dev/null 2>&1; then
        log "$name is reachable at $url."
        return 0
      fi
    else
      if curl -fsS --max-time 3 "$url" >/dev/null 2>&1; then
        log "$name is reachable at $url."
        return 0
      fi
    fi

    now_ts="$(date +%s)"
    if [ $((now_ts - start_ts)) -ge "$timeout" ]; then
      log "Timeout waiting for $name at $url after ${timeout}s."
      return 1
    fi

    sleep "$interval"
  done
}

wait_for_tcp() {
  name="$1"
  host="$2"
  port="$3"
  timeout="$4"
  interval="$5"
  start_ts="$(date +%s)"

  while :; do
    if node -e "const net=require('net');const host=process.argv[1];const port=Number(process.argv[2]);const socket=net.connect({host,port});const fail=()=>{socket.destroy();process.exit(1)};socket.setTimeout(2000,fail);socket.on('connect',()=>{socket.end();process.exit(0)});socket.on('error',fail);" "$host" "$port" >/dev/null 2>&1; then
      log "$name is reachable at ${host}:${port}."
      return 0
    fi

    now_ts="$(date +%s)"
    if [ $((now_ts - start_ts)) -ge "$timeout" ]; then
      log "Timeout waiting for $name at ${host}:${port} after ${timeout}s."
      return 1
    fi

    sleep "$interval"
  done
}

VAULT_ENABLED="${VAULT_ENABLED:-auto}"
if [ "$VAULT_ENABLED" = "false" ] || [ "$VAULT_ENABLED" = "0" ]; then
  return 0 2>/dev/null || exit 0
fi

if [ -z "${VAULT_ADDR:-}" ] || [ -z "${VAULT_TOKEN:-}" ]; then
  if [ "$VAULT_ENABLED" = "true" ] || [ "$VAULT_ENABLED" = "1" ]; then
    log "Vault bootstrap is required but VAULT_ADDR or VAULT_TOKEN is missing."
    return 1 2>/dev/null || exit 1
  fi
  return 0 2>/dev/null || exit 0
fi

if ! command -v curl >/dev/null 2>&1 || ! command -v jq >/dev/null 2>&1; then
  log "Vault bootstrap requires curl and jq."
  return 1 2>/dev/null || exit 1
fi

VAULT_KV_MOUNT="${VAULT_KV_MOUNT:-secret}"
VAULT_WAIT_TIMEOUT_SECONDS="${VAULT_WAIT_TIMEOUT_SECONDS:-90}"
VAULT_WAIT_INTERVAL_SECONDS="${VAULT_WAIT_INTERVAL_SECONDS:-2}"

wait_for_http \
  "Vault" \
  "${VAULT_ADDR%/}/v1/sys/health?standbyok=true&perfstandbyok=true" \
  "$VAULT_WAIT_TIMEOUT_SECONDS" \
  "$VAULT_WAIT_INTERVAL_SECONDS" \
  "strict"

load_secret_path() {
  path="$1"
  source_name="$2"
  if [ -z "$path" ]; then
    return 0
  fi

  url="${VAULT_ADDR%/}/v1/${VAULT_KV_MOUNT}/data/${path}"
  response="$(curl -fsS -H "X-Vault-Token: $VAULT_TOKEN" "$url")" || {
    log "Failed to load Vault path ${VAULT_KV_MOUNT}/${path}."
    return 1
  }

  encoded_items="$(printf '%s' "$response" | jq -r '.data.data // {} | to_entries[]? | @base64')"
  if [ -z "$encoded_items" ]; then
    return 0
  fi

  old_ifs="${IFS}"
  IFS='
'
  for encoded_item in $encoded_items; do
    key="$(printf '%s' "$encoded_item" | base64 -d | jq -r '.key')"
    value="$(printf '%s' "$encoded_item" | base64 -d | jq -r '.value | tostring')"
    export "$key=$value"
  done
  IFS="${old_ifs}"

  log "Loaded Vault ${source_name} secrets from ${VAULT_KV_MOUNT}/${path}."
}

load_secret_path "${VAULT_SHARED_PATH:-}" "shared"
load_secret_path "${VAULT_PROJECT_PATH:-}" "project"

if is_enabled "${WAIT_FOR_HATCHET_ENGINE:-0}"; then
  HATCHET_WAIT_TIMEOUT_SECONDS="${HATCHET_WAIT_TIMEOUT_SECONDS:-120}"
  HATCHET_WAIT_INTERVAL_SECONDS="${HATCHET_WAIT_INTERVAL_SECONDS:-2}"
  hatchet_wait_host_port="${HATCHET_WAIT_HOST_PORT:-${HATCHET_CLIENT_HOST_PORT:-}}"
  hatchet_wait_url="${HATCHET_WAIT_URL:-${HATCHET_CLIENT_API_URL:-}}"

  if [ -n "$hatchet_wait_host_port" ]; then
    case "$hatchet_wait_host_port" in
      *:*)
        hatchet_wait_host="${hatchet_wait_host_port%:*}"
        hatchet_wait_port="${hatchet_wait_host_port##*:}"
        ;;
      *)
        log "Invalid HATCHET wait host:port value: ${hatchet_wait_host_port}"
        return 1 2>/dev/null || exit 1
        ;;
    esac

    wait_for_tcp \
      "Hatchet engine" \
      "$hatchet_wait_host" \
      "$hatchet_wait_port" \
      "$HATCHET_WAIT_TIMEOUT_SECONDS" \
      "$HATCHET_WAIT_INTERVAL_SECONDS"
  else
    if [ -z "$hatchet_wait_url" ]; then
      log "WAIT_FOR_HATCHET_ENGINE is enabled but no HATCHET wait target is configured."
      return 1 2>/dev/null || exit 1
    fi

    wait_for_http \
      "Hatchet engine" \
      "${hatchet_wait_url%/}/" \
      "$HATCHET_WAIT_TIMEOUT_SECONDS" \
      "$HATCHET_WAIT_INTERVAL_SECONDS" \
      "connect"
  fi
fi
