# SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
#
# SPDX-License-Identifier: CC0-1.0

[tools]
bun = "1.3"

[tasks.fmt]
description = "Format all files with Biome"
run = "bun run fmt"

[tasks.lint]
description = "Lint all files with Biome"
run = "bun run lint"

[tasks.typecheck]
description = "Type-check all packages with TypeScript"
run = "bun run typecheck"

[tasks.check]
description = "Format, lint, and type-check"
depends = ["fmt", "lint", "typecheck"]

[tasks."release:bump"]
description = "Bump one or more package versions"
usage = '''
arg "<version>" help="SemVer increment or exact version"
arg "<packages>" help="Package selectors" var=#true var_min=1
flag "--preid <preid>" help="Prerelease identifier for pre* increments"
'''
shell = "bash -c"
run = '''
set -euo pipefail

version=${usage_version:?}
preid=${usage_preid:-}
eval "packages=(${usage_packages:?})"

exact_version_re='^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$'
is_exact_version=false
if [[ "$version" =~ $exact_version_re ]]; then
	is_exact_version=true
fi

case "$version" in
	patch|minor|major|prepatch|preminor|premajor|prerelease) ;;
	*)
		if [[ "$is_exact_version" != true ]]; then
			echo "Error: unsupported version '$version'" >&2
			echo "Use patch, minor, major, prepatch, preminor, premajor, prerelease, or an exact SemVer." >&2
			exit 1
		fi
		;;
esac

if [[ -n "$preid" ]]; then
	case "$version" in
		prepatch|preminor|premajor|prerelease) ;;
		*)
			echo "Error: --preid only applies to prepatch, preminor, premajor, or prerelease" >&2
			exit 1
			;;
	esac
fi

resolved_dirs=$(bash scripts/resolve-release-packages.bash "${packages[@]}")
mapfile -t dirs <<< "$resolved_dirs"

if [[ "$is_exact_version" == true && -n "${dirs[1]:-}" ]]; then
	echo "Error: exact versions may only be applied to one package at a time" >&2
	exit 1
fi

for dir in "${dirs[@]}"; do
	args=(pm version "$version" --no-git-tag-version)
	if [[ -n "$preid" ]]; then
		args+=(--preid "$preid")
	fi
	echo "Bumping $dir"
	(
		cd "$dir"
		bun "${args[@]}"
	)
done
'''

[tasks."release:pack"]
description = "Check and dry-run npm package packing"
usage = '''
arg "<packages>" help="Package selectors" var=#true var_min=1
'''
shell = "bash -c"
run = '''
set -euo pipefail

eval "packages=(${usage_packages:?})"
resolved_dirs=$(bash scripts/resolve-release-packages.bash "${packages[@]}")
mapfile -t dirs <<< "$resolved_dirs"

mise run check

for dir in "${dirs[@]}"; do
	echo "Packing $dir (dry run)"
	bunx npm pack --dry-run "./$dir"
done
'''

[tasks."release:publish"]
description = "Check, dry-run, and publish npm packages"
usage = '''
arg "<packages>" help="Package selectors" var=#true var_min=1
flag "--tag <tag>" help="npm dist-tag" default="latest"
flag "--otp <otp>" help="One-time password for npm two-factor auth"
'''
shell = "bash -c"
run = '''
set -euo pipefail

package_version() {
	bun -e 'const fs = require("node:fs"); const path = require("node:path"); const pkg = JSON.parse(fs.readFileSync(path.join(process.argv[1], "package.json"), "utf8")); console.log(pkg.version);' "$1"
}

eval "packages=(${usage_packages:?})"
tag=${usage_tag:?}
otp=${usage_otp:-}
resolved_dirs=$(bash scripts/resolve-release-packages.bash "${packages[@]}")
mapfile -t dirs <<< "$resolved_dirs"

if [[ -n "$otp" && -n "${dirs[1]:-}" ]]; then
	echo "Error: --otp may only be used with one package at a time" >&2
	echo "Use an npm automation token for multi-package publishing, or publish each package separately with a fresh OTP." >&2
	exit 1
fi

for dir in "${dirs[@]}"; do
	version=$(package_version "$dir")
	if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+- && "$tag" == latest ]]; then
		echo "Error: refusing to publish prerelease $dir@$version with tag latest" >&2
		echo "Use --tag beta or another prerelease dist-tag." >&2
		exit 1
	fi
done

mise run check

publish_args=(--access public --tag "$tag")
if [[ -n "$otp" ]]; then
	publish_args+=(--otp "$otp")
fi

for dir in "${dirs[@]}"; do
	echo "Publishing $dir (dry run)"
	bunx npm publish --dry-run "${publish_args[@]}" "./$dir"
done

for dir in "${dirs[@]}"; do
	echo "Publishing $dir"
	bunx npm publish "${publish_args[@]}" "./$dir"
done
'''
