const PreviewUtils = (() => {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');

  const getPixel = (data, width, x, y) => {
    const i = (y * width + x) * 4;
    return data.subarray(i, i + 4);
  };

  const findEdges = (width, height, threshold = 5) => {
    const { data } = ctx.getImageData(0, 0, width, height);
    const edges = {
      left: { isRow: false, step: 1, start: 0, end: width - 1 },
      top: { isRow: true, step: 1, start: 0, end: height - 1 },
      right: { isRow: false, step: -1, start: width - 1, end: 0 },
      bottom: { isRow: true, step: -1, start: height - 1, end: 0 },
    };

    const [left, top, right, bottom] = ['left', 'top', 'right', 'bottom'].map((side) => {
      const { isRow, start, step, end } = edges[side];
      const len = isRow ? width : height;

      for (let pos = start; step > 0 ? pos < end : pos > end; pos += step) {
        for (let i = 0; i < len; i++) {
          const p1 = isRow ? getPixel(data, width, i, pos) : getPixel(data, width, pos, i);
          const p2 = isRow ? getPixel(data, width, i, pos + step) : getPixel(data, width, pos + step, i);
          if (Math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2 + (p1[2] - p2[2]) ** 2) > threshold) {
            return pos;
          }
        }
      }

      return end;
    });

    return [left, top, right - left + 1, bottom - top + 1];
  };

  return {
    cropImage(image, maxWidth, maxHeight, cropThreshold = 5) {
      const width = image.naturalWidth;
      const height = image.naturalHeight;

      canvas.width = width;
      canvas.height = height;
      ctx.clearRect(0, 0, width, height);
      ctx.drawImage(image, 0, 0, width, height);

      let [sx, sy, sw, sh] = findEdges(width, height, cropThreshold);
      if (sw <= 0 || sh <= 0) {
        sx = 0;
        sy = 0;
        sw = width;
        sh = height;
      }

      const dw = Math.min(sw, maxWidth);
      const dh = Math.min(sh, maxHeight);

      canvas.width = dw;
      canvas.height = dh;
      ctx.clearRect(0, 0, dw, dh);
      ctx.drawImage(image, sx, sy, dw, dh, 0, 0, dw, dh);

      [sx, sy, sw, sh] = findEdges(dw, dh, cropThreshold);
      if (sw > 0 && sh > 0) {
        const imageData = ctx.getImageData(sx, sy, sw, sh);
        canvas.width = sw;
        canvas.height = sh;
        ctx.putImageData(imageData, 0, 0);
      }

      return canvas.toDataURL('image/png').split(',')[1];
    },
  };
})();
