#!/usr/bin/env bash
# CoinVision 版本号升级脚本
#
# 同步更新两处版本号:
#   1) pubspec.yaml             → version: X.Y.Z+CODE
#   2) lib/core/config/app_config.dart → static const String appVersion = 'X.Y.Z';
#
# 用法:
#   ./scripts/bump-version.sh patch        # 4.0.3 → 4.0.4 (修订号+1)
#   ./scripts/bump-version.sh minor        # 4.0.3 → 4.1.0 (次版本+1,修订号归零)
#   ./scripts/bump-version.sh major        # 4.0.3 → 5.0.0 (主版本+1,次/修订归零)
#   ./scripts/bump-version.sh 4.2.1        # 手动指定版本号
#   ./scripts/bump-version.sh --show       # 只显示当前版本,不修改
#   ./scripts/bump-version.sh --dry-run patch  # 预览改动,不写入文件
#
# versionCode 规则: major × 10000 + minor × 100 + patch
#   例: 4.0.3 → 40003 ; 4.1.0 → 40100 ; 5.0.0 → 50000
#
# 安全检查:
#   - 新 versionCode 必须严格大于当前 versionCode,否则拒绝更新
#   - pubspec.yaml 的 x.y.z 必须和 app_config.dart 的 appVersion 一致

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_ROOT"

PUBSPEC="pubspec.yaml"
APP_CONFIG="lib/core/config/app_config.dart"

if [ -t 1 ]; then
  RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
  BLUE='\033[0;34m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
else
  RED=''; GREEN=''; YELLOW=''; BLUE=''; CYAN=''; BOLD=''; NC=''
fi

log_info() { printf "${BLUE}==>${NC} %s\n" "$*"; }
log_ok()   { printf "${GREEN}✓${NC}  %s\n" "$*"; }
log_warn() { printf "${YELLOW}!${NC}  %s\n" "$*"; }
log_err()  { printf "${RED}✗${NC}  %s\n" "$*" >&2; }

usage() {
  cat <<EOF
CoinVision 版本号升级脚本

用法:
  ./scripts/bump-version.sh <模式> [选项]

模式:
  patch            修订号 +1 (4.0.3 → 4.0.4)
  minor            次版本 +1,修订号归零 (4.0.3 → 4.1.0)
  major            主版本 +1,次/修订归零 (4.0.3 → 5.0.0)
  X.Y.Z            手动指定版本号 (如 4.2.1)
  --show           仅显示当前版本,不修改

选项:
  --dry-run        预览改动,不写入文件
  -h, --help       显示此帮助

示例:
  ./scripts/bump-version.sh --show
  ./scripts/bump-version.sh patch
  ./scripts/bump-version.sh minor --dry-run
  ./scripts/bump-version.sh 4.2.1

versionCode = major × 10000 + minor × 100 + patch
EOF
}

if [ ! -f "$PUBSPEC" ]; then
  log_err "找不到 $PUBSPEC"
  exit 1
fi
if [ ! -f "$APP_CONFIG" ]; then
  log_err "找不到 $APP_CONFIG"
  exit 1
fi

# ── 解析当前版本 ─────────────────────────────────────────────
CURRENT_LINE=$(grep -E "^version:" "$PUBSPEC" | head -1)
if [ -z "$CURRENT_LINE" ]; then
  log_err "$PUBSPEC 中未找到 version: 行"
  exit 1
fi
CURRENT_VERSION_FULL=$(echo "$CURRENT_LINE" | awk '{print $2}' | tr -d '[:space:]')
CURRENT_SEMVER="${CURRENT_VERSION_FULL%%+*}"
CURRENT_CODE="${CURRENT_VERSION_FULL##*+}"

if ! echo "$CURRENT_SEMVER" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
  log_err "当前 pubspec.yaml 版本号格式非法: $CURRENT_SEMVER (应为 x.y.z)"
  exit 1
fi
if ! echo "$CURRENT_CODE" | grep -qE '^[0-9]+$'; then
  log_err "当前 pubspec.yaml versionCode 格式非法: $CURRENT_CODE"
  exit 1
