#!/usr/bin/env bash
# Install or upgrade the Outprint CLI (`outprint`) for the current machine.
# Published as:
#   curl -fsSL https://outprint.app/downloads/desktop/install.sh | bash
#
# Requires bash (not POSIX sh): the public one-liner pipes into bash so
# systems where /bin/sh is dash still work.
set -euo pipefail

if [[ -z "${BASH_VERSION:-}" ]]; then
  echo "this installer requires bash; run: curl -fsSL https://outprint.app/downloads/desktop/install.sh | bash" >&2
  exit 1
fi

BASE_URL="${OUTPRINT_BASE_URL:-https://outprint.app}"
BASE_URL="${BASE_URL%/}"
FEED_BASE="${OUTPRINT_FEED_BASE:-${BASE_URL}/downloads/desktop}"
BIN_DIR="${OUTPRINT_BIN_DIR:-${HOME}/.local/bin}"
BIN_NAME=outprint

write_feed_public_key() {
  # ECDSA P-256 SPKI PEM — must match CLI_FEED_PUBLIC_KEY_PEM in updater.rs
  if [[ -n "${OUTPRINT_CLI_FEED_PUBLIC_KEY_PEM:-}" ]]; then
    printf '%s\n' "$OUTPRINT_CLI_FEED_PUBLIC_KEY_PEM" >"$1"
    return
  fi
  cat >"$1" <<'PEM'
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2qDB9aHwb9arEqYD1l5oiTuuJWkv
GqKN0odDAlxi9UWvnbcqhnS0Mfp0N/d1jD6zJ8vk8kXzTKzRlk4a/PsNsg==
-----END PUBLIC KEY-----
PEM
}

for arg in "$@"; do
  case "$arg" in
    --yes|-y) ;;
    --help|-h)
      cat <<'EOF'
Install the Outprint CLI into ~/.local/bin (override with OUTPRINT_BIN_DIR).

  curl -fsSL https://outprint.app/downloads/desktop/install.sh | bash

Environment:
  OUTPRINT_BASE_URL   default https://outprint.app
  OUTPRINT_FEED_BASE  default $OUTPRINT_BASE_URL/downloads/desktop
  OUTPRINT_BIN_DIR    default $HOME/.local/bin

Currently ships a macOS Apple silicon build. Verifies the signed feed + sha256.
EOF
      exit 0
      ;;
    *)
      echo "unknown flag: $arg (try --help)" >&2
      exit 1
      ;;
  esac
done

os="$(uname -s 2>/dev/null || echo unknown)"
arch="$(uname -m 2>/dev/null || echo x86_64)"
case "$arch" in
  aarch64|arm64) arch_label=aarch64 ;;
  *)
    echo "unsupported architecture: $arch (Apple silicon / aarch64 only for now)" >&2
    exit 1
    ;;
esac
case "$os" in
  Darwin) os_label=macos ;;
  *)
    echo "unsupported OS: $os (macOS Apple silicon only for now; Linux packages are not published yet)" >&2
    exit 1
    ;;
esac

feed_url="${FEED_BASE}/feed-cli-${os_label}-${arch_label}.json"
echo "Outprint CLI installer"
echo "  feed: ${feed_url}"

need() {
  if ! command -v "$1" >/dev/null 2>&1; then
    echo "$1 is required" >&2
    exit 1
  fi
}
need curl
need tar
need openssl
if ! command -v shasum >/dev/null 2>&1 && ! command -v sha256sum >/dev/null 2>&1; then
  echo "shasum or sha256sum is required" >&2
  exit 1
fi

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT

feed_body="${tmp}/feed.json"
curl -fsSL "$feed_url" -o "$feed_body"

if command -v python3 >/dev/null 2>&1; then
  version="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1],encoding="utf-8"))["version"])' "$feed_body")"
  url="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1],encoding="utf-8"))["url"])' "$feed_body")"
  expected_sha="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1],encoding="utf-8"))["sha256"])' "$feed_body")"
  sig_hex="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1],encoding="utf-8")).get("sig",""))' "$feed_body")"
