import { preprocessors, codecs as supportedFormats } from "./codecs.js";
import ImageData from "./image_data.js";
const DELAY_MS = 1e3;
let _promise;
function delayOnce(ms) {
  if (!_promise) {
    _promise = new Promise((resolve) => {
      setTimeout(resolve, ms);
    });
  }
  return _promise;
}
function maybeDelay() {
  const isAppleM1 = process.arch === "arm64" && process.platform === "darwin";
  if (isAppleM1) {
    return delayOnce(DELAY_MS);
  }
  return Promise.resolve();
}
async function decodeBuffer(_buffer) {
  const buffer = Buffer.from(_buffer);
  const firstChunk = buffer.slice(0, 16);
  const firstChunkString = Array.from(firstChunk).map((v) => String.fromCodePoint(v)).join("");
  if (firstChunkString.includes("GIF")) {
    throw Error(`GIF images are not supported, please use the Sharp image service`);
  }
  const key = Object.entries(supportedFormats).find(
    ([, { detectors }]) => detectors.some((detector) => detector.exec(firstChunkString))
  )?.[0];
  if (!key) {
    throw Error(`Buffer has an unsupported format`);
  }
  const encoder = supportedFormats[key];
  const mod = await encoder.dec();
  const rgba = mod.decode(new Uint8Array(buffer));
  return rgba;
}
async function rotate(image, numRotations) {
  image = ImageData.from(image);
  const m = await preprocessors["rotate"].instantiate();
  return await m(image.data, image.width, image.height, { numRotations });
}
async function resize({ image, width, height }) {
  image = ImageData.from(image);
  const p = preprocessors["resize"];
  const m = await p.instantiate();
  await maybeDelay();
  return await m(image.data, image.width, image.height, {
    ...p.defaultOptions,
    width,
    height
  });
}
async function encodeJpeg(image, opts) {
  image = ImageData.from(image);
  const e = supportedFormats["mozjpeg"];
  const m = await e.enc();
  await maybeDelay();
  const quality = opts.quality || e.defaultEncoderOptions.quality;
  const r = await m.encode(image.data, image.width, image.height, {
    ...e.defaultEncoderOptions,
    quality
  });
  return r;
}
async function encodeWebp(image, opts) {
  image = ImageData.from(image);
  const e = supportedFormats["webp"];
  const m = await e.enc();
  await maybeDelay();
  const quality = opts.quality || e.defaultEncoderOptions.quality;
  const r = await m.encode(image.data, image.width, image.height, {
    ...e.defaultEncoderOptions,
    quality
  });
  return r;
}
async function encodeAvif(image, opts) {
  image = ImageData.from(image);
  const e = supportedFormats["avif"];
  const m = await e.enc();
  await maybeDelay();
  const val = e.autoOptimize.min;
  const quality = opts.quality || 75;
  const r = await m.encode(image.data, image.width, image.height, {
    ...e.defaultEncoderOptions,
    // Think of cqLevel as the "amount" of quantization (0 to 62),
    // so a lower value yields higher quality (0 to 100).
    cqLevel: quality === 0 ? val : Math.round(val - quality / 100 * val)
  });
  return r;
}
async function encodePng(image) {
  image = ImageData.from(image);
  const e = supportedFormats["oxipng"];
  const m = await e.enc();
  await maybeDelay();
  const r = await m.encode(image.data, image.width, image.height, {
    ...e.defaultEncoderOptions
  });
  return r;
}
export {
  decodeBuffer,
  encodeAvif,
  encodeJpeg,
  encodePng,
  encodeWebp,
  resize,
  rotate
};