fi

CURRENT_MAJOR="${CURRENT_SEMVER%%.*}"
CURRENT_REST="${CURRENT_SEMVER#*.}"
CURRENT_MINOR="${CURRENT_REST%%.*}"
CURRENT_PATCH="${CURRENT_REST##*.}"

# ── 解析 app_config.dart 中的 appVersion ────────────────────
APP_CONFIG_VERSION=$(grep -E "static const String appVersion" "$APP_CONFIG" | sed -E "s/.*'([^']+)'.*/\1/")
if [ -z "$APP_CONFIG_VERSION" ]; then
  log_err "$APP_CONFIG 中未找到 static const String appVersion"
  exit 1
fi

# ── 参数解析 ─────────────────────────────────────────────────
MODE=""
DRY_RUN=false
while [ $# -gt 0 ]; do
  case "$1" in
    -h|--help) usage; exit 0 ;;
    --show)
      printf "${CYAN}${BOLD}当前版本${NC}\n"
      printf "  pubspec.yaml     : %s (semver=%s, code=%s)\n" "$CURRENT_VERSION_FULL" "$CURRENT_SEMVER" "$CURRENT_CODE"
      printf "  app_config.dart  : %s\n" "$APP_CONFIG_VERSION"
      if [ "$CURRENT_SEMVER" != "$APP_CONFIG_VERSION" ]; then
        log_warn "两处版本号不一致!"
        exit 1
      fi
      exit 0
      ;;
    --dry-run) DRY_RUN=true ;;
    patch|minor|major)
      MODE="$1"
      ;;
    [0-9]*.[0-9]*.[0-9]*)
      MODE="manual"
      MANUAL_VERSION="$1"
      ;;
    *) log_err "未知参数: $1"; echo; usage; exit 1 ;;
  esac
  shift
done

if [ -z "$MODE" ]; then
  log_err "未指定模式"
  echo
  usage
  exit 1
fi

# ── 一致性校验 ───────────────────────────────────────────────
if [ "$CURRENT_SEMVER" != "$APP_CONFIG_VERSION" ]; then
  log_warn "pubspec.yaml ($CURRENT_SEMVER) 与 app_config.dart ($APP_CONFIG_VERSION) 不一致"
  log_warn "将以 pubspec.yaml 为基准计算新版本"
fi

# ── 计算新版本 ───────────────────────────────────────────────
case "$MODE" in
  patch)
    NEW_MAJOR="$CURRENT_MAJOR"
    NEW_MINOR="$CURRENT_MINOR"
    NEW_PATCH=$((CURRENT_PATCH + 1))
    ;;
  minor)
    NEW_MAJOR="$CURRENT_MAJOR"
    NEW_MINOR=$((CURRENT_MINOR + 1))
    NEW_PATCH=0
    ;;
  major)
    NEW_MAJOR=$((CURRENT_MAJOR + 1))
    NEW_MINOR=0
    NEW_PATCH=0
    ;;
  manual)
    if ! echo "$MANUAL_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
      log_err "手动版本号格式非法: $MANUAL_VERSION (应为 x.y.z)"
      exit 1
    fi
    NEW_MAJOR="${MANUAL_VERSION%%.*}"
    _REST="${MANUAL_VERSION#*.}"
    NEW_MINOR="${_REST%%.*}"
    NEW_PATCH="${_REST##*.}"
    ;;
esac

# 修订号不得超过 99,否则和下一个次版本的 versionCode 冲突
if [ "$NEW_PATCH" -gt 99 ]; then
  log_err "修订号 $NEW_PATCH 超过 99,会和下一个次版本 versionCode 冲突"
  log_err "建议升级 minor 版本: ./scripts/bump-version.sh minor"
  exit 1
fi
if [ "$NEW_MINOR" -gt 99 ]; then
  log_err "次版本号 $NEW_MINOR 超过 99,会和下一个主版本 versionCode 冲突"
  log_err "建议升级 major 版本: ./scripts/bump-version.sh major"
  exit 1
fi

