"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = _default;
var _pngjs = require("pngjs");
var _pixelmatch = _interopRequireDefault(require("pixelmatch"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function normalizeImageSize(image, width, height) {
  const normalizedImage = Buffer.alloc(4 * width * height);
  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      const i = (y * width + x) * 4;
      if (x < image.width && y < image.height) {
        const j = (y * image.width + x) * 4;
        normalizedImage[i + 0] = image.data[j + 0];
        normalizedImage[i + 1] = image.data[j + 1];
        normalizedImage[i + 2] = image.data[j + 2];
        normalizedImage[i + 3] = image.data[j + 3];
      } else {
        normalizedImage[i + 0] = 0;
        normalizedImage[i + 1] = 0;
        normalizedImage[i + 2] = 0;
        normalizedImage[i + 3] = 0;
      }
    }
  }
  return normalizedImage;
}
function hasDiffPixels(diff) {
  for (let i = 0; i < diff.length; i += 4) {
    if (diff[i + 0] == 255 && diff[i + 1] == 0 && diff[i + 2] == 0 && diff[i + 3] == 255) return true;
  }
  return false;
}
function compareImages(expect, actual, diffOptions) {
  const expectImage = _pngjs.PNG.sync.read(expect);
  const actualImage = _pngjs.PNG.sync.read(actual);
  const width = Math.max(actualImage.width, expectImage.width);
  const height = Math.max(actualImage.height, expectImage.height);
  const diffImage = new _pngjs.PNG({
    width,
    height
  });
  let actualImageData = actualImage.data;
  if (actualImage.width < width || actualImage.height < height) {
    actualImageData = normalizeImageSize(actualImage, width, height);
  }
  let expectImageData = expectImage.data;
  if (expectImage.width < width || expectImage.height < height) {
    expectImageData = normalizeImageSize(expectImage, width, height);
  }
  (0, _pixelmatch.default)(expectImageData, actualImageData, diffImage.data, width, height, diffOptions);
  return {
    isEqual: !hasDiffPixels(diffImage.data),
    diff: _pngjs.PNG.sync.write(diffImage)
  };
}
function _default(getExpected, diffOptions) {
  return function chaiImage({
    Assertion
  }, utils) {
    async function assertImage(actual, imageName) {
      let onCompare = () => Promise.resolve();
      let expected = await getExpected(imageName);
      if (!(expected instanceof Buffer) && expected != null) ({
        expected,
        onCompare
      } = expected);
      if (expected == null) {
        await onCompare(actual);
        return imageName ? `Expected image '${imageName}' does not exists` : 'Expected image does not exists';
      }
      if (actual.equals(expected)) return await onCompare(actual);
      const {
        isEqual,
        diff
      } = compareImages(expected, actual, diffOptions);
      if (isEqual) return await onCompare(actual);
      await onCompare(actual, expected, diff);
      return imageName ? `Expected image '${imageName}' to match` : 'Expected image to match';
    }
    utils.addMethod(Assertion.prototype, 'matchImage', async function matchImage(imageName) {
      const actual = utils.flag(this, 'object');
      const errorMessage = await assertImage(typeof actual == 'string' ? Buffer.from(actual, 'base64') : actual, imageName);
      if (errorMessage) {
        throw createImageError(imageName ? {
          [imageName]: errorMessage
        } : errorMessage);
      }
    });
    utils.addMethod(Assertion.prototype, 'matchImages', async function matchImages() {
      const errors = {};
      await Promise.all(Object.entries(utils.flag(this, 'object')).map(async ([imageName, imageOrBase64]) => {
        let errorMessage;
        try {
          errorMessage = await assertImage(typeof imageOrBase64 == 'string' ? Buffer.from(imageOrBase64, 'base64') : imageOrBase64, imageName);
        } catch (error) {
          errorMessage = error.stack;
        }
        if (errorMessage) {
          errors[imageName] = errorMessage;
        }
      }));
      if (Object.keys(errors).length > 0) {
        throw createImageError(errors);
      }
    });
  };
}
function createImageError(imageErrors) {
  const error = new Error('Expected image to match');
  error.images = imageErrors;
  return error;
}