/**
 * Visually lossless re-encode for imported raster images (same pixel dimensions).
 * Node-only; shared by the main app and ../project-converter (monorepo sibling).
 */
import { getSharp } from './sharpRuntime.mjs';

/** @typedef {import('node:buffer').Buffer} Buffer */

/**
 * @typedef {Object} OptimizeImageImportResult
 * @property {Buffer} buffer
 * @property {string} mime
 * @property {string} ext filename extension without dot (e.g. webp, jpg, png)
 * @property {number} width
 * @property {number} height
 * @property {boolean} passthrough true if original bytes were kept
 */

const WEBP_EFFORT = 6;
const RASTER_QUALITY = 95;

/**
 * @param {Buffer} buf
 * @param {import('sharp').Metadata | null} meta
 * @returns {OptimizeImageImportResult}
 */
function makePassthrough(buf, meta) {
  const fmt = meta?.format;
  if (fmt === 'jpeg' || fmt === 'jpg') {
    return {
      buffer: buf,
      mime: 'image/jpeg',
      ext: 'jpg',
      width: meta?.width ?? 0,
      height: meta?.height ?? 0,
      passthrough: true,
    };
  }
  if (fmt === 'png') {
    return {
      buffer: buf,
      mime: 'image/png',
      ext: 'png',
      width: meta?.width ?? 0,
      height: meta?.height ?? 0,
      passthrough: true,
    };
  }
  if (fmt === 'webp') {
    return {
      buffer: buf,
      mime: 'image/webp',
      ext: 'webp',
      width: meta?.width ?? 0,
      height: meta?.height ?? 0,
      passthrough: true,
    };
  }
  if (fmt === 'gif') {
    return {
      buffer: buf,
      mime: 'image/gif',
      ext: 'gif',
      width: meta?.width ?? 0,
      height: meta?.height ?? 0,
      passthrough: true,
    };
  }
  if (fmt === 'tiff' || fmt === 'tif') {
    return {
      buffer: buf,
      mime: 'image/tiff',
      ext: 'tiff',
      width: meta?.width ?? 0,
      height: meta?.height ?? 0,
      passthrough: true,
    };
  }
  if (fmt === 'bmp') {
    return {
      buffer: buf,
      mime: 'image/bmp',
      ext: 'bmp',
      width: meta?.width ?? 0,
      height: meta?.height ?? 0,
      passthrough: true,
    };
  }
  return {
    buffer: buf,
    mime: 'application/octet-stream',
    ext: 'bin',
    width: meta?.width ?? 0,
    height: meta?.height ?? 0,
    passthrough: true,
  };
}

/**
 * @param {Buffer} outBuf
 * @param {number} w0
 * @param {number} h0
 */
async function sameDimensionsOrThrow(outBuf, w0, h0) {
  const sharp = getSharp();
  const m = await sharp(outBuf).metadata();
  if ((m.width ?? 0) !== w0 || (m.height ?? 0) !== h0) {
    const err = new Error('encode changed dimensions');
    err.code = 'DIM';
    throw err;
  }
}

/**
 * @param {Buffer} src
 * @returns {Promise<OptimizeImageImportResult>}
 */
export async function optimizeImageBufferVisuallyLossless(src) {
  const input = Buffer.isBuffer(src) ? src : Buffer.from(src);
  if (input.length === 0) {
    return makePassthrough(input, { width: 0, height: 0, format: 'png' });
  }

  let sharp;
  try {
    sharp = getSharp();
  } catch {
    return makePassthrough(input, null);
  }

  let meta0;
  try {
    meta0 = await sharp(input, { failOn: 'error', unlimited: true }).metadata();
  } catch {
    return makePassthrough(input, null);
  }

  const width = meta0.width ?? 0;
  const height = meta0.height ?? 0;
  if (width <= 0 || height <= 0) {
    return makePassthrough(input, meta0);
  }

  const pages = meta0.pages ?? 1;
  if (pages > 1) {
    return makePassthrough(input, meta0);
  }

  const rawFmt = meta0.format;
  if (rawFmt === 'svg' || rawFmt === 'pdf' || rawFmt === 'heif' || rawFmt === 'jxl' || rawFmt === 'vips') {
    return makePassthrough(input, meta0);
  }

  const hasAlpha = meta0.hasAlpha === true;

  try {
    if (hasAlpha) {
      const webpLo = await sharp(input)
        .rotate()
        .ensureAlpha()
        .webp({ lossless: true, effort: WEBP_EFFORT })
        .toBuffer();
      const pngOut = await sharp(input)
        .rotate()
        .ensureAlpha()
        .png({ compressionLevel: 9, adaptiveFiltering: true })
        .toBuffer();
      await sameDimensionsOrThrow(webpLo, width, height);
      await sameDimensionsOrThrow(pngOut, width, height);

      const pickWebp = webpLo.length <= pngOut.length;
      const outBuf = pickWebp ? webpLo : pngOut;
      if (outBuf.length >= input.length) {
        return makePassthrough(input, meta0);
      }
      return {
        buffer: outBuf,
        mime: pickWebp ? 'image/webp' : 'image/png',
        ext: pickWebp ? 'webp' : 'png',
        width,
        height,
        passthrough: false,
      };
    }

    const webpColor = await sharp(input)
      .rotate()
      .webp({
        quality: RASTER_QUALITY,
        nearLossless: true,
        effort: WEBP_EFFORT,
        smartSubsample: false,
      })
      .toBuffer();
    const jpegColor = await sharp(input)
      .rotate()
      .jpeg({
        quality: RASTER_QUALITY,
        chromaSubsampling: '4:4:4',
        mozjpeg: true,
        optimizeScans: true,
      })
      .toBuffer();
    await sameDimensionsOrThrow(webpColor, width, height);
    await sameDimensionsOrThrow(jpegColor, width, height);

    const useWebp = webpColor.length <= jpegColor.length;
    const outBuf = useWebp ? webpColor : jpegColor;
    if (outBuf.length >= input.length) {
      return makePassthrough(input, meta0);
    }
    return {
      buffer: outBuf,
      mime: useWebp ? 'image/webp' : 'image/jpeg',
      ext: useWebp ? 'webp' : 'jpg',
      width,
      height,
      passthrough: false,
    };
  } catch (e) {
    if (e && typeof e === 'object' && /** @type {{ code?: string }} */ (e).code === 'DIM') {
      return makePassthrough(input, meta0);
    }
    return makePassthrough(input, meta0);
  }
}