NEW_SEMVER="${NEW_MAJOR}.${NEW_MINOR}.${NEW_PATCH}"
NEW_CODE=$((NEW_MAJOR * 10000 + NEW_MINOR * 100 + NEW_PATCH))
NEW_VERSION_FULL="${NEW_SEMVER}+${NEW_CODE}"

# ── 安全检查: versionCode 必须严格递增 ──────────────────────
if [ "$NEW_CODE" -le "$CURRENT_CODE" ]; then
  log_err "新 versionCode ($NEW_CODE) 不大于当前 versionCode ($CURRENT_CODE)"
  log_err "Android 拒绝安装 versionCode 更低或相同的包"
  exit 1
fi

# ── 展示变化 ─────────────────────────────────────────────────
printf "\n${CYAN}${BOLD}版本号变更预览${NC}\n"
printf "  版本号      : ${YELLOW}%s${NC} → ${GREEN}%s${NC}\n" "$CURRENT_SEMVER" "$NEW_SEMVER"
printf "  versionCode : ${YELLOW}%s${NC} → ${GREEN}%s${NC}\n" "$CURRENT_CODE" "$NEW_CODE"
printf "  完整写入    : ${GREEN}%s${NC}\n" "$NEW_VERSION_FULL"
printf "\n${CYAN}${BOLD}将更新文件${NC}\n"
printf "  %s (line: version: %s)\n" "$PUBSPEC" "$NEW_VERSION_FULL"
printf "  %s (line: static const String appVersion = '%s';)\n" "$APP_CONFIG" "$NEW_SEMVER"

if [ "$DRY_RUN" = true ]; then
  echo
  log_info "dry-run 模式,未写入文件"
  exit 0
fi

# ── 写入文件 (macOS/BSD sed 和 GNU sed 兼容) ─────────────────
sed_inplace() {
  local pattern="$1"
  local file="$2"
  # macOS BSD sed 要求 -i '' ; GNU sed 不能加 ''
  if sed --version >/dev/null 2>&1; then
    sed -i "$pattern" "$file"
  else
    sed -i '' "$pattern" "$file"
  fi
}

# pubspec.yaml: 替换第一个 ^version: 开头的行
sed_inplace "s|^version:.*|version: ${NEW_VERSION_FULL}|" "$PUBSPEC"

# app_config.dart: 替换 appVersion 常量
sed_inplace "s|static const String appVersion = '[^']*';|static const String appVersion = '${NEW_SEMVER}';|" "$APP_CONFIG"

# ── 写入验证 ─────────────────────────────────────────────────
WRITTEN_PUBSPEC=$(grep -E "^version:" "$PUBSPEC" | awk '{print $2}' | tr -d '[:space:]')
WRITTEN_CONFIG=$(grep -E "static const String appVersion" "$APP_CONFIG" | sed -E "s/.*'([^']+)'.*/\1/")

if [ "$WRITTEN_PUBSPEC" != "$NEW_VERSION_FULL" ]; then
  log_err "写入 $PUBSPEC 失败,实际: $WRITTEN_PUBSPEC"
  exit 1
fi
if [ "$WRITTEN_CONFIG" != "$NEW_SEMVER" ]; then
  log_err "写入 $APP_CONFIG 失败,实际: $WRITTEN_CONFIG"
  exit 1
fi

echo
log_ok "$PUBSPEC         → version: $WRITTEN_PUBSPEC"
log_ok "$APP_CONFIG → appVersion = '$WRITTEN_CONFIG'"

# ── 下一步提示 ───────────────────────────────────────────────
echo
printf "${CYAN}${BOLD}下一步${NC}\n"
printf "  1. 检查改动:        ${BLUE}git diff $PUBSPEC $APP_CONFIG${NC}\n"
printf "  2. 构建 Release:    ${BLUE}./scripts/build.sh${NC}\n"
printf "  3. 提交 + 打 tag:\n"
printf "     ${BLUE}git add $PUBSPEC $APP_CONFIG${NC}\n"
printf "     ${BLUE}git commit -m 'chore(release): bump version to $NEW_SEMVER'${NC}\n"
printf "     ${BLUE}git tag v$NEW_SEMVER${NC}\n"
