#!/usr/bin/env sh
set -eu

default_base_url="https://ec.bedol.la"
base_url="${ENRICODE_INSTALL_BASE_URL:-$default_base_url}"
install_dir="${ENRICODE_INSTALL:-$HOME/.enricode}"
target="${ENRICODE_TARGET:-}"
update_path="1"

print_usage() {
  cat <<EOF
Installs the verified EnriCode standalone executable for the current macOS/Linux user.

Usage:
  curl -fsSL https://ec.bedol.la/install.sh | sh
  curl -fsSL https://ec.bedol.la/install.sh | sh -s -- --base-url https://host

Options:
  --base-url <url>      HTTPS site origin. Defaults to $default_base_url
  --install-dir <path>  Install root. Defaults to <current-user-home>/.enricode
  --target <target>     Standalone target. Defaults to the current OS/architecture.
  --no-path             Do not persist the EnriCode bin directory in shell profiles.
  --help                Show this help.
EOF
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    --base-url) base_url="${2:-}"; shift 2 ;;
    --install-dir) install_dir="${2:-}"; shift 2 ;;
    --target) target="${2:-}"; shift 2 ;;
    --no-path) update_path="0"; shift ;;
    --help|-h) print_usage; exit 0 ;;
    *) echo "enricode install: unknown option: $1" >&2; exit 1 ;;
  esac
done

log() {
  echo "enricode install: $*"
}

