#!/usr/bin/env bash
#
# sync-env-var.sh: 批量把 env var 同步到 FF AI Workspace 全部 5 个部署环境。
#
# 设计目的：FF AI Workspace + AIxC 两套产品 5 台应用服务器，新增 env var 历史上靠人记 / 单环境
# 手动 SSH，常漏掉 Test / AIxC 两路。本工具按权威清单一次性追加 + 备份 + diff，
# 防漏防错。详见 .learnings/2026-05-16-five-envs-not-two.md。
#
# 用法：
#   bash scripts/ops/sync-env-var.sh KEY=VALUE [KEY2=VALUE2 ...]
#   bash scripts/ops/sync-env-var.sh --dry-run KEY=VALUE
#   bash scripts/ops/sync-env-var.sh --header "# === XXX 模块 (#NNN) ===" KEY=VALUE
#   bash scripts/ops/sync-env-var.sh --comment "用途说明" KEY=VALUE
#   bash scripts/ops/sync-env-var.sh --envs ffai-test,ffai-uat KEY=VALUE   # 仅指定子集
#
# 行为：
#   1. SSH 每个目标环境，cp <env> <env>.bak.YYYYMMDD-HHMM 备份
#   2. cat >> <env> << EOF 追加 KEY=VALUE（含可选注释块）
#   3. diff 验证；任何 SSH 失败 → 立即中止剩余环境
#   4. **不重启 pm2**（让用户决定时间窗口）
#
# 环境清单（权威源 docs/ops/01-server-infrastructure.md）：
#   ffai-test : ubuntu@170.106.161.71:/srv/apps/ffworkspace-test/.env.test
#   ffai-uat  : ubuntu@43.153.69.73:/srv/apps/ffworkspace-test/.env.uat
#   ffai-pro  : srvadmin@43.130.6.44:/srv/apps/ffworkspace/.env.pro
#   aixc-uat  : itadminaixc@52.234.29.56:/srv/apps/aixcworkspace/.env.uat
#   aixc-pro  : itadminaixc@23.101.202.65:/srv/apps/aixcworkspace/.env.pro

set -euo pipefail

# ---- 环境清单（单一来源；新加环境改这里一处） ----
declare -a ENVS_ALL=(
  "ffai-test|ubuntu@170.106.161.71|/srv/apps/ffworkspace-test|.env.test"
  "ffai-uat|ubuntu@43.153.69.73|/srv/apps/ffworkspace-test|.env.uat"
  "ffai-pro|srvadmin@43.130.6.44|/srv/apps/ffworkspace|.env.pro"
  "aixc-uat|itadminaixc@52.234.29.56|/srv/apps/aixcworkspace|.env.uat"
  "aixc-pro|itadminaixc@23.101.202.65|/srv/apps/aixcworkspace|.env.pro"
)

DRY_RUN=0
HEADER=""
COMMENT=""
ENV_FILTER=""
KV_PAIRS=()

usage() {
  sed -n '2,30p' "$0" | sed 's/^# \?//'
  exit "${1:-0}"
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --dry-run) DRY_RUN=1; shift ;;
    --header) HEADER="$2"; shift 2 ;;
    --comment) COMMENT="$2"; shift 2 ;;
    --envs) ENV_FILTER="$2"; shift 2 ;;
    -h|--help) usage 0 ;;
    -*) echo "未知参数：$1" >&2; usage 1 ;;
    *=*) KV_PAIRS+=("$1"); shift ;;
    *) echo "参数 '$1' 不是 KEY=VALUE 形式" >&2; usage 1 ;;
  esac
done

