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

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." >/dev/null 2>&1 && pwd)"
cd "$REPO_ROOT"

usage() {
  echo "usage: scripts/release patch|minor|major"
}

BUMP="${1:-}"
case "$BUMP" in
  patch|minor|major)
    ;;
  -h|--help|"")
    usage
    exit 0
    ;;
  *)
    usage
    exit 1
    ;;
esac

if [ "$(git branch --show-current)" != "main" ]; then
  echo "Releases must be run from the main branch."
  exit 1
fi

if ! git remote get-url origin >/dev/null 2>&1; then
  echo "Missing git remote 'origin'."
  exit 1
fi

if [ -n "$(git status --porcelain)" ]; then
  echo "Working tree is dirty. Commit or stash changes before releasing."
  exit 1
fi

git fetch origin main --tags --quiet

LOCAL_COMMIT="$(git rev-parse HEAD)"
REMOTE_COMMIT="$(git rev-parse origin/main)"
BASE_COMMIT="$(git merge-base HEAD origin/main)"
if [ "$LOCAL_COMMIT" != "$REMOTE_COMMIT" ]; then
  if [ "$LOCAL_COMMIT" = "$BASE_COMMIT" ]; then
    echo "Local main is behind origin/main. Pull latest changes before releasing."
  elif [ "$REMOTE_COMMIT" = "$BASE_COMMIT" ]; then
    echo "Local main has unpushed commits. Push main before releasing."
  else
    echo "Local main and origin/main have diverged. Reconcile them before releasing."
  fi
  exit 1
fi

VERSION="$(tr -d '[:space:]' < VERSION)"
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
  echo "Invalid SemVer in VERSION: $VERSION"
  exit 1
fi

IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
case "$BUMP" in
  patch)
    PATCH=$((PATCH + 1))
    ;;
  minor)
    MINOR=$((MINOR + 1))
    PATCH=0
    ;;
  major)
    MAJOR=$((MAJOR + 1))
    MINOR=0
    PATCH=0
    ;;
esac

NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}"
NEW_TAG="v${NEW_VERSION}"

if [ "$BUMP" = "major" ]; then
  EXPECTED="major ${NEW_VERSION}"
  echo "This will release ${NEW_VERSION}."
  echo "Type '${EXPECTED}' to continue:"
  read -r RESPONSE
  if [ "$RESPONSE" != "$EXPECTED" ]; then
    echo "Major release cancelled."
    exit 1
  fi
fi

if git rev-parse --verify --quiet "refs/tags/$NEW_TAG" >/dev/null; then
  echo "Tag already exists locally: $NEW_TAG"
  exit 1
fi

node scripts/set-version.mjs "$NEW_VERSION"
make pre-release

git add VERSION README.md pkg/version/version.go packaging/npm
git commit -m "Release $NEW_VERSION"
git tag -a "$NEW_TAG" -m "Release $NEW_VERSION"

if ! git push --atomic origin main "$NEW_TAG"; then
  echo "Push failed. The release commit and tag remain local."
  exit 1
fi

echo "Released $NEW_VERSION ($NEW_TAG)."