normalize_base_url() {
  normalized="${1%/}"
  case "$normalized" in
    */releases/latest) normalized="${normalized%/releases/latest}" ;;
    */releases) normalized="${normalized%/releases}" ;;
  esac
  case "$normalized" in
    https://*) ;;
    *) echo "enricode install: base URL must be a credential-free HTTPS origin." >&2; exit 1 ;;
  esac
  origin_tail="${normalized#https://}"
  case "$origin_tail" in
    ""|*@*|*/*|*"?"*|*"#"*) echo "enricode install: base URL must be a credential-free HTTPS origin." >&2; exit 1 ;;
  esac
  printf "%s\n" "$normalized"
}

resolve_target() {
  os_name="$(uname -s)"
  machine_name="$(uname -m)"
  case "$os_name:$machine_name" in
    Darwin:arm64|Darwin:aarch64) echo "darwin-arm64" ;;
    Darwin:x86_64|Darwin:amd64) echo "darwin-x64" ;;
    Linux:arm64|Linux:aarch64) echo "linux-arm64" ;;
    Linux:x86_64|Linux:amd64) echo "linux-x64" ;;
    *) echo "enricode install: unsupported OS/architecture: $os_name/$machine_name" >&2; exit 1 ;;
  esac
}

download_file() {
  url="$1"
  destination="$2"
  log "downloading $url"
  if command -v curl >/dev/null 2>&1; then
    curl -fsSL "$url" -o "$destination"
  elif command -v wget >/dev/null 2>&1; then
    wget -qO "$destination" "$url"
  else
    echo "enricode install: curl or wget is required." >&2
    exit 1
  fi
}

write_release_public_key() {
  destination="$1"
  cat >"$destination" <<'EOF'
-----BEGIN PUBLIC KEY-----
MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAt6bam2ZtPYtWWYPxpYEI
o6E4vY0KkXluIg4f4P68piwpVV1RjR+U8qeSyQX//Qw/F+jTKPiAcwzpoEMz/1Jv
etqnjpXUY8xsTFPfLrmNgrCiNdUCpMVsoIPjUm41ENot7hZW1c5rqDJKYRDDTaHL
AsUs9nxiivBcC3HjyaN0ZrN5Ru9kW/HoghP1wmMfWch4wjzlXsR25mTmUtQvaz2E
bG1HazTt/osmT3PplhPtdWZGaWLpMpOyNrOHP70rQ7da55VTMDnWPCSIOVCZKHK+
ppBvbavNF7N6nLxsPIB1cx3D7kqMP7epoBP7wIxL8NeBVa6vmc92QtfFzpJ7feDt
tRhAg4tZk8e6HsFPDdXwEPh8p5KoNyZVDpKCR+1uK28fOixh1LhvzK/kq6+pgefO
+4uINOQjzkJsaBffslkGhxfpVCMDNRdYvamP1QQryugH4zu6Dn7FUKcciYqJcYR5
2JzFanP/a/l66DlBgBRDWkhp3bZDW+aFuvsR2dpJo63hAgMBAAE=
-----END PUBLIC KEY-----
EOF
}

extract_artifact_block() {
  manifest_path="$1"
  target_name="$2"
  awk -v needle="\"target\": \"$target_name\"" '
    index($0, needle) { capture = 1 }
    capture { print }
    capture && /^[[:space:]]*}[,]?[[:space:]]*$/ { exit }
  ' "$manifest_path"
}

extract_json_string() {
  property_name="$1"
  sed -n "s/^[[:space:]]*\"$property_name\": \"\\([^\"]*\\)\",\\{0,1\\}[[:space:]]*$/\\1/p"
}

extract_json_number() {
  property_name="$1"
  sed -n "s/^[[:space:]]*\"$property_name\": \\([0-9][0-9]*\\),\\{0,1\\}[[:space:]]*$/\\1/p"
}

quote_shell_value() {
  printf "'%s'" "$(printf "%s" "$1" | sed "s/'/'\\\\''/g")"
}

append_path_block() {
  profile_path="$1"
  quoted_install_dir="$(quote_shell_value "$install_dir")"
  mkdir -p "$(dirname "$profile_path")"
  touch "$profile_path"
  if grep -F "ENRICODE_INSTALL" "$profile_path" >/dev/null 2>&1; then
    return
  fi
  {
    echo ""
    echo "# >>> EnriCode >>>"
    printf "export ENRICODE_INSTALL=%s\n" "$quoted_install_dir"
    echo 'case ":$PATH:" in'
    echo '  *":$ENRICODE_INSTALL/bin:"*) ;;'
    echo '  *) export PATH="$ENRICODE_INSTALL/bin:$PATH" ;;'
    echo "esac"
    echo "# <<< EnriCode <<<"
  } >>"$profile_path"
  log "registered PATH block in $profile_path"
}

register_path() {
  append_path_block "$HOME/.profile"
  shell_name="$(basename "${SHELL:-}")"
  case "$shell_name" in
    zsh) append_path_block "$HOME/.zshrc" ;;
    bash) append_path_block "$HOME/.bashrc" ;;
  esac
  if [ "$(uname -s)" = "Darwin" ]; then
    append_path_block "$HOME/.zshrc"
  fi
}

if ! command -v openssl >/dev/null 2>&1; then
  echo "enricode install: OpenSSL is required to authenticate the release manifest." >&2
  exit 1
fi
if [ -z "$target" ]; then
  target="$(resolve_target)"
fi
case "$target" in
  darwin-x64|darwin-arm64|linux-x64|linux-arm64) ;;
  *) echo "enricode install: invalid POSIX target: $target" >&2; exit 1 ;;
esac

base_url="$(normalize_base_url "$base_url")"
temporary_root="$(mktemp -d "${TMPDIR:-/tmp}/enricode-install.XXXXXX")"
trap 'rm -rf "$temporary_root"' EXIT HUP INT TERM
manifest_path="$temporary_root/manifest.json"
signature_text_path="$temporary_root/manifest.json.sig"
signature_binary_path="$temporary_root/manifest.signature"
public_key_path="$temporary_root/manifest-public-key.pem"
download_file "$base_url/releases/manifest.json" "$manifest_path"
download_file "$base_url/releases/manifest.json.sig" "$signature_text_path"
write_release_public_key "$public_key_path"
openssl base64 -d -A -in "$signature_text_path" -out "$signature_binary_path"
if ! openssl dgst -sha256 -verify "$public_key_path" -signature "$signature_binary_path" "$manifest_path" >/dev/null 2>&1; then
  echo "enricode install: release manifest signature verification failed." >&2
  exit 1
fi

match_count="$(grep -c "\"target\": \"$target\"" "$manifest_path" || true)"
if [ "$match_count" -ne 1 ]; then
  echo "enricode install: signed release must contain exactly one artifact for $target." >&2
  exit 1
fi
artifact_block="$(extract_artifact_block "$manifest_path" "$target")"
artifact_path="$(printf "%s\n" "$artifact_block" | extract_json_string path)"
artifact_url="$(printf "%s\n" "$artifact_block" | extract_json_string url)"
artifact_size="$(printf "%s\n" "$artifact_block" | extract_json_number size)"
artifact_sha256="$(printf "%s\n" "$artifact_block" | extract_json_string sha256)"
expected_path="releases/standalone/$target/enricode.bin"
expected_url="$base_url/$expected_path"
case "$artifact_sha256" in
  *[!0-9a-f]*|"") echo "enricode install: signed artifact digest is invalid." >&2; exit 1 ;;
esac
if [ "$artifact_path" != "$expected_path" ] ||
   [ "$artifact_url" != "$expected_url" ] ||
   [ "${#artifact_sha256}" -ne 64 ] ||
   [ -z "$artifact_size" ] ||
   [ "$artifact_size" -le 0 ]; then
  echo "enricode install: signed artifact contract is invalid for $target." >&2
  exit 1
fi

download_path="$temporary_root/enricode"
download_file "$artifact_url" "$download_path"
actual_size="$(wc -c <"$download_path" | tr -d '[:space:]')"
if [ "$actual_size" -ne "$artifact_size" ]; then
  echo "enricode install: downloaded artifact size does not match the signed manifest." >&2
  exit 1
fi
if command -v sha256sum >/dev/null 2>&1; then
  actual_sha256="$(sha256sum "$download_path" | awk '{print $1}')"
else
  actual_sha256="$(shasum -a 256 "$download_path" | awk '{print $1}')"
fi
if [ "$actual_sha256" != "$artifact_sha256" ]; then
  echo "enricode install: downloaded artifact failed its signed SHA-256 integrity check." >&2
  exit 1
fi

bin_dir="$install_dir/bin"
mkdir -p "$bin_dir"
mv "$download_path" "$bin_dir/enricode"
chmod 0755 "$bin_dir/enricode"
ln -sf "enricode" "$bin_dir/ec"
if [ "$update_path" = "1" ]; then
  register_path
fi
log "installed verified EnriCode to $bin_dir/enricode"
log "run 'enricode version' in a new terminal to verify the PATH registration"
