import {execFile} from 'child_process';
import {copyFile, unlink} from 'fs';

import pngquant from 'pngquant-bin';
import sharp from 'sharp';

import headers from './headers.js';

const fit = sharp.fit.inside;
const pngquantArgs = ['--skip-if-larger', '--speed', '1', '-f', '-o'];
const withoutEnlargement = true;

const optimize = (source, dest) => new Promise((res, rej) => {
  execFile(pngquant, pngquantArgs.concat(dest, source), err => {
    if (err) {
      copyFile(source, dest, err => {
        if (err) rej(err);
        else res(dest);
      });
    }
    else
      res(dest);
  });
});

/**
 * Create a file after optimizing via `pngquant`.
 * @param {string} source The source PNG file to optimize.
 * @param {string} dest The optimized destination file.
 * @param {Options} [options] Options to deal with extra computation.
 * @return {Promise<string>} A promise that resolves with the destination file.
 */
export default (source, dest, options = {}) =>
  new Promise((res, rej) => {
    const {maxWidth: width, maxHeight: height, createFiles} = options;
    const done = () => res(dest);
    const walkThrough = () => {
      if (createFiles) writeHeaders(dest).then(done, rej);
      else done();
    };
    const writeHeaders = dest => headers(source, dest, options.headers);
    if (width || height) {
      sharp(source)
        .resize({width, height, fit, withoutEnlargement})
        .toFile(`${dest}.resized.png`)
        .then(
          () => optimize(`${dest}.resized.png`, dest).then(
            () => {
              unlink(`${dest}.resized.png`, err => {
                /* istanbul ignore if */
                if (err) rej(err);
                else walkThrough();
              });
            },
            rej
          ),
          rej
        )
      ;
    }
    else
      optimize(source, dest).then(walkThrough, rej);
  });