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

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

usage() { echo "Usage: release [--dry-run] [--pre <suffix>] [patch|minor|major|local]"; exit 1; }
die() { echo "error: $1" >&2; exit 1; }

update_changelog() {
  local ver="$1" tag="$2"
  local changelog="$ROOT/CHANGELOG.md"
  [[ -f "$changelog" ]] || return 0

  local date prev_tag
  date=$(date +%Y-%m-%d)
  prev_tag=$(sed -n 's|^\[Unreleased\]: .*/compare/\(.*\)\.\.\.HEAD|\1|p' "$changelog")

  awk -v ver="$ver" -v date="$date" -v tag="$tag" -v prev="$prev_tag" '
    /^## \[Unreleased\]/ {
      print
      print ""
      print "## [" ver "] - " date
      next
    }
    /^\[Unreleased\]:/ {
      match($0, /https:\/\/[^/]*\/[^/]*\/[^/]*/)
      base = substr($0, RSTART, RLENGTH)
      print "[Unreleased]: " base "/compare/" tag "...HEAD"
      print "[" ver "]: " base "/compare/" prev "..." tag
      next
    }
    { print }
  ' "$changelog" > "$changelog.tmp" && mv "$changelog.tmp" "$changelog"
}

bump_version() {
  local ver="$1" part="$2"
  IFS='.' read -r major minor patch <<< "$ver"
  case "$part" in
    major) echo "$((major + 1)).0.0" ;;
    minor) echo "$major.$((minor + 1)).0" ;;
    patch) echo "$major.$minor.$((patch + 1))" ;;
  esac
}

dry_run=false
pre_suffix=""

while [[ $# -gt 0 ]]; do
  case "$1" in
    --dry-run) dry_run=true; shift ;;
    --pre) [[ $# -ge 2 ]] || usage; pre_suffix="$2"; shift 2 ;;
    -*) usage ;;
    *) break ;;
  esac
done

part="${1:-}"

pyproject="$ROOT/pyproject.toml"
old_ver=$(grep '^version' "$pyproject" | head -1 | sed 's/.*"\(.*\)".*/\1/')

# Strip any existing pre-release suffix to get base version
base_ver="${old_ver%%[a-z]*}"

# --- local: build + install dev wheel for testing ---
if [[ "$part" == "local" ]]; then
  tag="gems-v${base_ver}"
  if ! git rev-parse "$tag" &>/dev/null; then
    tag="gems-v${old_ver}"
  fi
  distance=$(git rev-list "$tag..HEAD" --count 2>/dev/null) || die "tag $tag not found"
  dev_ver="${base_ver}.dev${distance}"

  if $dry_run; then
    echo "$old_ver -> $dev_ver (local install)"
    exit 0
  fi

  [[ -f "$pyproject.orig" ]] && mv -f "$pyproject.orig" "$pyproject"
  cp "$pyproject" "$pyproject.orig"
  trap 'mv -f "$pyproject.orig" "$pyproject"' EXIT
  sed -i.bak "s/version = \"$old_ver\"/version = \"$dev_ver\"/" "$pyproject" && rm -f "$pyproject.bak"

  out_dir="/tmp/gems-test"
  rm -rf "$out_dir"
  uv build --out-dir "$out_dir" || die "build failed"

  whl=$(ls "$out_dir"/buvis_gems-*.whl | head -1)
  [[ -f "$whl" ]] || die "no wheel found in $out_dir"

  mise_root=$(mise where pipx:buvis-gems 2>/dev/null) || die "mise buvis-gems not found"
  mise_python="$mise_root/buvis-gems/bin/python"
  [[ -x "$mise_python" ]] || die "python not found at $mise_python"
  uv pip install --force-reinstall "${whl}[all]" --python "$mise_python" || die "mise install failed"
  mise reshim

  uv tool install --force "${whl}[all]" || die "uv tool install failed"

  echo "Installed buvis-gems $dev_ver"
  exit 0
fi

# --- normal release flow ---
if [[ -n "$part" ]]; then
  [[ "$part" =~ ^(patch|minor|major)$ ]] || usage
  new_base=$(bump_version "$base_ver" "$part")
elif [[ -n "$pre_suffix" ]]; then
  new_base="$base_ver"
elif [[ "$old_ver" != "$base_ver" ]]; then
  # Current version is pre-release; release as stable
  new_base="$base_ver"
else
  usage
fi

new_ver="${new_base}${pre_suffix}"
tag="gems-v${new_ver}"

if $dry_run; then
  echo "$old_ver -> $new_ver (tag: $tag)"
  exit 0
fi

git pull --ff-only || die "pull failed — resolve manually"
[[ -z "$(git status --porcelain)" ]] || die "working tree is dirty"
git tag -l "$tag" | grep -q . && die "tag $tag already exists"

sed -i.bak "s/version = \"$old_ver\"/version = \"$new_ver\"/" "$pyproject" && rm -f "$pyproject.bak"

[[ -z "$pre_suffix" ]] && update_changelog "$new_ver" "$tag"

uv lock || die "uv lock failed"

git add "$pyproject" uv.lock
[[ -f "$ROOT/CHANGELOG.md" ]] && git add "$ROOT/CHANGELOG.md"
git commit -m "build(gems): bump to v$new_ver"
git tag "$tag"
git push origin HEAD --tags

echo "Released gems v$new_ver"