if [[ ${#KV_PAIRS[@]} -eq 0 ]]; then
  echo "❌ 至少需要一个 KEY=VALUE 对" >&2
  usage 1
fi

# 过滤环境
declare -a ENVS
if [[ -n "$ENV_FILTER" ]]; then
  IFS=',' read -ra WANTED <<< "$ENV_FILTER"
  for env_entry in "${ENVS_ALL[@]}"; do
    name="${env_entry%%|*}"
    for w in "${WANTED[@]}"; do
      [[ "$w" == "$name" ]] && ENVS+=("$env_entry")
    done
  done
  if [[ ${#ENVS[@]} -eq 0 ]]; then
    echo "❌ --envs 过滤后没匹配到任何环境。可选：ffai-test ffai-uat ffai-pro aixc-uat aixc-pro" >&2
    exit 1
  fi
else
  ENVS=("${ENVS_ALL[@]}")
fi

TS=$(date +%Y%m%d-%H%M)

# 构造追加内容
build_payload() {
  local out=""
  if [[ -n "$HEADER" ]]; then
    out+=$'\n'"$HEADER"$'\n'
  else
    out+=$'\n'
  fi
  if [[ -n "$COMMENT" ]]; then
    while IFS= read -r line; do
      out+="# $line"$'\n'
    done <<< "$COMMENT"
  fi
  for kv in "${KV_PAIRS[@]}"; do
    out+="$kv"$'\n'
  done
  printf '%s' "$out"
}
PAYLOAD=$(build_payload)

echo "==============================================="
echo "目标环境：${#ENVS[@]} 个"
for env_entry in "${ENVS[@]}"; do
  IFS='|' read -r name ssh_target deploy_dir env_file <<< "$env_entry"
  echo "  - $name : $ssh_target  →  $deploy_dir/$env_file"
done
echo
echo "追加内容："
echo "---"
echo "$PAYLOAD"
echo "---"
[[ "$DRY_RUN" -eq 1 ]] && { echo "（--dry-run 不执行 SSH）"; exit 0; }
echo "继续？[y/N]"
read -r ans
[[ "$ans" == "y" || "$ans" == "Y" ]] || { echo "已取消"; exit 0; }

# 提取所有 KEY 名（用于远端重复检测）
declare -a KEY_NAMES
for kv in "${KV_PAIRS[@]}"; do
  KEY_NAMES+=("${kv%%=*}")
done
KEYS_SPACE_SEP="${KEY_NAMES[*]}"

# PAYLOAD 经 base64 编码传输：彻底消除本地 / 远端 shell 对值中 $VAR / 反引号 /
# heredoc marker 的二次扩展或意外解释（AI review round 12 #3）。
PAYLOAD_B64=$(printf '%s' "$PAYLOAD" | base64 -w0)

# 逐环境执行
FAILED=()
for env_entry in "${ENVS[@]}"; do
  IFS='|' read -r name ssh_target deploy_dir env_file <<< "$env_entry"
  echo
  echo "=== [$name] $ssh_target ==="

  # ssh 内：(1) 重复 KEY 检测（warn 不阻断）→ (2) backup → (3) base64 解码追加 → (4) diff
  if ssh -o ConnectTimeout=15 -o BatchMode=no "$ssh_target" "
    set -e
    cd '$deploy_dir' || { echo '目录不存在: $deploy_dir' >&2; exit 2; }
    [ -f '$env_file' ] || { echo 'env 文件不存在: $env_file' >&2; exit 3; }
    # (1) 重复 KEY 检测：warn 不阻断（dotenv 主流解析 last-wins，但污染可读性）
    for k in $KEYS_SPACE_SEP; do
      if grep -q \"^\${k}=\" '$env_file' 2>/dev/null; then
        echo \"⚠️  \${k} 已存在于 $env_file，追加会出现重复定义（dotenv last-wins）\" >&2
      fi
    done
    # (2) backup
    cp '$env_file' '${env_file}.bak.${TS}'
    # (3) 追加（base64 解码避免 $VAR / 反引号 / heredoc marker 转义陷阱）
    echo '$PAYLOAD_B64' | base64 -d >> '$env_file'
    # (4) diff 验证
    diff '${env_file}.bak.${TS}' '$env_file' | tail -20
    echo '✓ backup: ${env_file}.bak.${TS}'
  "; then
    echo "[$name] ✓"
  else
    echo "[$name] ✗ 失败"
    FAILED+=("$name")
  fi
done

echo
echo "==============================================="
if [[ ${#FAILED[@]} -eq 0 ]]; then
  echo "✅ 全部 ${#ENVS[@]} 环境同步完成"
  echo
  echo "🔁 重启提示（不自动执行；按需手工）："
  echo "  - 后端 env 变更：ssh <env> 'pm2 restart <backend-name>'"
  echo "  - 前端 NEXT_PUBLIC_* 变更：ssh <env> 'cd <root>/frontend && npm run build && pm2 reload <frontend-name>'"
else
  echo "❌ 失败：${FAILED[*]}"
  echo "（成功环境的 backup 文件已生成，可用 .${TS} 时间戳找回）"
  exit 1
fi
