#!/usr/bin/env bash
# Usage:
#   scripts/release/changelog.sh suggest            print the suggested next version
#   scripts/release/changelog.sh generate [X.Y.Z]   write CHANGELOG.md; X.Y.Z is the release being cut
set -euo pipefail

CLIFF="pnpm dlx git-cliff@2.14.2"
BASE_TAG="assemble-base"
cd "$(git rev-parse --show-toplevel)"

command -v jq >/dev/null || { echo "jq is required" >&2; exit 1; }
git rev-parse -q --verify "refs/tags/${BASE_TAG}" >/dev/null ||
  { echo "Tag ${BASE_TAG} not found; fetch tags first (git fetch --tags)" >&2; exit 1; }

work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT

# Commits reachable from the Assemble base or from any upstream sync merge are upstream work.
# shellcheck disable=SC2046
git rev-list --no-merges HEAD --not "${BASE_TAG}" \
  $(git log --merges --format='%P %s' HEAD | grep "upstream/main" | awk '{print $2}') \
  >"$work/ours.txt"

$CLIFF -c cliff.toml -x "${BASE_TAG}..HEAD" 2>/dev/null >"$work/context.json"

jq --rawfile ids "$work/ours.txt" '
  ($ids | split("\n") | map(select(length > 0))) as $ok
  | map(.commits |= map(select(.id as $i | $ok | index($i))))
  | map(select(.commits | length > 0))
' "$work/context.json" >"$work/ours.json"

last_tag=$(git describe --tags --match 'v[0-9]*' --abbrev=0 2>/dev/null || true)
last_version=${last_tag#v}

suggest() {
  local level
  [ -n "$last_tag" ] || { echo "No vX.Y.Z release tag found; tag the first release before suggesting a bump" >&2; exit 1; }
  level=$(jq -r --arg major "${last_version%%.*}" '
    [.[] | select(.version == null) | .commits[]] as $c
    | if ($c | length) == 0 then "none"
      elif ($c | any(.breaking == true)) then (if $major == "0" then "minor" else "major" end)
      elif ($c | any(.group == "Features")) then "minor"
      else "patch" end
  ' "$work/ours.json")
  [ "$level" = none ] && { echo "No unreleased changes since ${last_tag}" >&2; exit 1; }
  IFS=. read -r maj min pat <<<"$last_version"
  case "$level" in
    major) echo "$((maj + 1)).0.0" ;;
    minor) echo "${maj}.$((min + 1)).0" ;;
    patch) echo "${maj}.${min}.$((pat + 1))" ;;
  esac
}

generate() {
  local next=${1:-}
  if [ -n "$next" ]; then
    jq --arg v "v${next}" 'map(if .version == null then .version = $v | .timestamp = (now | floor) else . end)' \
      "$work/ours.json" >"$work/final.json"
  else
    cp "$work/ours.json" "$work/final.json"
  fi
  $CLIFF -c cliff.toml --from-context "$work/final.json" 2>/dev/null >CHANGELOG.md
}

case "${1:-}" in
  suggest) suggest ;;
  generate) generate "${2:-}" ;;
  *) echo "usage: $0 suggest | generate [X.Y.Z]" >&2; exit 2 ;;
esac
