import { spawn } from 'child_process';
import { readFile, writeFile } from 'fs';
import tmp from 'tmp';

export const convertBufferToOpus = (buffer: Buffer, maxLengthSeconds: number = Infinity): Promise<Buffer> => {
  const args = ['-vn', '-c:a', 'libopus', '-b:a', '160K', '-application', 'audio', '-f', 'ogg'];
  if (maxLengthSeconds !== Infinity) {
    args.push('-t', maxLengthSeconds.toString());
  }
  return ffmpegBuffer(buffer, args);
};

export const convertWebmToMP4 = (buffer: Buffer): Promise<Buffer> => {
  return ffmpegBuffer(buffer, ['-f', 'mp4']);
};

export const ffmpegBuffer = async (buffer: Buffer, options: Array<string>): Promise<Buffer> => {
  let cleanupCallback = () => {};
  try {
    return await new Promise<Buffer>((resolve, reject) => {
      tmp.dir({ unsafeCleanup: true }, async (err, path, innerCleanupCallback) => {
        if (err) {
          return reject(err);
        }
        cleanupCallback = innerCleanupCallback;

        const inputFilePath = `${path}/input`;
        const outputFilePath = `${path}/output`;
        writeFile(inputFilePath, buffer, (err) => {
          if (err) {
            return reject(err);
          }
          const process = spawn('ffmpeg', ['-i', inputFilePath, ...options, outputFilePath]);
          process.on('error', (err) => reject(err));
          process.on('close', (code) => {
            if (code !== 0) {
              return reject(`ffmpeg process exited with code ${code}`);
            }

            readFile(outputFilePath, (err, outputBuffer) => {
              if (err) {
                return reject(err);
              }

              resolve(outputBuffer);
            });
          });
        });
      });
    });
  } finally {
    cleanupCallback();
  }
};
