import { readFile, writeFile } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const usesendDir = path.join(__dirname, '..', 'node_modules', 'usesend-js');

const ensureReplacement = (content, searchValue, replaceValue, filePath) => {
  if (replaceValue !== '' && content.includes(replaceValue)) {
    return content;
  }

  if (!content.includes(searchValue)) {
    if (replaceValue === '') {
      return content;
    }
    throw new Error(`Expected snippet not found in ${filePath}`);
  }

  return content.replace(searchValue, replaceValue);
};

const patchFile = async (relativePath, replacements) => {
  const filePath = path.join(usesendDir, relativePath);
  let content = await readFile(filePath, 'utf8');

  for (const [searchValue, replaceValue] of replacements) {
    content = ensureReplacement(
      content,
      searchValue,
      replaceValue,
      relativePath,
    );
  }

  await writeFile(filePath, content);
};

const patchUseSend = async () => {
  const packageJsonPath = path.join(usesendDir, 'package.json');
  const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'));

  if (packageJson.version !== '1.6.3') {
    console.log(
      `Skipping UseSend patch for version ${packageJson.version ?? 'unknown'}.`,
    );
    return;
  }

  const runtimeHelper = `function getNodeCrypto() {
  const builtinModuleLoader = globalThis.process?.getBuiltinModule;
  if (typeof builtinModuleLoader === "function") {
    const nodeCrypto = builtinModuleLoader("node:crypto");
    if (nodeCrypto) {
      return nodeCrypto;
    }
  }
  throw new WebhookVerificationError(
    "UNSUPPORTED_RUNTIME",
    "Webhook verification requires a Node.js runtime with node:crypto support"
  );
}
`;

  await patchFile('dist/index.mjs', [
    ['import { createHmac, timingSafeEqual } from "crypto";\n', ''],
    [
      'function computeSignature(secret, timestamp, body) {\n',
      `${runtimeHelper}function computeSignature(secret, timestamp, body) {\n`,
    ],
    [
      '  const hmac = createHmac("sha256", secret);\n',
      '  const { createHmac } = getNodeCrypto();\n  const hmac = createHmac("sha256", secret);\n',
    ],
    [
      'function safeEqual(a, b) {\n',
      'function safeEqual(a, b) {\n  const { timingSafeEqual } = getNodeCrypto();\n',
    ],
  ]);

  await patchFile('dist/index.js', [
    ['var import_crypto = require("crypto");\n', ''],
    [
      'function computeSignature(secret, timestamp, body) {\n',
      `${runtimeHelper}function computeSignature(secret, timestamp, body) {\n`,
    ],
    [
      '  const hmac = (0, import_crypto.createHmac)("sha256", secret);\n',
      '  const { createHmac } = getNodeCrypto();\n  const hmac = createHmac("sha256", secret);\n',
    ],
    [
      'function safeEqual(a, b) {\n',
      'function safeEqual(a, b) {\n  const { timingSafeEqual } = getNodeCrypto();\n',
    ],
    [
      '  return (0, import_crypto.timingSafeEqual)(aBuf, bBuf);\n',
      '  return timingSafeEqual(aBuf, bBuf);\n',
    ],
  ]);

  console.log('Patched usesend-js 1.6.3 for Convex-compatible bundling.');
};

await patchUseSend();
