import cuid from 'cuid'
import fs from 'fs'
import path from 'path'
import concat from 'concat-stream'
import rimraf from 'rimraf'
import thenify from 'thenify'

const mkdirAsync = thenify(fs.mkdir)
const rimrafAsync = thenify(rimraf)

const TMP_DIR = path.join(__dirname, '..', 'tmp') + path.sep

const fileExtensions = {
  'image/jpeg': '.jpg',
  'video/mp4': '.mp4',
}
const videoCodecs = {
  mp4: {
    type: 'ffmpeg',
    ext: '.mp4',
    vcodec: '-vcodec libx264',
    mime: 'video/mp4',
  },
}

async function writeTempFiles(folder, frames, imgExtension) {
  await mkdirAsync(folder)
  await Promise.all(
    frames.map(
      (frame, i) =>
        new Promise((resolve, reject) => {
          fs.createWriteStream(folder + path.sep + i + imgExtension)
            .on('error', reject)
            .end(frames[i], resolve)
        }),
    ),
  )
}

async function convert(ffmpegRunner, folder, imgExtension) {
  const promises = Object.keys(videoCodecs).map(async codec => {
    const info = videoCodecs[codec]
    const data = await doFfmpeg(ffmpegRunner, folder, imgExtension, info.vcodec, info.ext)
    return {
      codec,
      result: data,
    }
  })

  const results = (await Promise.all(promises)).reduce((acc, { codec, result }) => {
    acc[codec] = result
    return acc
  }, {})

  return results
}

export default async function convertFrame(frames, format, ffmpegRunner) {
  if (!fileExtensions[format]) {
    throw new Error('Invalid input format')
  }

  const id = cuid()
  const folder = TMP_DIR + id
  const imgExtension = fileExtensions[format]

  try {
    await writeTempFiles(folder, frames, imgExtension)
    return await convert(ffmpegRunner, folder, imgExtension)
  } finally {
    try {
      await rimrafAsync(folder)
    } catch (err) {
      console.error('Error deleting folder: ' + folder + '\n' + err)
    }
  }
}

async function doFfmpeg(ffmpegRunner, folder, imgExtension, vcodecArgs, vidExtension) {
  const sep = path.sep
  // 11fps is pretty weird, but this more faithfully reproduces the duration/speed of the original
  // app than 10fps does.
  const command =
    `-r 11 -i "${folder}${sep}%d${imgExtension}" ${vcodecArgs} ` +
    `-crf 21 -preset fast -r 11 -movflags +faststart -tune fastdecode ` +
    `-an "${folder}${sep}vid${vidExtension}"`

  await ffmpegRunner(command, { timeout: 3000 })

  return new Promise((resolve, reject) => {
    const readStream = fs.createReadStream(`${folder}${sep}vid${vidExtension}`)
    readStream.on('error', reject)

    readStream.pipe(concat(resolve)).on('error', reject)
  })
}

@@ -461,16 +461,33 @@
  libx264
+ -pix_fmt yuv420p
 ',%0A    m

Add color format back. Firefox seems to generate jpegs that convert to mp4s that it cannot then decode. Cool lol.