#!/usr/bin/env node
/**
 * sync-versions.js — Sync version constants across all source files
 *
 * Reads the canonical values from src/data/versions.js and updates
 * every hardcoded occurrence in JS, JSON, MD, and CJS files.
 *
 * Usage:
 *   node scripts/sync-versions.js          # dry-run (preview changes)
 *   node scripts/sync-versions.js --apply  # apply changes
 *
 * Safe to run multiple times — idempotent.
 */
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.resolve(__dirname, '..');

// Import canonical versions
const {
  VL_VERSION,
  THEME_VERSION,
  THEME_VERSION_FULL,
  STYLESPACE_VERSION,
  THEME_TAG,
  THEME_PROFILE,
  WORKFLOW_VERSION,
  PARSEVL_URL,
} = await import('../src/data/versions.js');

const dryRun = !process.argv.includes('--apply');

// ── Replacement rules ──────────────────────────────────────────────
// Each rule: [pattern (regex), replacement (string)]
// Patterns are designed to match the OLD format regardless of old version number.
const rules = [
  // VL_VERSION header in code/templates
  [/VL_VERSION:[\d.]+/g, `VL_VERSION:${VL_VERSION}`],

  // VL_SYNTAX_VERSION in md
  [/VL_SYNTAX_VERSION:[\d.]+/g, `VL_SYNTAX_VERSION:${VL_VERSION}`],

  // vlVersion: 'x.x' (JS object literal)
  [/vlVersion:\s*'[\d.]+'/g, `vlVersion: '${VL_VERSION}'`],

  // "vlVersion": "x.x" (JSON)
  [/"vlVersion":\s*"[\d.]+"/g, `"vlVersion": "${VL_VERSION}"`],

  // "version": "x.x" in vl-syntax-meta.json only (too generic for global)
  // handled via file-specific rule below

  // VL x.x syntax references in prompts/comments
  [/VL [\d.]+ syntax/g, `VL ${VL_VERSION} syntax`],
  [/VL [\d.]+ Syntax/g, `VL ${VL_VERSION} Syntax`],
  [/VL \(Visual Logic\) [\d.]+/g, `VL (Visual Logic) ${VL_VERSION}`],
  [/VL \(Visual Language\) v[\d.]+/g, `VL (Visual Language) v${VL_VERSION}`],

  // VL Language Complete Reference (vX.X)
  [/VL Language Complete Reference \(v[\d.]+\)/g, `VL Language Complete Reference (v${VL_VERSION})`],

  // "Follow VL x.x syntax strictly"
  [/Follow VL [\d.]+ syntax/g, `Follow VL ${VL_VERSION} syntax`],
  [/following VL [\d.]+ syntax/g, `following VL ${VL_VERSION} syntax`],

  // "VL x.x" standalone in comments (e.g. "VL 3.5 injects", "VL 3.5 PREFERRED")
  // Only match "VL X.X" followed by common suffixes to avoid false positives
  [/VL [\d.]+( injects| PREFERRED| primary| data-vl-id| live| IDs| runtime)/g,
    `VL ${VL_VERSION}$1`],

  // Theme-Enterprise-X.X tag
  [/Theme-Enterprise-[\d.]+/g, `Theme-Enterprise-${THEME_VERSION}`],

  // Theme version in theme content: version:"X.X.X"
  [/version:"[\d.]+"\n/g, `version:"${THEME_VERSION_FULL}"\n`],

  // styleSpaceVersion:"X.X"
  [/styleSpaceVersion:"[\d.]+"/g, `styleSpaceVersion:"${STYLESPACE_VERSION}"`],

  // Enterprise Theme X.X in comments
  [/Enterprise Theme [\d.]+/g, `Enterprise Theme ${THEME_VERSION}`],

  // Enterprise theme vX.X in doc tables
  [/Enterprise theme v[\d.]+/g, `Enterprise theme v${THEME_VERSION}`],

  // THEME_X.X.vth in doc tables
  [/THEME_[\d.]+\.vth/g, `THEME_${THEME_VERSION}.vth`],

  // StyleSpace X.X references
  [/StyleSpace [\d.]+/g, `StyleSpace ${STYLESPACE_VERSION}`],

  // VL x.x Syntax Rules (in workflow JSON docs)
  [/"VL [\d.]+ Syntax Rules"/g, `"VL ${VL_VERSION} Syntax Rules"`],

  // "for VL x.x syntax compliance"
  [/for VL [\d.]+ syntax compliance/g, `for VL ${VL_VERSION} syntax compliance`],

  // version: 'x.x' in meta.json context (type: 'vl-project')
  [/version: '[\d.]+',\n(\s+type: 'vl-project')/g, `version: '${VL_VERSION}',\n$1`],

  // ── VL Workflow spec version (3.15 → 3.16, etc.) ──
  // Matches workflow-builder.js, autotest-pipeline.js: version: '3.xx'
  [/version:\s*'3\.\d{2}'/g, `version: '${WORKFLOW_VERSION}'`],
  // Matches orchestrator.js template strings: version "3.xx"
  [/version "3\.\d{2}"/g, `version "${WORKFLOW_VERSION}"`],
  // Matches workflow-run.js: spec: 'v3.xx'
  [/spec:\s*'v3\.\d{2}'/g, `spec: 'v${WORKFLOW_VERSION}'`],
  // Matches AGENTS.md / docs: VL Workflow 3.xx
  [/VL Workflow [\d.]+/g, `VL Workflow ${WORKFLOW_VERSION}`],
  // Matches short-form vX.xx spec references in comments/strings
  [/\(VL Workflow spec v[\d.]+\)/g, `(VL Workflow spec v${WORKFLOW_VERSION})`],

  // ── VL version in short form (app banners, package.json description) ──
  [/\bVL v[\d.]+/g, `VL v${VL_VERSION}`],
];

