// Added by https://github.com/ortsevlised

import { config } from '../support/config';
import { ICustomWorld } from '../support/custom-world';
import { ensureFile, pathExists } from 'fs-extra';
import pixelmatch from 'pixelmatch';
import { PNG } from 'pngjs';
import * as fs from 'fs';
import { writeFileSync } from 'fs';
import { join } from 'path';

/**
 * Compares a screenshot to a base image,
 * if the base image doesn't exist it fails the test but creates a new base image based on
 * the screenshot passed so it can be used on the next run.
 * @param screenshot a playwright screenshot
 * @param customWorld needed to create the base image path
 * @param threshold the difference threshold
 */

interface ImagePathOptions {
  skipOs: boolean;
}

export function getImagePath(
  customWorld: ICustomWorld,
  name: string,
  options?: ImagePathOptions,
): string {
  return join(
    'screenshots',
    customWorld.feature?.uri || '',
    options?.skipOs ? '' : process.platform,
    config.browser,
    `${name}.png`,
  );
}
export async function compareToBaseImage(
  customWorld: ICustomWorld,
  name: string,
  screenshot: Buffer,
  threshold?: { threshold: number },
) {
  let baseImage;
  const baseImagePath = getImagePath(customWorld, name);
  const baseImgExist = await pathExists(baseImagePath);
  if (baseImgExist) {
    baseImage = PNG.sync.read(fs.readFileSync(baseImagePath));
  } else {
    await ensureFile(baseImagePath);
    writeFileSync(baseImagePath, screenshot);
    customWorld.log(
      `The base Image doesn't exist, a screenshot was taken to ${baseImagePath} so it can be used for next run`,
    );
    return;
  }
  const img1 = PNG.sync.read(screenshot);
  const difference = getDifference(img1, baseImage, threshold);
  if (difference) {
    await customWorld.attach(difference, 'image/png;base64');
    throw new Error(`Screenshot does not match : ${baseImagePath}`);
  }
}

/**
 * Returns the difference between 2 images
 * @param img1
 * @param img2
 * @param threshold the difference threshold
 */
export function getDifference(
  img1: PNG,
  img2: PNG,
  threshold = config.IMG_THRESHOLD,
): Buffer | undefined {
  const { width, height } = img2;
  const diff = new PNG({ width, height });
  const difference = pixelmatch(img1.data, img2.data, diff.data, width, height, threshold);
  if (difference > 0) {
    return PNG.sync.write(diff);
  }
  return undefined;
}