#!/usr/bin/env node
/* eslint-disable import/no-dynamic-require */
/* eslint-disable global-require */

// Called by the `version` npm script.
// This is run _after_ lerna updates the version numbers,
// but _before_ it commits, so we have time to update the
// version numbers throughout the repo and add it to the
// release commit.
// After updating version numbers, this runs a full
// IS_RELEASE_BUILD=1 build, so that the version numbers
// are properly embedded in the JS bundles.
// NOTE this _amends_ the previous commit, which should
// already be a "Release" commit generated by bin/release.

const lastCommitMessage = require('last-commit-message')
const { spawn } = require('child_process')
const { promisify } = require('util')
const once = require('events.once')
const globby = require('globby')
const fs = require('fs')

const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)

async function replaceInFile (filename, replacements) {
  let content = await readFile(filename, 'utf8')
  for (const [rx, replacement] of replacements) {
    content = content.replace(rx, replacement)
  }

  await writeFile(filename, content, 'utf8')
}

async function updateVersions (files, packageName) {
  const { version } = require(`../packages/${packageName}/package.json`)

  // uppy → uppy
  // @uppy/robodog → uppy/robodog
  const urlPart = packageName === 'uppy' ? packageName : packageName.slice(1)

  const replacements = new Map([
    [RegExp(`${urlPart}/v\\d+\\.\\d+\\.\\d+\\/`, 'g'), `${urlPart}/v${version}/`],
    // maybe more later
  ])

  console.log('replacing', replacements, 'in', files.length, 'files')

  for (const f of files) {
    // eslint-disable-next-line no-await-in-loop
    await replaceInFile(f, replacements)
  }
}

async function gitAdd (files) {
  const git = spawn('git', ['add', ...files], { stdio: 'inherit' })
  const [exitCode] = await once(git, 'exit')
  if (exitCode !== 0) {
    throw new Error(`git add failed with ${exitCode}`)
  }
}

// Run the build as a release build (that inlines version numbers etc.)
async function npmRunBuild () {
  const npmRun = spawn('npm', ['run', 'build'], {
    stdio: 'inherit',
    env: {
      ...process.env,
      FRESH: true, // force rebuild everything
      IS_RELEASE_BUILD: true,
    },
  })
  const [exitCode] = await once(npmRun, 'exit')
  if (exitCode !== 0) {
    throw new Error(`npm run build failed with ${exitCode}`)
  }
}

async function main () {
  if (process.env.ENDTOEND === '1') {
    console.log('Publishing for e2e tests, skipping version number sync.')
    process.exit(0)
  }

  const message = await lastCommitMessage()
  if (message.trim() !== 'Release') {
    console.error(`Last commit is not a release commit, but '${message}'`)
    process.exit(1)
  }

  const files = await globby([
    'README.md',
    'examples/**/*.html',
    'packages/*/README.md',
    'packages/@uppy/*/README.md',
    'website/src/docs/**',
    'website/src/examples/**',
    'website/themes/uppy/layout/**',
    '!**/node_modules/**',
  ])

  await updateVersions(files, 'uppy')
  await updateVersions(files, '@uppy/robodog')
  await updateVersions(files, '@uppy/locales')

  // gitignored files were updated for the npm package, but can't be updated
  // on git.
  const isIgnored = await globby.gitignore()
  await gitAdd(files.filter((filename) => !isIgnored(filename)))

  await npmRunBuild()
}

main().catch((err) => {
  console.error(err.stack)
  process.exit(1)
})

@@ -2824,24 +2824,48 @@
 README.md',%0A
+    'BUNDLE-README.md',%0A
     'example

update versions is bundle-readme too