import { base64ToBuffer } from "../lib/utils";

/**
 * A hook for the image output.
 *
 * Automatically converts image URLs from image/x-pixel to image/png.
 */
const ImageOutput = {
  mounted() {
    this.updateSrc();
  },

  updated() {
    this.updateSrc();
  },

  updateSrc() {
    const dataUrl = this.el.src;
    const prefix = "data:image/x-pixel;base64,";

    const base64Data = dataUrl.slice(prefix.length);

    if (dataUrl.startsWith(prefix)) {
      const buffer = base64ToBuffer(base64Data);

      const view = new DataView(buffer);
      const height = view.getUint32(0, false);
      const width = view.getUint32(4, false);
      const channels = view.getUint8(8);
      const pixelBuffer = buffer.slice(9);

      const imageData = imageDataFromPixelBuffer(
        pixelBuffer,
        width,
        height,
        channels,
      );

      const canvas = document.createElement("canvas");
      canvas.height = height;
      canvas.width = width;
      canvas.getContext("2d").putImageData(imageData, 0, 0);
      const pngDataUrl = canvas.toDataURL("image/png");

      this.el.src = pngDataUrl;
    }
  },
};

function imageDataFromPixelBuffer(buffer, width, height, channels) {
  const pixelCount = width * height;
  const bytes = new Uint8Array(buffer);
  const data = new Uint8ClampedArray(pixelCount * 4);

  for (let i = 0; i < pixelCount; i++) {
    if (channels === 1) {
      data[i * 4] = bytes[i];
      data[i * 4 + 1] = bytes[i];
      data[i * 4 + 2] = bytes[i];
      data[i * 4 + 3] = 255;
    } else if (channels === 2) {
      data[i * 4] = bytes[i * 2];
      data[i * 4 + 1] = bytes[i * 2];
      data[i * 4 + 2] = bytes[i * 2];
      data[i * 4 + 3] = bytes[i * 2 + 1];
    } else if (channels === 3) {
      data[i * 4] = bytes[i * 3];
      data[i * 4 + 1] = bytes[i * 3 + 1];
      data[i * 4 + 2] = bytes[i * 3 + 2];
      data[i * 4 + 3] = 255;
    } else if (channels === 4) {
      data[i * 4] = bytes[i * 4];
      data[i * 4 + 1] = bytes[i * 4 + 1];
      data[i * 4 + 2] = bytes[i * 4 + 2];
      data[i * 4 + 3] = bytes[i * 4 + 3];
    }
  }

  return new ImageData(data, width, height);
}

export default ImageOutput;
