#!/usr/bin/env bash
set -euo pipefail

server_url="${OTO_BOOTSTRAP_SERVER_URL:-}"
socket_url="${OTO_BOOTSTRAP_SOCKET_URL:-}"
agent_id="${OTO_AGENT_ID:-}"
enrollment_token=""
release_base_url="${OTO_BOOTSTRAP_RELEASE_BASE_URL:-}"
agent_alias="${OTO_AGENT_ALIAS:-}"
install_dir="${HOME}/.oto/bin"
config_path="${HOME}/.oto/agent/config.yaml"
workspace_root="${HOME}/.oto/workspace"
log_dir="${HOME}/.oto/agent/log"
background="true"

usage() {
  echo "Usage: $0 --token <token> [options]"
  echo "Options:"
  echo "  --server-url <url>         OTO Core HTTP URL (default: served by bootstrap endpoint or OTO_BOOTSTRAP_SERVER_URL)"
  echo "  --socket-url <url>         Runner proto-socket URL (default: served by bootstrap endpoint or OTO_BOOTSTRAP_SOCKET_URL)"
  echo "  --release-base-url <url>   OTO release asset base URL (default: served by bootstrap endpoint or OTO_BOOTSTRAP_RELEASE_BASE_URL)"
  echo "  --agent-id <id>            Agent ID override (default: derived from this device)"
  echo "  --agent-alias <alias>      Alias override (default: device name)"
  echo "  --install-dir <path>       Directory to install OTO agent (default: \$HOME/.oto/bin)"
  echo "  --config-path <path>       Path to config file (default: \$HOME/.oto/agent/config.yaml)"
  echo "  --workspace-root <path>    Workspace root directory (default: \$HOME/.oto/workspace)"
  echo "  --log-dir <path>           Log directory (default: \$HOME/.oto/agent/log)"
  echo "  --no-background            Run in the foreground"
}

yaml_escape() {
  local value="$1"
  value="${value//\\/\\\\}"
  value="${value//\"/\\\"}"
  value="${value//$'\t'/\\t}"
  value="${value//$'\r'/\\r}"
  value="${value//$'\n'/\\n}"
  printf '%s' "$value"
}

hash_value() {
  local value="$1"
  if command -v sha256sum >/dev/null 2>&1; then
    printf '%s' "$value" | sha256sum | awk '{print $1}'
  elif command -v shasum >/dev/null 2>&1; then
    printf '%s' "$value" | shasum -a 256 | awk '{print $1}'
  else
    printf '%s' "$value" | cksum | awk '{print $1}'
  fi
}

device_identity_source() {
  local source=""
  if [[ "${os_name:-}" = "macos" ]] && command -v ioreg >/dev/null 2>&1; then
    source="$(ioreg -rd1 -c IOPlatformExpertDevice 2>/dev/null | awk -F'"' '/IOPlatformUUID/ { print $(NF-1); exit }' || true)"
  fi
  if [[ -z "$source" && "${os_name:-}" = "linux" ]]; then
    if [[ -r /etc/machine-id ]]; then
      source="$(tr -d '[:space:]' < /etc/machine-id)"
    elif [[ -r /var/lib/dbus/machine-id ]]; then
      source="$(tr -d '[:space:]' < /var/lib/dbus/machine-id)"
    fi
  fi
  if [[ -z "$source" ]]; then
    source="$(hostname 2>/dev/null || true)"
  fi
  printf '%s' "$source"
}

default_agent_id() {
  local source hash
  source="$(device_identity_source)"
  hash="$(hash_value "oto:${os_name}:${source}")"
  printf 'oto-%s' "${hash:0:32}"
}

default_agent_alias() {
  local alias=""
  if [[ "${os_name:-}" = "macos" ]] && command -v scutil >/dev/null 2>&1; then
    alias="$(scutil --get ComputerName 2>/dev/null || true)"
  fi
  if [[ -z "$alias" ]]; then
    alias="$(hostname -s 2>/dev/null || hostname 2>/dev/null || true)"
  fi
  if [[ -z "$alias" ]]; then
    alias="oto-runner"
  fi
  printf '%s' "$alias"
}

if [[ -z "$server_url" ]]; then
  server_url='__OTO_BOOTSTRAP_DEFAULT_SERVER_URL__'
fi
if [[ -z "$socket_url" ]]; then
  socket_url='__OTO_BOOTSTRAP_DEFAULT_SOCKET_URL__'
fi
if [[ -z "$release_base_url" ]]; then
  release_base_url='__OTO_BOOTSTRAP_DEFAULT_RELEASE_BASE_URL__'
fi
if [[ "$server_url" = "__OTO_BOOTSTRAP_DEFAULT_SERVER_URL__" ]]; then
  server_url=""
fi
if [[ "$socket_url" = "__OTO_BOOTSTRAP_DEFAULT_SOCKET_URL__" ]]; then
  socket_url=""
fi
if [[ "$release_base_url" = "__OTO_BOOTSTRAP_DEFAULT_RELEASE_BASE_URL__" ]]; then
  release_base_url=""
fi