// ── File-specific rules ────────────────────────────────────────────
const fileRules = {
  'src/data/vl-syntax-meta.json': [
    [/"version":\s*"[\d.]+"/g, `"version": "${VL_VERSION}"`],
  ],
};

// ── Scan targets ───────────────────────────────────────────────────
const SCAN_DIRS = ['src', 'public', '.vl-code/workflows'];
const ROOT_FILES = ['AGENTS.md', 'MODULE-SPEC.md', 'package.json', 'CLAUDE.md'];
const EXTENSIONS = new Set(['.js', '.cjs', '.mjs', '.json', '.md', '.html']);
const SKIP = new Set(['node_modules', 'dist', '.git', 'versions.js']);

function walk(dir) {
  const results = [];
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
    if (SKIP.has(entry.name)) continue;
    const full = path.join(dir, entry.name);
    if (entry.isDirectory()) {
      results.push(...walk(full));
    } else if (EXTENSIONS.has(path.extname(entry.name))) {
      results.push(full);
    }
  }
  return results;
}

// ── Main ───────────────────────────────────────────────────────────
console.log(`\n📐 VL-Code Version Sync`);
console.log(`   VL_VERSION:        ${VL_VERSION}`);
console.log(`   THEME_VERSION:     ${THEME_VERSION} (${THEME_VERSION_FULL})`);
console.log(`   STYLESPACE:        ${STYLESPACE_VERSION}`);
console.log(`   THEME_TAG:         ${THEME_TAG}`);
console.log(`   Mode:              ${dryRun ? 'DRY RUN (use --apply to write)' : 'APPLYING'}\n`);

let totalFiles = 0;
let changedFiles = 0;
let totalReplacements = 0;

const files = [
  ...SCAN_DIRS.flatMap(d => walk(path.join(ROOT, d))),
  ...ROOT_FILES.map(f => path.join(ROOT, f)).filter(f => fs.existsSync(f)),
];

for (const filePath of files) {
  const relPath = path.relative(ROOT, filePath);
  const original = fs.readFileSync(filePath, 'utf-8');
  let content = original;
  let fileChanges = 0;

  // Apply global rules
  for (const [pattern, replacement] of rules) {
    const before = content;
    content = content.replace(pattern, replacement);
    if (content !== before) {
      const count = (before.match(pattern) || []).length;
      fileChanges += count;
    }
  }

  // Apply file-specific rules
  const extras = fileRules[relPath];
  if (extras) {
    for (const [pattern, replacement] of extras) {
      const before = content;
      content = content.replace(pattern, replacement);
      if (content !== before) {
        const count = (before.match(pattern) || []).length;
        fileChanges += count;
      }
    }
  }

  totalFiles++;
  if (content !== original) {
    changedFiles++;
    totalReplacements += fileChanges;
    console.log(`  ✏️  ${relPath} (${fileChanges} replacements)`);
    if (!dryRun) {
      fs.writeFileSync(filePath, content, 'utf-8');
    }
  }
}

console.log(`\n${dryRun ? '🔍 Preview' : '✅ Done'}: ${changedFiles}/${totalFiles} files, ${totalReplacements} replacements\n`);
if (dryRun && changedFiles > 0) {
  console.log('Run with --apply to write changes:\n  node scripts/sync-versions.js --apply\n');
}
