import { readFile } from 'node:fs/promises';
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const execFileAsync = promisify(execFile);

/**
 * replaceOnCopyPlugin is an esbuild plugin. it loads files as utf-8 text
 * and replaces certain placeholders with their values computed on plugin setup.
 * the fileFilter is a regexp matching names or extensions of the files to process,
 * passed to esbuild's onLoad as is.
 *
 * the following placeholders are replaced:
 *
 * #[PKG_VERSION]# -> npm package version
 * #[GIT_COMMIT]#  -> short git commit at current HEAD
 */
export function replaceOnCopyPlugin(fileFilter) {
  return {
    name: 'replace-on-copy',
    setup(build) {
      const appVersion = sanitizedStr(process.env.npm_package_version);
      const gitHeadCommit = gitRevParse('HEAD');

      build.onLoad({filter: fileFilter}, async (args) => {
        const gitCommitHash = await gitHeadCommit;
        let text = await readFile(args.path, 'utf8');
        text = text.replaceAll('#[PKG_VERSION]#', appVersion);
        text = text.replaceAll('#[GIT_COMMIT]#', gitCommitHash);
        return {
          contents: text,
          loader: 'copy',
        }
      });
    }
  }
}

async function gitRevParse(rev) {
  rev = sanitizedStr(rev);
  const { stdout } = await execFileAsync('git', ['rev-parse', '--short', rev]);
  return sanitizedStr(stdout.trim());
}

function sanitizedStr(s) {
  const notOk = /[^0-9a-z \.@-]/ig;
  return s.replaceAll(notOk, '-');
}