const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

const RETRYABLE_RENAME_CODES = new Set(['EPERM', 'EBUSY', 'EACCES', 'ENOTEMPTY', 'EEXIST']);

function defaultSleepSync(delayMs) {
  const waitBuffer = new Int32Array(new SharedArrayBuffer(4));
  Atomics.wait(waitBuffer, 0, 0, delayMs);
}

function renameWithRetrySync(sourcePath, targetPath, options = {}) {
  const attempts = Math.max(1, Math.min(20, Number(options.attempts || 8)));
  const delayMs = Math.max(1, Math.min(250, Number(options.delayMs || 25)));
  const renameSync = options.renameSync || fs.renameSync;
  const sleepSync = options.sleepSync || defaultSleepSync;
  let lastError;
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
    try {
      renameSync(sourcePath, targetPath);
      return { attempts: attempt };
    } catch (error) {
      lastError = error;
      if (!RETRYABLE_RENAME_CODES.has(error?.code) || attempt === attempts) throw error;
      sleepSync(delayMs * attempt);
    }
  }
  throw lastError;
}

function writeUtf8AtomicSync(targetPath, content, options = {}) {
  fs.mkdirSync(path.dirname(targetPath), { recursive: true });
  const temporaryPath = `${targetPath}.${process.pid}.${crypto.randomUUID()}.tmp`;
  try {
    fs.writeFileSync(temporaryPath, String(content), { encoding: 'utf8', flag: 'wx' });
    const result = renameWithRetrySync(temporaryPath, targetPath, options);
    return { ...result, targetPath };
  } finally {
    try { if (fs.existsSync(temporaryPath)) fs.unlinkSync(temporaryPath); } catch (_) {}
  }
}

module.exports = {
  RETRYABLE_RENAME_CODES,
  renameWithRetrySync,
  writeUtf8AtomicSync
};
