#!/usr/bin/env bash
# Node.js, npm-to-pnpm migration, and mandatory release-age policy.

cleanup_node() {
  local target project root
  for project in "${NODE_PROJECTS[@]}"; do
    target="$(dirname "$project")"
    for target in "$target/.next" "$target/node_modules"; do
      [[ -e "$target" ]] || continue
      if ((DRY_RUN)); then info "[Dry run] Delete: $target"; else rm -rf -- "$target"; ok "Deleted: $target"; CHANGED=1; fi
    done
  done
  for root in "${NODE_ROOTS[@]}"; do
    for target in "$root/.next" "$root/node_modules"; do
      [[ -e "$target" ]] || continue
      if ((DRY_RUN)); then info "[Dry run] Delete: $target"; else rm -rf -- "$target"; ok "Deleted: $target"; CHANGED=1; fi
    done
  done
}

ensure_pnpm() {
  has pnpm && return 0
  if has corepack; then run 'Enable pnpm through Corepack' "$ROOT" corepack enable; has pnpm && return 0; fi
  has npm || { err 'pnpm, Corepack, and npm are all unavailable.'; return 1; }
  local tool="$ROOT/.maintenance/tools/pnpm"
  run 'Install pnpm locally' "$ROOT" npm --prefix "$tool" install --no-audit --no-fund --save=false pnpm@latest
  export PATH="$tool/node_modules/.bin:$PATH"
  has pnpm || { err 'pnpm could not be provisioned.'; return 1; }
}

migrate_manifest_to_pnpm() {
  local manifest="$1" version="$2"
  if ((DRY_RUN)); then info "[Dry run] Set packageManager in $manifest to pnpm@$version"; return; fi
  node - "$manifest" "$version" <<'NODE'
const fs=require('fs');
const [file,version]=process.argv.slice(2);
const p=JSON.parse(fs.readFileSync(file,'utf8'));
p.packageManager=`pnpm@${version}`;
fs.writeFileSync(file,JSON.stringify(p,null,2)+'\n');
NODE
  CHANGED=1
}

ensure_workspace_policy() {
  local root="$1" file="$root/pnpm-workspace.yaml" packages
  if ((DRY_RUN)); then info "[Dry run] Set minimumReleaseAge: 10080 in $file"; return; fi
  packages="$(node - "$root/package.json" <<'NODE' 2>/dev/null || true
const fs=require('fs');const f=process.argv[2];if(!fs.existsSync(f))process.exit();
const p=JSON.parse(fs.readFileSync(f));let w=p.workspaces||[];if(!Array.isArray(w))w=w.packages||[];
for(const x of w)console.log(x);
NODE
)"
  if [[ ! -f "$file" ]]; then
    { printf 'packages:\n'; if [[ -n "$packages" ]]; then while IFS= read -r p; do printf '  - "%s"\n' "$p"; done <<<"$packages"; else printf '  - "apps/*"\n  - "packages/*"\n'; fi; } >"$file"
  fi
  if grep -q '^minimumReleaseAge:' "$file"; then sed -i.bak -E 's/^minimumReleaseAge:.*/minimumReleaseAge: 10080/' "$file"; rm -f "$file.bak"; else printf '\nminimumReleaseAge: 10080\n' >>"$file"; fi
  if [[ "$HARDEN" != off ]] && ! grep -q '^blockExoticSubdeps:' "$file"; then printf 'blockExoticSubdeps: true\n' >>"$file"; fi
  if [[ "$HARDEN" == strict ]] && ! grep -q '^trustPolicy:' "$file"; then printf 'trustPolicy: no-downgrade\n' >>"$file"; fi
  ok "pnpm policy configured: $file"
}

ncu_target() { case "$MODE" in patch) printf patch;; minor) printf minor;; semver-safe) printf semver;; *) printf latest;; esac; }

update_node() {
  ((${#NODE_PROJECTS[@]})) || return 0
  ensure_pnpm || return 1
  create_backup
  cleanup_node
  local version manifest dir root target args=()
  version="$(pnpm --version)"
  for root in "${NODE_ROOTS[@]}"; do
    if [[ -f "$root/package-lock.json" || -f "$root/npm-shrinkwrap.json" ]]; then run 'Import npm lockfile' "$root" pnpm import || true; fi
  done
  for manifest in "${NODE_PROJECTS[@]}"; do
    dir="$(dirname "$manifest")"
    if [[ -f "$dir/package-lock.json" || -f "$dir/npm-shrinkwrap.json" ]]; then run 'Import application lockfile' "$dir" pnpm import || true; fi
    migrate_manifest_to_pnpm "$manifest" "$version"
    if [[ "$MODE" == interactive ]]; then args=(--interactive); else target="$(ncu_target)"; args=(-u --target "$target"); fi
    run "Update dependencies: ${manifest#$ROOT/}" "$dir" pnpm dlx npm-check-updates@latest "${args[@]}" || true
    if ((!DRY_RUN)); then rm -f "$dir/package-lock.json" "$dir/npm-shrinkwrap.json"; fi
  done
  for root in "${NODE_ROOTS[@]}"; do
    [[ -f "$root/package.json" ]] && migrate_manifest_to_pnpm "$root/package.json" "$version"
    ensure_workspace_policy "$root"
    if ((!DRY_RUN)); then rm -f "$root/package-lock.json" "$root/npm-shrinkwrap.json"; fi
    run 'pnpm install --fix-lockfile' "$root" pnpm install --fix-lockfile || true
    run 'pnpm dedupe' "$root" pnpm dedupe || true
    [[ "$AUDIT_MODE" == off ]] || run 'pnpm audit' "$root" pnpm audit --audit-level moderate || true
    if [[ "$AUDIT_MODE" == fix ]]; then run 'pnpm audit --fix' "$root" pnpm audit --fix || true; fi
    if pnpm audit --help 2>/dev/null | grep -q signatures; then run 'pnpm audit signatures' "$root" pnpm audit signatures || true; fi
  done
}
