#!/bin/bash
#
# rebrand: 把面向用户的品牌标识从 GPUStack 批量替换为 MesaStack（或自定义品牌）。
#
# 设计目标：上游每次更新后，在新的 v<version>-lofyer 分支上跑一次即可重新应用品牌定制。
#
# 只替换「独立的品牌词」FROM，并刻意跳过所有功能性引用：
#   - 小写 `gpustack`     —— npm 包名 (@gpustack/core-ui)、URL、路径、k8s 命名空间、author（大小写敏感，天然不匹配）
#   - 全大写 `GPUSTACK`   —— 常量/环境变量/全局 (GPUSTACK_API_BASE_URL, __GPUSTACK_*__, GPUSTACK_UI_*)（大小写敏感，不匹配）
#   - 代码标识符          —— getGPUStackPlugin / GPUStackVersionAtom / GPUStackPluginManager / GPUStackLogo 等
#                            （FROM 紧邻字母时视为标识符的一部分，跳过）
#   - HTTP 头 X-GPUStack-* —— 后端契约 (如 X-GPUStack-Model)，跳过
#
# 匹配规则：FROM 前后都不是字母（独立单词），且不是 `X-` 前缀的头名。
#
# 环境变量：
#   FROM       源品牌词（默认 GPUStack）
#   TO         目标品牌词（默认 MesaStack）
#   DRY_RUN    设为 1 时只预览将改动的行，不写文件
#
set -e

FROM="${FROM:-GPUStack}"
TO="${TO:-MesaStack}"
DRY_RUN="${DRY_RUN:-0}"

log() { echo -e "\033[1;34m[rebrand]\033[0m $*"; }

# 大小写敏感、单词边界、排除 X- 头前缀的 Perl 正则。
# (?<![A-Za-z]) 前面不是字母  (?<!X-) 不是 X- 头  (?![A-Za-z]) 后面不是字母
# FROM 为纯字母品牌词（无正则元字符），故直接拼接，不用 \Q\E
# —— \Q\E 在「经变量插值进正则」时不会被求值，反而会破坏匹配。
PATTERN="(?<![A-Za-z])(?<!X-)${FROM}(?![A-Za-z])"

# 行级排除：某些 FROM 出现在「与后端契约绑定的字符串」里，改了会破坏运行时逻辑，
# 即使是独立单词也必须整行跳过。命中下列任一正则的行不替换。
# 已知例外：
#   - llmodels/hooks/index.ts 用 startsWith() 比对后端返回的英文兼容性消息
#     （"... does not exist on the GPUStack server ..."），后端仍发 GPUStack，前端不能改。
SKIP_LINE_PATTERNS=(
  'does not exist on the .*server. It'"'"'s recommended'
)
skip_line() {
  local line="$1" pat
  for pat in "${SKIP_LINE_PATTERNS[@]}"; do
    if echo "$line" | grep -qP "$pat"; then return 0; fi
  done
  return 1
}

# 待处理的已跟踪文本文件（排除 lockfile 与本脚本自身）。
mapfile -t files < <(
  git ls-files -- \
    '*.ts' '*.tsx' '*.js' '*.jsx' '*.json' '*.less' '*.html' '*.md' \
  | grep -v 'pnpm-lock.yaml'
)

log "品牌替换: '${FROM}' -> '${TO}'"
log "候选文件: ${#files[@]}"

# 把行级排除合并成一个 perl 正则，供预览与替换共用（经环境变量传入，免去转义）。
SKIP_RE=""
for pat in "${SKIP_LINE_PATTERNS[@]}"; do
  SKIP_RE="${SKIP_RE:+${SKIP_RE}|}(?:${pat})"
done
export REBRAND_SKIP_RE="${SKIP_RE}"
export REBRAND_PATTERN="${PATTERN}"
export REBRAND_TO="${TO}"

# 统计命中行（预览/确认用），已扣除被行级排除的行。
log "命中行预览（最多 40 行）："
grep -rnP "${PATTERN}" "${files[@]}" 2>/dev/null \
  | { [[ -n "${SKIP_RE}" ]] && grep -vP "${SKIP_RE}" || cat; } \
  | head -40 || true
total=$(grep -rnP "${PATTERN}" "${files[@]}" 2>/dev/null \
  | { [[ -n "${SKIP_RE}" ]] && grep -vP "${SKIP_RE}" || cat; } | wc -l)
log "命中总行数: ${total}"
if [[ -n "${SKIP_RE}" ]]; then
  skipped=$(grep -rnP "${PATTERN}" "${files[@]}" 2>/dev/null | grep -cP "${SKIP_RE}" || true)
  log "行级排除（后端契约，保留 ${FROM}）: ${skipped} 行"
fi

if [[ "${DRY_RUN}" == "1" ]]; then
  log "DRY_RUN=1：未写入任何文件。"
  exit 0
fi

# 实际替换（in-place）。命中行级排除的行整行跳过。
changed=0
for f in "${files[@]}"; do
  if grep -qP "${PATTERN}" "$f" 2>/dev/null; then
    perl -i -pe '
      my $skip = $ENV{REBRAND_SKIP_RE};
      next if length($skip) && /$skip/;
      s/$ENV{REBRAND_PATTERN}/$ENV{REBRAND_TO}/g;
    ' "$f"
    changed=$((changed + 1))
  fi
done

log "已修改文件数: ${changed}"
log "完成。请用 'git diff' 复核改动。"
