#!/bin/bash
#
# Publishes the CLI as "canary-dolphin-swimsuit" to npm without
# modifying the working tree. Works from a disposable temp copy.
#
# Usage:
#   ./scripts/publish-canary.sh          # publish current version
#   ./scripts/publish-canary.sh patch    # bump patch version first
#   ./scripts/publish-canary.sh minor    # bump minor version first
#   ./scripts/publish-canary.sh 0.3.1    # set explicit version
#

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
CLI_DIR="$(dirname "$SCRIPT_DIR")"
REPO_ROOT="$(cd "$CLI_DIR/../.." && pwd)"
TMP_DIR=$(mktemp -d)
# Mirror the monorepo layout inside the temp dir. A bare copy of
# packages/consortium-cli cannot build: yarn hoists shared devDependencies
# (shx, minimist, pkgroll, typescript) and every `@consortium/*` workspace
# package into the REPO ROOT node_modules, so a flat copy dies at
# `Cannot find module 'minimist'` before pkgroll ever runs. Recreating
# <tmp>/packages/consortium-cli and symlinking <tmp>/node_modules at the real
# root lets Node's upward resolution find both, without copying 1GB+ or
# mutating the working tree.
WORK_DIR="$TMP_DIR/packages/consortium-cli"

# Capture build identity from the REAL checkout. The build below runs inside
# the temp copy, which is not a git repo, so scripts/build-stamp.cjs would
# stamp 'unknown' and the published canary could not name the source it came
# from -- the exact problem the stamp exists to solve.
export CONSORTIUM_BUILD_SHA="$(git -C "$REPO_ROOT" rev-parse --short HEAD 2>/dev/null || echo unknown)"
export CONSORTIUM_BUILD_BRANCH="$(git -C "$REPO_ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)"
export CONSORTIUM_BUILD_DIRTY="$([ -n "$(git -C "$REPO_ROOT" status --porcelain 2>/dev/null)" ] && echo 1 || echo 0)"

cleanup() {
    # Unlink the borrowed root node_modules BEFORE the recursive delete. rm -rf
    # does not follow symlinks, but the blast radius if that ever changed is the
    # repo's entire dependency tree, so this is not left to a subtlety.
    rm -f "$TMP_DIR/node_modules"
    rm -rf "$TMP_DIR"
}
trap cleanup EXIT

echo "==> Copying CLI to temp directory..."
mkdir -p "$WORK_DIR"
cp -R "$CLI_DIR/." "$WORK_DIR/"
ln -s "$REPO_ROOT/node_modules" "$TMP_DIR/node_modules"
cd "$WORK_DIR"

echo "==> Rewriting package for canary-dolphin-swimsuit..."
# Rewrite name + bin map with node, not sed. The previous sed keyed on a literal
# `"consortium-cli": "./bin/consortium.mjs"` that no longer exists in
# package.json, so the bin rename silently no-opped -- sed exits 0 whether or not
# it matched -- and published a canary exposing `consortium`, which collides with
# the real package and breaks the documented
# `--build-arg CONSORTIUM_CLI_BIN=consortium-dev`. JSON-aware editing cannot
# drift with formatting, and the assertion below fails the publish loudly
# instead of shipping a broken bin map.
node -e '
const fs = require("fs");
const p = JSON.parse(fs.readFileSync("package.json", "utf8"));
p.name = "canary-dolphin-swimsuit";
const RENAME = {
  "consortium": "consortium-dev",
  "consortium-local": "consortium-dev-local",
  "consortium-mcp": "consortium-dev-mcp",
};
const bin = {};
for (const [k, v] of Object.entries(p.bin || {})) bin[RENAME[k] || k] = v;
const stray = Object.keys(bin).filter(k => !k.startsWith("consortium-dev"));
if (stray.length) {
  console.error("FATAL: bin entries not renamed for the canary channel: " + stray.join(", "));
  console.error("       Add them to RENAME in scripts/publish-canary.sh.");
  process.exit(1);
}
p.bin = bin;
fs.writeFileSync("package.json", JSON.stringify(p, null, 2) + "\n");
console.log("    name -> " + p.name);
console.log("    bin  -> " + Object.keys(bin).join(", "));
'

# Point all URLs at staging
find src scripts -type f \( -name '*.ts' -o -name '*.cjs' -o -name '*.mjs' \) -exec \
    sed -i '' -e "s|https://api.consortium.dev|https://api-staging.consortium.dev|g" \
              -e "s|https://app.consortium.dev|https://staging.consortium.dev|g" {} +

# Set version — default to timestamp-based prerelease
if [ "${1:-}" != "" ]; then
    case "$1" in
        patch|minor|major)
            npm version "$1" --no-git-tag-version
            ;;
        *)
            npm version "$1" --no-git-tag-version
            ;;
    esac
else
    CURRENT=$(node -p "require('./package.json').version")
    npm version "${CURRENT}-canary.$(date +%Y%m%d%H%M%S)" --no-git-tag-version
fi

echo "==> Building..."
npm run build

echo "==> Publishing to npm..."
npm publish

VERSION=$(node -p "require('./package.json').version")
echo ""
echo "==> Published canary-dolphin-swimsuit@$VERSION"
echo "    Source:  $CONSORTIUM_BUILD_SHA on $CONSORTIUM_BUILD_BRANCH (dirty=$CONSORTIUM_BUILD_DIRTY)"
echo "    Install: npx canary-dolphin-swimsuit@latest"
echo "    Server:  https://api-staging.consortium.dev"
