#!/bin/bash
#
# repoman :: bump the project version across all source files.
#
# repoman's version lives in three unlinked places — keep them in lockstep:
#   reef.toml         version = "X.Y.Z"
#   src/cli.reef      version_string() -> "repoman X.Y.Z"
#   README.md         Current version: **vX.Y.Z**.
#
# Usage: ./scripts/bump-version.sh [--major|--minor|--patch|X.Y.Z]
#                                  [--dry-run] [--commit] [--tag]
#   default bump is --patch; --tag implies --commit.
#
# After --tag, `hg push` sends the bump + tag and fires the tag pipeline
# (build + test + package + release) on Isurus.

set -euo pipefail

AUTHOR="Chris Tusa <chris.tusa@leafscale.com>"

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo="$(dirname "$script_dir")"
cd "$repo"

current_version() {
    grep '^version' reef.toml | head -n1 | sed 's/.*"\([^"]*\)".*/\1/'
}

usage() {
    cat <<EOF
Usage: $0 [OPTIONS] [VERSION]

Bump repoman's version across reef.toml, src/cli.reef, and README.md.

Options:
  --major      Bump major (X.0.0)
  --minor      Bump minor (x.Y.0)
  --patch      Bump patch (x.y.Z)   [default]
  --dry-run    Show changes without writing
  --commit     hg commit the version files after bumping
  --tag        hg tag vX.Y.Z after committing (implies --commit)
  -h, --help   This help

Current version: $(current_version)
EOF
}

DRY_RUN=false
DO_COMMIT=false
DO_TAG=false
BUMP_TYPE=""
NEW_VERSION=""

while [[ $# -gt 0 ]]; do
    case "$1" in
        --major) BUMP_TYPE="major" ;;
        --minor) BUMP_TYPE="minor" ;;
        --patch) BUMP_TYPE="patch" ;;
        --dry-run) DRY_RUN=true ;;
        --commit) DO_COMMIT=true ;;
        --tag) DO_TAG=true; DO_COMMIT=true ;;
        -h|--help) usage; exit 0 ;;
        -*) echo "Error: unknown option $1" >&2; usage; exit 1 ;;
        *)
            if [[ "$1" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
                NEW_VERSION="$1"
            else
                echo "Error: invalid version '$1' (want X.Y.Z)" >&2
                exit 1
            fi
            ;;
    esac
    shift
done

CUR="$(current_version)"
if [[ -z "$CUR" ]]; then
    echo "Error: could not read current version from reef.toml" >&2
    exit 1
fi

if [[ -z "$NEW_VERSION" ]]; then
    IFS='.' read -r MAJOR MINOR PATCH <<< "$CUR"
    case "${BUMP_TYPE:-patch}" in
        major) NEW_VERSION="$((MAJOR + 1)).0.0" ;;
        minor) NEW_VERSION="${MAJOR}.$((MINOR + 1)).0" ;;
        patch) NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" ;;
    esac
fi

echo "Current version: $CUR"
echo "New version:     $NEW_VERSION"

if [[ "$CUR" == "$NEW_VERSION" ]]; then
    echo "Version unchanged, nothing to do."
    exit 0
fi

# Literal find-and-replace with a presence guard, so a missing/renamed anchor is a
# hard error rather than a silent no-op.
replace_in() {
    local file="$1" old="$2" new="$3"
    if ! grep -qF -- "$old" "$file"; then
        echo "Error: expected \"$old\" in $file — not found (already bumped or anchor moved?)" >&2
        exit 1
    fi
    if $DRY_RUN; then
        echo "  would update $file: \"$old\" -> \"$new\""
        return
    fi
    local esc_old esc_new
    esc_old=$(printf '%s' "$old" | sed 's/[.[\*^$/]/\\&/g')
    esc_new=$(printf '%s' "$new" | sed 's/[&/]/\\&/g')
    sed -i "s/$esc_old/$esc_new/" "$file"
    echo "  updated $file"
}

replace_in reef.toml    "version = \"$CUR\""       "version = \"$NEW_VERSION\""
replace_in src/cli.reef "return \"repoman $CUR\""  "return \"repoman $NEW_VERSION\""
replace_in README.md    "**v$CUR**"                "**v$NEW_VERSION**"

if $DRY_RUN; then
    echo "Dry run complete; no files modified."
    exit 0
fi

# Rebuild so the embedded version_string is validated to compile and matches.
# Build quietly; surface the log only on failure. Note: repoman prints --version
# to stderr (console.printErr), so the check must read 2>&1.
echo "Rebuilding to validate the bump..."
build_log="$(mktemp)"
if ! make all >"$build_log" 2>&1; then
    echo "Error: build failed:" >&2
    cat "$build_log" >&2
    rm -f "$build_log"
    exit 1
fi
rm -f "$build_log"
got="$(./build/repoman --version 2>&1)"
echo "  build/repoman --version -> $got"
if [[ "$got" != "repoman $NEW_VERSION" ]]; then
    echo "Error: built version '$got' != expected 'repoman $NEW_VERSION'" >&2
    exit 1
fi

if $DO_COMMIT; then
    echo "Committing version bump..."
    hg commit -u "$AUTHOR" -m "Bump version to $NEW_VERSION" \
        reef.toml src/cli.reef README.md
fi

if $DO_TAG; then
    echo "Tagging v$NEW_VERSION..."
    hg tag -u "$AUTHOR" -m "Release v$NEW_VERSION" "v$NEW_VERSION"
    echo
    echo "Next: hg push   # sends the bump + tag; the tag fires the release pipeline"
fi

echo "Done: $NEW_VERSION"
