#!/usr/bin/env bash
# Publish @mosaicstack/* packages to npmjs.org as @mosaicstack/*
#
# This script patches each package.json to:
#   1. Rename @mosaicstack/X → @mosaicstack/X
#   2. Replace workspace:^ deps with resolved versions using @mosaicstack/* names
#   3. Run npm publish
#   4. Restore original package.json
#
# Usage:
#   scripts/publish-npmjs.sh [--dry-run] [--filter <package-name>]
#
# Requirements:
#   - NPM_TOKEN env var set (npmjs.org auth token)
#   - jq installed
#   - Run from monorepo root after `pnpm build`

set -euo pipefail

DRY_RUN=false
FILTER=""

while [[ $# -gt 0 ]]; do
  case "$1" in
    --dry-run) DRY_RUN=true; shift ;;
    --filter) FILTER="$2"; shift 2 ;;
    *) echo "Unknown option: $1"; exit 1 ;;
  esac
done

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

# Collect all publishable package directories (non-private, has publishConfig)
PACKAGE_DIRS=()
for pkg_json in "$REPO_ROOT"/packages/*/package.json "$REPO_ROOT"/plugins/*/package.json "$REPO_ROOT"/apps/gateway/package.json; do
  [[ -f "$pkg_json" ]] || continue
  is_private=$(jq -r '.private // false' "$pkg_json")
  [[ "$is_private" == "true" ]] && continue
  PACKAGE_DIRS+=("$(dirname "$pkg_json")")
done

echo "Found ${#PACKAGE_DIRS[@]} publishable packages"

# Build a version map: @mosaicstack/X → version
declare -A VERSION_MAP
for dir in "${PACKAGE_DIRS[@]}"; do
  name=$(jq -r '.name' "$dir/package.json")
  version=$(jq -r '.version' "$dir/package.json")
  VERSION_MAP["$name"]="$version"
done

# Configure npmjs auth
if [[ -z "${NPM_TOKEN:-}" ]] && [[ "$DRY_RUN" == "false" ]]; then
  echo "ERROR: NPM_TOKEN is required for publishing. Set it or use --dry-run."
  exit 1
fi

publish_package() {
  local dir="$1"
  local orig_json="$dir/package.json"
  local backup="$dir/package.json.bak"

  local name
  name=$(jq -r '.name' "$orig_json")

  # Apply filter if set
  if [[ -n "$FILTER" ]] && [[ "$name" != "$FILTER" ]]; then
    return 0
  fi

  local new_name="${name/@mosaic\//@mosaicstack/}"
  echo ""
  echo "━━━ Publishing $name → $new_name ━━━"

  # Backup original
  cp "$orig_json" "$backup"

  # Patch: rename package
  local patched
  patched=$(jq --arg new_name "$new_name" '.name = $new_name' "$orig_json")

  # Patch: publishConfig to npmjs
  patched=$(echo "$patched" | jq '.publishConfig = {"registry": "https://registry.npmjs.org/", "access": "public"}')

  # Patch: replace workspace:^ dependencies with @mosaicstack/* and resolved versions
  for dep_field in dependencies devDependencies peerDependencies; do
    if echo "$patched" | jq -e ".$dep_field" > /dev/null 2>&1; then
      local deps
      deps=$(echo "$patched" | jq -r ".$dep_field // {} | keys[]")
      for dep in $deps; do
        local dep_version
        dep_version=$(echo "$patched" | jq -r ".$dep_field[\"$dep\"]")

        # Only transform @mosaicstack/* workspace deps
        if [[ "$dep" == @mosaicstack/* ]] && [[ "$dep_version" == workspace:* ]]; then
          local new_dep="${dep/@mosaic\//@mosaicstack/}"
          local resolved="${VERSION_MAP[$dep]:-}"

          if [[ -z "$resolved" ]]; then
            echo "  WARNING: No version found for $dep — using '*'"
            resolved="*"
          else
            # workspace:^ means ^version, workspace:* means *
            if [[ "$dep_version" == "workspace:^" ]]; then
              resolved="^$resolved"
            fi
          fi

          # Rename the dep key and set the resolved version
          patched=$(echo "$patched" | jq \
            --arg field "$dep_field" \
            --arg old_dep "$dep" \
            --arg new_dep "$new_dep" \
            --arg version "$resolved" \
            '.[$field] |= (del(.[$old_dep]) | .[$new_dep] = $version)')
        fi
      done
    fi
  done

  # Write patched package.json
  echo "$patched" > "$orig_json"

  echo "  Patched: $new_name"

  # Publish
  if [[ "$DRY_RUN" == "true" ]]; then
    echo "  [DRY RUN] npm publish --dry-run"
    (cd "$dir" && npm publish --dry-run 2>&1) || true
  else
    echo "  Publishing to npmjs..."
    (cd "$dir" && npm publish 2>&1) || echo "  WARNING: Publish failed (may already exist at this version)"
  fi

  # Restore original
  mv "$backup" "$orig_json"
  echo "  Restored original package.json"
}

# Set up npmrc for npmjs
if [[ -n "${NPM_TOKEN:-}" ]]; then
  echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
fi

# Publish in dependency order: packages first, then plugins, then apps
echo ""
echo "=== Publishing packages ==="
for dir in "$REPO_ROOT"/packages/*/; do
  [[ -f "$dir/package.json" ]] || continue
  publish_package "$dir"
done

echo ""
echo "=== Publishing plugins ==="
for dir in "$REPO_ROOT"/plugins/*/; do
  [[ -f "$dir/package.json" ]] || continue
  publish_package "$dir"
done

echo ""
echo "=== Publishing apps ==="
publish_package "$REPO_ROOT/apps/gateway"

echo ""
echo "Done."
