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

# Deploy TiDBX to a fresh machine with explicit per-step reporting.
# Required env:
#   REMOTE_TARGET=admin@<host>
#   SSH_PORT=22 (optional)
#   LOCAL_TIKV_TAR=/path/to/tikv-server.tar.gz
#   LOCAL_PD_TAR=/path/to/pd-server.tar.gz
#   LOCAL_TIDB_TAR=/path/to/tidb-server.tar.gz
# Optional:
#   CLUSTER_NAME=cse
#   CLUSTER_VERSION=v8.5.0

SSH_PORT="${SSH_PORT:-22}"
REMOTE_TARGET="${REMOTE_TARGET:?set REMOTE_TARGET, e.g. admin@1.2.3.4}"
LOCAL_TIKV_TAR="${LOCAL_TIKV_TAR:-}"
LOCAL_PD_TAR="${LOCAL_PD_TAR:-}"
LOCAL_TIDB_TAR="${LOCAL_TIDB_TAR:-}"
CLUSTER_NAME="${CLUSTER_NAME:-cse}"
CLUSTER_VERSION="${CLUSTER_VERSION:-v8.5.0}"
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
CSE_TEMPLATE="${CSE_TEMPLATE:-$SCRIPT_DIR/../references/cse.yaml}"

run_remote() {
  ssh -p "$SSH_PORT" "$REMOTE_TARGET" "$@"
}

step() {
  local id="$1"; shift
  local title="$1"; shift
  echo "\n===== STEP ${id}: ${title} ====="
  if "$@"; then
    echo "[STEP ${id} RESULT] SUCCESS"
  else
    local rc=$?
    echo "[STEP ${id} RESULT] FAILED (exit=${rc})" >&2
    exit "$rc"
  fi
}

have_file() {
  local f="$1"
  [ -n "$f" ] && [ -f "$f" ]
}

print_plan() {
  cat <<'PLAN'
Execution Plan:
1) Install dependencies on remote: tiup, latest golang, mysql client, minio; export PATH.
2) Ensure minio is running in background with bucket path ~/serverless_s3/cse-test.
3) Generate local SSH key (if missing) and configure remote authorized_keys.
4) Upload cse.yaml to remote home directory.
5) Deploy cluster with: tiup cluster deploy cse v8.5.0 ./cse.yaml --ignore-config-check -y
6) Upload input tarballs to remote ~/bin.
7) Patch binaries for tidb/pd/tikv.
8) Start cluster.
PLAN
}

setup_ssh_key() {
  if [ ! -f "$HOME/.ssh/id_rsa" ]; then
    mkdir -p "$HOME/.ssh"
    chmod 700 "$HOME/.ssh"
    ssh-keygen -t rsa -b 4096 -N "" -f "$HOME/.ssh/id_rsa"
  fi

  if command -v ssh-copy-id >/dev/null 2>&1; then
    ssh-copy-id -i "$HOME/.ssh/id_rsa.pub" -p "$SSH_PORT" "$REMOTE_TARGET"
  else
    local pub
    pub="$(cat "$HOME/.ssh/id_rsa.pub")"
    ssh -p "$SSH_PORT" "$REMOTE_TARGET" "mkdir -p ~/.ssh && chmod 700 ~/.ssh && grep -qxF '$pub' ~/.ssh/authorized_keys 2>/dev/null || echo '$pub' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
  fi

  # TiUP deploy/start on single-host topology needs remote user SSH to 127.0.0.1.
  run_remote "bash -lc 'set -euo pipefail
mkdir -p ~/.ssh
chmod 700 ~/.ssh
if [ ! -f ~/.ssh/id_rsa ]; then
  ssh-keygen -t rsa -b 4096 -N \"\" -f ~/.ssh/id_rsa
fi
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
grep -qxFf ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys || cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
ssh -o StrictHostKeyChecking=accept-new -o BatchMode=yes admin@127.0.0.1 \"echo loopback-ssh-ok\" >/dev/null
'"

  run_remote "echo ssh-ready"
}

