#!/usr/bin/env node

/**
 * @file
 * Updates all @wordpress/* packages in package.json to a given WP version's dist-tag.
 *
 * Usage:
 *   node scripts/update-wp-packages.js 6.9
 *   node scripts/update-wp-packages.js 6.9 --dry-run
 */

const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');

const ROOT = path.resolve(__dirname, '..');
const PKG_PATH = path.join(ROOT, 'package.json');
const PATCHES_DIR = path.join(ROOT, 'patches');

const args = process.argv.slice(2);
const dryRun = args.includes('--dry-run');
const wpVersion = args.find((a) => !a.startsWith('--'));

if (!wpVersion) {
  console.error('Usage: node scripts/update-wp-packages.js <wp-version> [--dry-run]');
  console.error('Example: node scripts/update-wp-packages.js 6.9');
  process.exit(1);
}

const distTag = `wp-${wpVersion}`;
console.log(`Resolving @wordpress/* package versions for dist-tag: ${distTag}`);
if (dryRun) {
  console.log('(dry run — no files will be modified)\n');
} else {
  console.log('');
}

const pkg = JSON.parse(fs.readFileSync(PKG_PATH, 'utf8'));

const wpDeps = Object.keys(pkg.dependencies).filter((k) =>
  k.startsWith('@wordpress/'),
);
const wpDevDeps = Object.keys(pkg.devDependencies).filter((k) =>
  k.startsWith('@wordpress/'),
);
const allWpPackages = [...wpDeps, ...wpDevDeps];

const updated = [];
const failed = [];
const unchanged = [];

for (const name of allWpPackages) {
  const currentVersion =
    pkg.dependencies[name] || pkg.devDependencies[name];

  let newVersion;
  try {
    newVersion = execSync(`npm info "${name}@${distTag}" version 2>/dev/null`, {
      encoding: 'utf8',
    }).trim();
  } catch {
    // dist-tag might not exist for this package
  }

  if (!newVersion) {
    failed.push({ name, currentVersion, reason: `no ${distTag} dist-tag` });
    continue;
  }

  if (newVersion === currentVersion) {
    unchanged.push({ name, version: currentVersion });
    continue;
  }

  updated.push({ name, from: currentVersion, to: newVersion });

  if (!dryRun) {
    if (pkg.dependencies[name]) {
      pkg.dependencies[name] = newVersion;
    } else {
      pkg.devDependencies[name] = newVersion;
    }
  }
}

// Print results.
if (updated.length > 0) {
  console.log(`Updated (${updated.length}):`);
  for (const { name, from, to } of updated) {
    console.log(`  ${name}: ${from} -> ${to}`);
  }
  console.log('');
}

if (unchanged.length > 0) {
  console.log(`Unchanged (${unchanged.length}):`);
  for (const { name, version } of unchanged) {
    console.log(`  ${name}: ${version}`);
  }
  console.log('');
}

if (failed.length > 0) {
  console.log(`Failed (${failed.length}):`);
  for (const { name, currentVersion, reason } of failed) {
    console.log(`  ${name}: ${currentVersion} (${reason})`);
  }
  console.log('');
}

// Handle patch file rename for block-editor.
const blockEditorUpdate = updated.find(
  (u) => u.name === '@wordpress/block-editor',
);
if (blockEditorUpdate) {
  const oldPatch = path.join(
    PATCHES_DIR,
    `@wordpress+block-editor+${blockEditorUpdate.from}.patch`,
  );
  const newPatch = path.join(
    PATCHES_DIR,
    `@wordpress+block-editor+${blockEditorUpdate.to}.patch`,
  );

  if (fs.existsSync(oldPatch)) {
    if (!dryRun) {
      fs.renameSync(oldPatch, newPatch);
    }
    console.log(`Patch file renamed:`);
    console.log(`  ${path.basename(oldPatch)} -> ${path.basename(newPatch)}`);
    console.log(
      '  NOTE: After npm install, verify the patch still applies cleanly.',
    );
    console.log(
      '  If it fails, manually fix the iframe file and run: npx patch-package @wordpress/block-editor\n',
    );
  }
}

if (!dryRun && updated.length > 0) {
  fs.writeFileSync(PKG_PATH, JSON.stringify(pkg, null, 2) + '\n');
  console.log('package.json updated.');
  console.log('');
  console.log('Next steps:');
  console.log('  1. npm install');
  console.log('  2. npm run build:vendor');
  console.log('  3. Review gutenberg.libraries.yml diff');
  console.log('  4. Test in browser');
} else if (dryRun && updated.length > 0) {
  console.log('Run without --dry-run to apply changes.');
} else {
  console.log('Nothing to update.');
}