while [[ $# -gt 0 ]]; do
  case "$1" in
    --server-url|--edge-url)
      server_url="$2"
      shift 2
      ;;
    --socket-url)
      socket_url="$2"
      shift 2
      ;;
    --agent-id)
      agent_id="$2"
      shift 2
      ;;
    --token)
      enrollment_token="$2"
      shift 2
      ;;
    --release-base-url)
      release_base_url="$2"
      shift 2
      ;;
    --agent-alias)
      agent_alias="$2"
      shift 2
      ;;
    --install-dir)
      install_dir="$2"
      shift 2
      ;;
    --config-path)
      config_path="$2"
      shift 2
      ;;
    --workspace-root)
      workspace_root="$2"
      shift 2
      ;;
    --log-dir)
      log_dir="$2"
      shift 2
      ;;
    --no-background)
      background="false"
      shift 1
      ;;
    *)
      echo "Unknown option: $1" >&2
      usage
      exit 1
      ;;
  esac
done

if [[ -z "$enrollment_token" ]]; then
  echo "Error: Missing required argument: --token." >&2
  usage
  exit 1
fi
if [[ -z "$server_url" ]]; then
  echo "Error: Missing OTO Core URL. Use --server-url or fetch this script from the OTO Core bootstrap endpoint." >&2
  usage
  exit 1
fi
if [[ -z "$release_base_url" ]]; then
  echo "Error: Missing release base URL. Use --release-base-url or fetch this script from the OTO Core bootstrap endpoint." >&2
  usage
  exit 1
fi

case "$release_base_url" in
  https://*) ;;
  *)
    echo "Error: --release-base-url must use https://" >&2
    exit 1
    ;;
esac

os=$(uname -s)
case "$os" in
  Linux)   os_name="linux" ;;
  Darwin)  os_name="macos" ;;
  *)
    echo "Error: Unsupported OS: $os" >&2
    exit 1
    ;;
esac

arch=$(uname -m)
case "$arch" in
  x86_64|amd64)   arch_name="x64" ;;
  aarch64|arm64)  arch_name="arm64" ;;
  *)
    echo "Error: Unsupported architecture: $arch" >&2
    exit 1
    ;;
esac

asset_name="oto-${os_name}-${arch_name}.tar.gz"

if [[ -z "$agent_id" ]]; then
  agent_id="$(default_agent_id)"
fi
if [[ -z "$agent_alias" ]]; then
  agent_alias="$(default_agent_alias)"
fi
if [[ -z "$agent_id" ]]; then
  echo "Error: Unable to derive agent id from this device. Use --agent-id to override." >&2
  exit 1
fi

download_url="${release_base_url}/${asset_name}"
tmp_dir=$(mktemp -d)
trap 'rm -rf "$tmp_dir"' EXIT

echo "Downloading OTO agent..."
curl -fsSL "$download_url" -o "$tmp_dir/$asset_name"

echo "Extracting OTO agent..."
tar -xzf "$tmp_dir/$asset_name" -C "$tmp_dir"

mkdir -p "$install_dir"
cp "$tmp_dir/oto" "$install_dir/oto"
chmod +x "$install_dir/oto"

if [[ "$os_name" = "macos" ]]; then
  xattr -dr com.apple.quarantine "$install_dir/oto" 2>/dev/null || true
  if command -v codesign >/dev/null 2>&1; then
    codesign --force --sign - "$install_dir/oto" >/dev/null 2>&1 || true
  fi
fi

echo "Verifying OTO binary..."
if ! "$install_dir/oto" --version > /dev/null 2>&1; then
  echo "Error: OTO binary verification failed." >&2
  exit 1
fi

config_dir=$(dirname "$config_path")
agent_state_dir="${HOME}/.oto/agent"
pid_path="${agent_state_dir}/oto-agent.pid"

mkdir -p "$config_dir"
mkdir -p "$agent_state_dir"
mkdir -p "$workspace_root"
mkdir -p "$log_dir"

cat <<EOF > "$config_path"
agent:
  id: "$(yaml_escape "$agent_id")"
  alias: "$(yaml_escape "$agent_alias")"
  enrollment_token: "$(yaml_escape "$enrollment_token")"
server:
  url: "$(yaml_escape "$server_url")"
EOF
if [[ -n "$socket_url" ]]; then
  printf '  socket_url: "%s"\n' "$(yaml_escape "$socket_url")" >> "$config_path"
fi
cat <<EOF >> "$config_path"
runtime:
  install_dir: "$(yaml_escape "$install_dir")"
  workspace_root: "$(yaml_escape "$workspace_root")"
  log_dir: "$(yaml_escape "$log_dir")"
EOF

chmod 600 "$config_path"

if [ "$background" = "true" ]; then
  echo "Starting OTO agent in the background..."
  nohup "$install_dir/oto" agent run --config "$config_path" >> "$log_dir/oto-agent.log" 2>&1 &
  pid=$!
  echo "$pid" > "$pid_path"
  echo "OTO agent started in the background. PID: $pid"
  echo "Log path: $log_dir/oto-agent.log"
else
  echo "OTO agent is configured to run in the foreground."
  echo "To run it manually, use the following command:"
  echo "  $install_dir/oto agent run --config $config_path"
fi
