/**
 * Server-side image normalisation. Single funnel for every image
 * upload (avatar, generic file, scan, attachment) to:
 *
 * - **Strip EXIF** (incl. GPS coords, device serial, photographer name)
 *   so uploaded photos don't leak per-pixel PII to anyone with a
 *   download URL. asset-auditor C1.
 * - **Cap dimensions** at MAX_DIMENSION so a 30000×30000 palette PNG
 *   can't decompression-bomb a sharp decode further downstream. C2.
 * - **Re-encode via sharp** so polyglot trailing bytes (PDF+JPEG
 *   sandwiches, HTML+PNG) are dropped - the output buffer is a clean
 *   single-format file regardless of input trickery. H1.
 * - **Freeze animated GIFs** to first frame so a 5000-frame phishing
 *   GIF can't pin a worker on every list-view render. H3.
 *
 * Falls through to the original buffer (with a warning at the call
 * site) when sharp isn't available or the input isn't a recognised
 * image. The MIME type stays the same as declared - magic-byte
 * verification has already run upstream.
 */

const MAX_DIMENSION = 4096;

export async function normalizeImage(
  input: Buffer,
  mimeType: string,
): Promise<{ buffer: Buffer; format: string }> {
  const { default: sharp } = await import('sharp');

  // Map MIME → sharp output format. Stay in-format so the stored
  // contentType keeps matching the bytes.
  const format = mimeFormat(mimeType);

  let pipeline = sharp(input, { animated: false, pages: 1 })
    .rotate() // honour EXIF orientation BEFORE stripping it
    .resize({
      width: MAX_DIMENSION,
      height: MAX_DIMENSION,
      fit: 'inside',
      withoutEnlargement: true,
    })
    .withMetadata({ orientation: undefined });

  // toFormat() drops anything non-format-shaped after re-encode.
  if (format === 'jpeg') pipeline = pipeline.jpeg({ quality: 88, mozjpeg: true });
  else if (format === 'png') pipeline = pipeline.png({ compressionLevel: 9 });
  else if (format === 'webp') pipeline = pipeline.webp({ quality: 88 });
  else if (format === 'gif') pipeline = pipeline.gif();

  const buffer = await pipeline.toBuffer();
  return { buffer, format };
}

function mimeFormat(mimeType: string): 'jpeg' | 'png' | 'webp' | 'gif' | 'unknown' {
  if (mimeType === 'image/jpeg' || mimeType === 'image/jpg') return 'jpeg';
  if (mimeType === 'image/png') return 'png';
  if (mimeType === 'image/webp') return 'webp';
  if (mimeType === 'image/gif') return 'gif';
  return 'unknown';
}