else
  version="$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$feed_body" | head -1)"
  url="$(sed -n 's/.*"url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$feed_body" | head -1)"
  expected_sha="$(sed -n 's/.*"sha256"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$feed_body" | head -1)"
  sig_hex="$(sed -n 's/.*"sig"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$feed_body" | head -1)"
fi
if [[ -z "${version:-}" || -z "${url:-}" || -z "${expected_sha:-}" || -z "${sig_hex:-}" ]]; then
  echo "could not parse signed feed JSON at ${feed_url}" >&2
  exit 1
fi

# Host allowlist for package URL (bootstrap must not follow arbitrary hosts).
# Production packages live on downloads.outprint.app (R2); feeds stay on
# outprint.app. Legacy origin-hosted package URLs remain accepted.
case "$url" in
  https://outprint.app/*|https://www.outprint.app/*|https://downloads.outprint.app/*) ;;
  http://127.0.0.1/*|http://localhost/*|http://localhost:*/*|http://127.0.0.1:*/*) ;;
  *)
    echo "refusing package URL outside allowlisted hosts: $url" >&2
    exit 1
    ;;
esac

# Verify ECDSA P-256/SHA-256 feed signature (LibreSSL/OpenSSL portable).
msg_file="${tmp}/msg"
sig_file="${tmp}/sig"
pk_file="${tmp}/pk.pem"
printf '%s\n%s\n%s\n' "$version" "$url" "$expected_sha" >"$msg_file"
write_feed_public_key "$pk_file"
if command -v xxd >/dev/null 2>&1; then
  printf '%s' "$sig_hex" | xxd -r -p >"$sig_file"
else
  # Fallback without xxd
  python3 -c 'import sys; open(sys.argv[1],"wb").write(bytes.fromhex(sys.argv[2]))' "$sig_file" "$sig_hex"
fi
if ! openssl dgst -sha256 -verify "$pk_file" -signature "$sig_file" "$msg_file" >/dev/null 2>&1; then
  echo "feed signature verification failed" >&2
  exit 1
fi
echo "  feed signature: ok"

echo "  version: ${version}"
echo "  package: ${url}"

archive="${tmp}/outprint-cli.tar.gz"
curl -fsSL "$url" -o "$archive"

if command -v shasum >/dev/null 2>&1; then
  got_sha="$(shasum -a 256 "$archive" | awk '{print $1}')"
else
  got_sha="$(sha256sum "$archive" | awk '{print $1}')"
fi
if [[ "${got_sha}" != "${expected_sha}" ]]; then
  echo "sha256 mismatch: expected ${expected_sha}, got ${got_sha}" >&2
  exit 1
fi

extract="${tmp}/extract"
mkdir -p "$extract"
tar -xzf "$archive" -C "$extract"
if [[ -f "${extract}/${BIN_NAME}" ]]; then
  bin_src="${extract}/${BIN_NAME}"
else
  bin_src="$(find "$extract" -type f -name "$BIN_NAME" | head -1 || true)"
fi
if [[ -z "${bin_src:-}" || ! -f "$bin_src" ]]; then
  echo "archive did not contain ${BIN_NAME}" >&2
  exit 1
fi
chmod 755 "$bin_src"

mkdir -p "$BIN_DIR"
dest="${BIN_DIR}/${BIN_NAME}"
install -m 755 "$bin_src" "${dest}.new"
mv -f "${dest}.new" "$dest"

echo "Installed ${dest} (${version})"
case ":${PATH}:" in
  *":${BIN_DIR}:"*) ;;
  *)
    echo "Note: add ${BIN_DIR} to PATH, e.g. export PATH=\"${BIN_DIR}:\$PATH\""
    ;;
esac
echo "Next: outprint login && outprint whoami"
echo "Upgrade later: outprint update   # or re-run this installer"