install_deps_remote() {
  run_remote "bash -lc 'set -euo pipefail
if command -v apt-get >/dev/null 2>&1; then
  sudo apt-get update
  sudo apt-get install -y curl wget tar ca-certificates
  sudo apt-get install -y default-mysql-client || sudo apt-get install -y mysql-client || true
elif command -v brew >/dev/null 2>&1; then
  brew update
  brew install mysql-client || true
else
  echo unsupported package manager >&2
  exit 2
fi

if ! command -v minio >/dev/null 2>&1; then
  curl -fsSL https://dl.min.io/server/minio/release/linux-amd64/minio -o /tmp/minio
  chmod +x /tmp/minio
  sudo mv /tmp/minio /usr/local/bin/minio
fi

if ! command -v go >/dev/null 2>&1; then
  if command -v apt-get >/dev/null 2>&1; then
    GO_VER=\$(curl -fsSL https://go.dev/VERSION?m=text | head -n1)
    curl -fsSL https://go.dev/dl/\${GO_VER}.linux-amd64.tar.gz -o /tmp/go.tar.gz
    sudo rm -rf /usr/local/go
    sudo tar -C /usr/local -xzf /tmp/go.tar.gz
  fi
fi

if [ ! -x \"\$HOME/.tiup/bin/tiup\" ] && ! command -v tiup >/dev/null 2>&1; then
  curl --proto \"=https\" --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
fi

for rc in \"\$HOME/.bashrc\" \"\$HOME/.zshrc\"; do
  touch \"\$rc\"
  grep -q \"/usr/local/go/bin\" \"\$rc\" || echo \"export PATH=/usr/local/go/bin:\$HOME/.tiup/bin:\$PATH\" >> \"\$rc\"
  grep -q \"\$HOME/.tiup/bin\" \"\$rc\" || echo \"export PATH=\$HOME/.tiup/bin:\$PATH\" >> \"\$rc\"
done
export PATH=/usr/local/go/bin:\$HOME/.tiup/bin:\$PATH
command -v go
command -v tiup
command -v mysql || true
command -v minio
'"
}

ensure_minio_remote() {
  run_remote "bash -lc 'set -euo pipefail
mkdir -p ~/serverless_s3/cse-test
if ! pgrep -af \"[m]inio server /home/admin/serverless_s3\" >/dev/null 2>&1; then
  nohup minio server /home/admin/serverless_s3 >/tmp/minio.log 2>&1 &
  sleep 3
fi
pgrep -af \"[m]inio server /home/admin/serverless_s3\" >/dev/null
ss -lntp | grep :9000 >/dev/null
'"
}

upload_cse_yaml() {
  [ -f "$CSE_TEMPLATE" ] || { echo "missing cse template: $CSE_TEMPLATE" >&2; return 1; }
  scp -P "$SSH_PORT" "$CSE_TEMPLATE" "$REMOTE_TARGET:~/cse.yaml"
}

deploy_cluster_remote() {
  run_remote "bash -lc 'set -euo pipefail
export PATH=/usr/local/go/bin:\$HOME/.tiup/bin:\$PATH
cd ~
if tiup cluster display ${CLUSTER_NAME} >/dev/null 2>&1; then
  echo \"[INFO] cluster ${CLUSTER_NAME} already exists, skip deploy\"
else
  tiup cluster deploy ${CLUSTER_NAME} ${CLUSTER_VERSION} ./cse.yaml --ignore-config-check -y
fi
'"
}

upload_if_needed() {
  local local_path="$1"
  local remote_path="$2"
  local role="$3"

  if ! have_file "$local_path"; then
    echo "[INFO] skip ${role} upload (local file missing): ${local_path:-<unset>}"
    return 0
  fi

  if ssh -p "$SSH_PORT" "$REMOTE_TARGET" "bash -lc '[ -f ${remote_path} ]'"; then
    echo "[INFO] skip ${role} upload (remote exists): ${remote_path}"
    return 0
  fi

  echo "[INFO] upload ${role}: remote missing"
  scp -P "$SSH_PORT" "$local_path" "$REMOTE_TARGET:${remote_path}"
}

upload_tarballs() {
  run_remote "mkdir -p ~/bin"
  upload_if_needed "$LOCAL_TIDB_TAR" "/home/admin/bin/tidb.tar.gz" "tidb"
  upload_if_needed "$LOCAL_PD_TAR" "/home/admin/bin/pd.tar.gz" "pd"
  upload_if_needed "$LOCAL_TIKV_TAR" "/home/admin/bin/tikv.tar.gz" "tikv"
}

patch_remote() {
  run_remote "bash -lc 'set -euo pipefail
export PATH=/usr/local/go/bin:\$HOME/.tiup/bin:\$PATH
cd ~
patched=0
if [ -f ~/bin/tidb.tar.gz ]; then
  tiup cluster patch ${CLUSTER_NAME} ~/bin/tidb.tar.gz -R tidb --offline -y --overwrite
  patched=1
else
  echo \"[INFO] skip tidb patch (~/bin/tidb.tar.gz not found)\"
fi
if [ -f ~/bin/pd.tar.gz ]; then
  tiup cluster patch ${CLUSTER_NAME} ~/bin/pd.tar.gz -R pd --offline -y --overwrite
  patched=1
else
  echo \"[INFO] skip pd patch (~/bin/pd.tar.gz not found)\"
fi
if [ -f ~/bin/tikv.tar.gz ]; then
  tiup cluster patch ${CLUSTER_NAME} ~/bin/tikv.tar.gz -R tikv --offline -y --overwrite
  patched=1
else
  echo \"[INFO] skip tikv patch (~/bin/tikv.tar.gz not found)\"
fi
if [ \"\$patched\" -eq 0 ]; then
  echo \"[INFO] no patch tarballs found, skip patch step\"
fi
'"
}

start_cluster_remote() {
  ensure_minio_remote
  run_remote "bash -lc 'set -euo pipefail
export PATH=/usr/local/go/bin:\$HOME/.tiup/bin:\$PATH
tiup cluster start ${CLUSTER_NAME}
'"
}

# ---------- prechecks ----------
print_plan
if ! have_file "$LOCAL_TIKV_TAR" && ! have_file "$LOCAL_PD_TAR" && ! have_file "$LOCAL_TIDB_TAR"; then
  echo "[INFO] no local tarball exists; step 6/7 will be skipped"
fi

step 1 "install deps on remote (tiup/go/mysql/minio + PATH)" install_deps_remote
step 2 "run minio in background if missing" ensure_minio_remote
step 3 "generate and configure ssh key" setup_ssh_key
step 4 "scp cse.yaml to remote" upload_cse_yaml
step 5 "deploy cluster with tiup" deploy_cluster_remote
step 6 "scp tikv/pd/tidb tarballs to remote ~/bin" upload_tarballs
step 7 "patch tidb/pd/tikv binaries" patch_remote
step 8 "start cluster" start_cluster_remote

echo "\nAll steps finished successfully."