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

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

info() {
  printf '%s\n' "$1"
}

warn() {
  printf 'warning: %s\n' "$1" >&2
}

need() {
  command -v "$1" >/dev/null 2>&1 || fail "$1 is required"
}

sha256_check() {
  local checksum="$1"
  local path="$2"

  if command -v shasum >/dev/null 2>&1; then
    printf '%s  %s\n' "$checksum" "$path" | shasum -a 256 -c - >/dev/null
    return
  fi
  if command -v sha256sum >/dev/null 2>&1; then
    printf '%s  %s\n' "$checksum" "$path" | sha256sum -c - >/dev/null
    return
  fi
  fail "shasum or sha256sum is required to verify eo"
}

safe_relative_path() {
  local path="$1"
  case "$path" in
    ""|/*|*"/../"*|"../"*|*".."|*//*) return 1 ;;
    *) return 0 ;;
  esac
}

validate_archive_listing() {
  local archive="$1"
  local kind="$2"
  local entry

  case "$kind" in
    tar)
      while IFS= read -r entry; do
        safe_relative_path "$entry" || fail "archive contains unsafe path: $entry"
      done < <(tar -tzf "$archive")
      ;;
    zip)
      need unzip
      while IFS= read -r entry; do
        safe_relative_path "$entry" || fail "archive contains unsafe path: $entry"
      done < <(unzip -Z1 "$archive")
      ;;
  esac
}

detect_os() {
  case "$(uname -s | tr '[:upper:]' '[:lower:]')" in
    darwin) printf 'darwin' ;;
    linux) printf 'linux' ;;
    *) fail "unsupported OS: $(uname -s)" ;;
  esac
}

detect_arch() {
  case "$(uname -m)" in
    arm64|aarch64) printf 'arm64' ;;
    x86_64|amd64) printf 'amd64' ;;
    *) fail "unsupported architecture: $(uname -m)" ;;
  esac
}

download() {
  local url="$1"
  local dest="$2"
  curl -fsSL "$url" -o "$dest"
}

is_hosted_pack_url() {
  local url="$1"
  case "$url" in
    *"/agent-kit/packs/"*.zip) return 0 ;;
    *) return 1 ;;
  esac
}

header_value() {
  local header_file="$1"
  local name="$2"
  awk -v want="$(printf '%s' "$name" | tr '[:upper:]' '[:lower:]')" '
    BEGIN { FS = ":" }
    tolower($1) == want {
      value = substr($0, index($0, ":") + 1)
      gsub(/^[ \t]+|[ \t\r]+$/, "", value)
      print value
    }
  ' "$header_file" | tail -n 1
}

download_pack_archive() {
  local url="$1"
  local dest="$2"
  local headers checksum

  headers="$(mktemp "${TMPDIR:-/tmp}/eo-agent-kit-pack-headers.XXXXXX")"
  if ! curl -fsSL -D "$headers" "$url" -o "$dest"; then
    rm -f "$headers"
    fail "download failed: $url"
  fi
  checksum="$(header_value "$headers" "x-eo-pack-sha256")"
  rm -f "$headers"
  if [ -n "$checksum" ]; then
    [[ "$checksum" =~ ^[0-9a-fA-F]{64}$ ]] || fail "hosted pack checksum header is invalid"
    sha256_check "$checksum" "$dest"
  elif is_hosted_pack_url "$url"; then
    fail "hosted pack response did not include x-eo-pack-sha256"
  fi
}

install_cli() {
  local os_name arch base version install_dir cli_url tmp_bin sha_url tmp_sha checksum

  os_name="$(detect_os)"
  arch="$(detect_arch)"
  base="${EO_AGENT_KIT_BASE_URL:-https://agentscompany.io/agent-kit}"
  base="${base%/}"
  version="${EO_AGENT_KIT_VERSION:-latest}"
  install_dir="${EO_AGENT_KIT_INSTALL_DIR:-$HOME/.local/bin}"
  cli_url="${EO_AGENT_KIT_CLI_URL:-$base/cli/$version/$os_name/$arch/eo}"

  mkdir -p "$install_dir"
  tmp_bin="$(mktemp "${TMPDIR:-/tmp}/eo-agent-kit-eo.XXXXXX")"
  download "$cli_url" "$tmp_bin"

  sha_url="${EO_AGENT_KIT_SHA256_URL:-$cli_url.sha256}"
  tmp_sha="$(mktemp "${TMPDIR:-/tmp}/eo-agent-kit-sha.XXXXXX")"
  if download "$sha_url" "$tmp_sha" 2>/dev/null; then
    checksum="$(awk '{print $1}' "$tmp_sha")"
    [ -n "$checksum" ] || fail "checksum file is empty at $sha_url"
    sha256_check "$checksum" "$tmp_bin"
  elif [ "${EO_AGENT_KIT_ALLOW_UNVERIFIED:-0}" = "1" ]; then
    warn "checksum not found at $sha_url; EO_AGENT_KIT_ALLOW_UNVERIFIED=1 allowed install"
  else
    fail "checksum required but not available at $sha_url; set EO_AGENT_KIT_ALLOW_UNVERIFIED=1 only for local testing"
  fi

  chmod 0755 "$tmp_bin"
  mv "$tmp_bin" "$install_dir/eo"
  rm -f "$tmp_sha"
  printf '%s\n' "$install_dir/eo"
}

extract_pack_url() {
  local url="$1"
  local target="$2"
  local archive

  archive="$(mktemp "${TMPDIR:-/tmp}/eo-agent-kit-pack.XXXXXX")"
  download_pack_archive "$url" "$archive"
  mkdir -p "$target"
  case "$url" in
    *.tar.gz|*.tgz)
      validate_archive_listing "$archive" tar
      tar -xzf "$archive" -C "$target" --strip-components="${EO_AGENT_KIT_ARCHIVE_STRIP_COMPONENTS:-0}"
      ;;
    *.zip)
      validate_archive_listing "$archive" zip
      unzip -q "$archive" -d "$target"
      ;;
    *)
      fail "EO_AGENT_KIT_PACK_URL must end with .tar.gz, .tgz, or .zip"
      ;;
  esac
  rm -f "$archive"
}

main() {
  need curl

  local eo_bin pack_dir runtime dest install_args doctor_args pack_stage
  if [ "${EO_AGENT_KIT_SKIP_CLI:-0}" = "1" ]; then
    eo_bin="${EO_AGENT_KIT_EO_BIN:-eo}"
  else
    eo_bin="$(install_cli)"
    info "installed eo: $eo_bin"
  fi

  pack_dir="${EO_AGENT_KIT_PACK_DIR:-}"
  if [ -n "${EO_AGENT_KIT_PACK_URL:-}" ]; then
    pack_stage="$(mktemp -d "${TMPDIR:-/tmp}/eo-agent-kit-pack.XXXXXX")"
    extract_pack_url "$EO_AGENT_KIT_PACK_URL" "$pack_stage"
    if [ -n "${EO_AGENT_KIT_PACK_SUBDIR:-}" ]; then
      safe_relative_path "$EO_AGENT_KIT_PACK_SUBDIR" || fail "EO_AGENT_KIT_PACK_SUBDIR must be a safe relative path"
    fi
    pack_dir="${EO_AGENT_KIT_PACK_SUBDIR:+$pack_stage/$EO_AGENT_KIT_PACK_SUBDIR}"
    pack_dir="${pack_dir:-$pack_stage}"
  fi

  if [ -z "$pack_dir" ]; then
    info "eo is installed. To install runtime files, rerun with EO_AGENT_KIT_PACK_DIR or EO_AGENT_KIT_PACK_URL."
    info "example: EO_AGENT_KIT_PACK_URL=https://agentscompany.io/agent-kit/packs/<token>.zip EO_AGENT_KIT_DEST=\$PWD EO_AGENT_KIT_RUNTIME=codex $0"
    exit 0
  fi

  runtime="${EO_AGENT_KIT_RUNTIME:-}"
  dest="${EO_AGENT_KIT_DEST:-$PWD}"
  install_args=(agent-kit install --pack "$pack_dir" --dest "$dest")
  if [ -n "$runtime" ]; then
    install_args+=(--runtime "$runtime")
  fi
  if [ "${EO_AGENT_KIT_FORCE:-0}" = "1" ]; then
    install_args+=(--force)
  fi
  if [ "${EO_AGENT_KIT_SKIP_IDENTITY:-0}" = "1" ]; then
    install_args+=(--skip-identity)
  fi
  if [ "${EO_AGENT_KIT_REQUIRE_IDENTITY:-0}" = "1" ]; then
    install_args+=(--require-identity)
  fi
  "$eo_bin" "${install_args[@]}"

  if [ "${EO_AGENT_KIT_SKIP_DOCTOR:-0}" = "1" ]; then
    exit 0
  fi

  doctor_args=(agent-kit doctor --pack "$dest")
  if [ -n "$runtime" ]; then
    doctor_args+=(--runtime "$runtime")
  fi
  if [ "${EO_AGENT_KIT_DOCTOR_SKIP_LIVE:-0}" = "1" ]; then
    doctor_args+=(--skip-live)
  fi
  if [ -n "${EO_AGENT_KIT_GCP_PROJECT:-}" ]; then
    doctor_args+=(--gcp-project "$EO_AGENT_KIT_GCP_PROJECT")
  fi
  if [ -n "${EO_AGENT_KIT_AZURE_SUBSCRIPTION:-}" ]; then
    doctor_args+=(--azure-subscription "$EO_AGENT_KIT_AZURE_SUBSCRIPTION")
  fi
  "$eo_bin" "${doctor_args[@]}"
}

main "$@"
