import webpModuleFactory from './jsquash-webp/codec/enc/webp_enc.js';
import avifModuleFactory from './jsquash-avif/codec/enc/avif_enc.js';

const webpDefaults = {
  quality: 75,
  target_size: 0,
  target_PSNR: 0,
  method: 4,
  sns_strength: 50,
  filter_strength: 60,
  filter_sharpness: 0,
  filter_type: 1,
  partitions: 0,
  segments: 4,
  pass: 1,
  show_compressed: 0,
  preprocessing: 0,
  autofilter: 0,
  partition_limit: 0,
  alpha_compression: 1,
  alpha_filtering: 1,
  alpha_quality: 100,
  lossless: 0,
  exact: 0,
  image_hint: 0,
  emulate_jpeg_size: 0,
  thread_level: 0,
  low_memory: 0,
  near_lossless: 100,
  use_delta_palette: 0,
  use_sharp_yuv: 0,
};

const avifDefaults = {
  quality: 50,
  qualityAlpha: -1,
  denoiseLevel: 0,
  tileColsLog2: 0,
  tileRowsLog2: 0,
  speed: 6,
  subsample: 1,
  chromaDeltaQ: false,
  sharpness: 0,
  tune: 0,
  enableSharpYUV: false,
  bitDepth: 8,
  lossless: false,
};

let webpEncoderPromise;
let avifEncoderPromise;

function initModule(factory) {
  return factory({ noInitialRun: true });
}

function toQualityPercent(value, fallback) {
  const quality = Number.isFinite(Number(value)) ? Number(value) : fallback;
  return Math.max(0, Math.min(100, Math.round(quality * 100)));
}

async function getWebpEncoder() {
  if (!webpEncoderPromise) {
    webpEncoderPromise = initModule(webpModuleFactory);
  }
  return webpEncoderPromise;
}

async function getAvifEncoder() {
  if (!avifEncoderPromise) {
    avifEncoderPromise = initModule(avifModuleFactory);
  }
  return avifEncoderPromise;
}

export async function probe() {
  const result = { webp: false, avif: false };
  try {
    const mod = await getWebpEncoder();
    result.webp = !!(mod && typeof mod.encode === 'function');
  } catch (error) {
    result.webp = false;
  }
  try {
    const mod = await getAvifEncoder();
    result.avif = !!(mod && typeof mod.encode === 'function');
  } catch (error) {
    result.avif = false;
  }
  return result;
}

export async function encodeWebP(imageData, options = {}) {
  const mod = await getWebpEncoder();
  if (!mod || typeof mod.encode !== 'function') {
    throw new Error('WEBP encoder module is not available.');
  }
  const settings = {
    ...webpDefaults,
    ...options,
    quality: toQualityPercent(options.quality, 0.92),
    alpha_quality: options.alpha_quality != null ? options.alpha_quality : 100,
  };
  const result = mod.encode(imageData.data, imageData.width, imageData.height, settings);
  if (!result) {
    throw new Error('WEBP encoding failed.');
  }
  return result.buffer;
}

export async function encodeAVIF(imageData, options = {}) {
  const mod = await getAvifEncoder();
  if (!mod || typeof mod.encode !== 'function') {
    throw new Error('AVIF encoder module is not available.');
  }
  const settings = {
    ...avifDefaults,
    ...options,
    quality: toQualityPercent(options.quality, 0.72),
    qualityAlpha: options.qualityAlpha != null ? options.qualityAlpha : -1,
  };
  const result = mod.encode(new Uint8Array(imageData.data.buffer), imageData.width, imageData.height, settings);
  if (!result) {
    throw new Error('AVIF encoding failed.');
  }
  return result.buffer;
}

export default {
  probe,
  encodeWebP,
  encodeAVIF,
};
