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

# Run Cargo commands on a remote Rust build host while editing locally.
# Defaults match the development server prepared for this machine.
#
# Examples:
#   ./scripts/remote-cargo.sh
#   ./scripts/remote-cargo.sh check -p pipi
#   ./scripts/remote-cargo.sh clippy --workspace --all-targets
#   REMOTE=root@10.126.126.1 REMOTE_DIR=/data/workspace/pipi ./scripts/remote-cargo.sh build --release

REMOTE=${REMOTE:-root@10.126.126.1}
REMOTE_DIR=${REMOTE_DIR:-/data/workspace/pipi}
REMOTE_TARGET_DIR=${REMOTE_TARGET_DIR:-/data/cargo-target/pipi}
REMOTE_CARGO_NO_SYNC=${REMOTE_CARGO_NO_SYNC:-0}
SSH_OPTS=${SSH_OPTS:-}
RSYNC_OPTS=${RSYNC_OPTS:-}

usage() {
  cat <<USAGE
Usage: ${0##*/} [--no-sync] [cargo-subcommand args...]

Sync this repository to a remote host, then run Cargo there.
If no Cargo command is supplied, defaults to:
  cargo check --workspace --all-targets

Environment variables:
  REMOTE                 SSH target. Default: root@10.126.126.1
  REMOTE_DIR             Remote source directory. Default: /data/workspace/pipi
  REMOTE_TARGET_DIR      Remote Cargo target dir. Default: /data/cargo-target/pipi
  REMOTE_CARGO_NO_SYNC=1 Skip rsync and only run the command remotely
  SSH_OPTS               Extra ssh options, e.g. '-p 2222'
  RSYNC_OPTS             Extra rsync options

Examples:
  ./scripts/remote-cargo.sh
  ./scripts/remote-cargo.sh check -p pipi
  ./scripts/remote-cargo.sh cargo fmt --all -- --check
  REMOTE_CARGO_NO_SYNC=1 ./scripts/remote-cargo.sh check --workspace
USAGE
}

if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
  usage
  exit 0
fi

if [[ "${1:-}" == "--no-sync" ]]; then
  REMOTE_CARGO_NO_SYNC=1
  shift
fi

# Allow both `remote-cargo.sh check ...` and `remote-cargo.sh cargo check ...`.
if [[ "${1:-}" == "cargo" ]]; then
  shift
fi

cargo_args=("$@")
if [[ ${#cargo_args[@]} -eq 0 ]]; then
  cargo_args=(check --workspace --all-targets)
fi

repo_root=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
cd "$repo_root"

printf '[remote-cargo] repo: %s\n' "$repo_root"
printf '[remote-cargo] remote: %s:%s\n' "$REMOTE" "$REMOTE_DIR"
printf '[remote-cargo] target: %s\n' "$REMOTE_TARGET_DIR"
printf '[remote-cargo] command: cargo %s\n' "${cargo_args[*]}"

if [[ "$REMOTE_CARGO_NO_SYNC" != "1" ]]; then
  printf '[remote-cargo] syncing source...\n'
  # SSH_OPTS/RSYNC_OPTS are intentionally expanded as simple option strings.
  # For complex options containing spaces, prefer ~/.ssh/config.
  # shellcheck disable=SC2086
  ssh $SSH_OPTS "$REMOTE" "mkdir -p '$REMOTE_DIR' '$REMOTE_TARGET_DIR'"
  # shellcheck disable=SC2086
  rsync -az --delete \
    --exclude='.git/' \
    --exclude='target/' \
    --exclude='.DS_Store' \
    --exclude='.idea/' \
    --exclude='.vscode/' \
    --exclude='node_modules/' \
    --exclude='docs-site/node_modules/' \
    --exclude='docs-site/.docusaurus/' \
    --exclude='docs-site/build/' \
    --exclude='starters/saas/frontend/node_modules/' \
    --exclude='starters/saas/frontend/dist/' \
    --exclude='pipi-new/base_template/frontend/node_modules/' \
    --exclude='pipi-new/base_template/frontend/dist/' \
    $RSYNC_OPTS \
    -e "ssh $SSH_OPTS" \
    ./ "$REMOTE:$REMOTE_DIR/"
else
  printf '[remote-cargo] sync skipped.\n'
fi

printf '[remote-cargo] running remotely...\n'
# shellcheck disable=SC2086
ssh $SSH_OPTS "$REMOTE" bash -s -- "$REMOTE_DIR" "$REMOTE_TARGET_DIR" "${cargo_args[@]}" <<'REMOTE_SCRIPT'
set -Eeuo pipefail
remote_dir=$1
target_dir=$2
shift 2

export RUSTUP_HOME=${RUSTUP_HOME:-/data/rustup}
export CARGO_HOME=${CARGO_HOME:-/data/cargo}
export RUSTUP_DIST_SERVER=${RUSTUP_DIST_SERVER:-https://rsproxy.cn}
export RUSTUP_UPDATE_ROOT=${RUSTUP_UPDATE_ROOT:-https://rsproxy.cn/rustup}
export CARGO_TARGET_DIR=$target_dir
export PATH="$CARGO_HOME/bin:$PATH"

cd "$remote_dir"
printf '[remote-cargo:remote] pwd: %s\n' "$(pwd)"
printf '[remote-cargo:remote] rustc: %s\n' "$(rustc --version)"
printf '[remote-cargo:remote] cargo: %s\n' "$(cargo --version)"
exec cargo "$@"
REMOTE_SCRIPT
