// ── Afmetingen en type van een afbeelding uit de ruwe bytes ─────────────────
// De `docx`-bibliotheek (ImageRun) vereist expliciete pixelafmetingen en een
// type ("png"/"jpg") bij het invoegen — ze leidt dat niet zelf af uit de
// data. Voor door de gebruiker aangeleverde schermafbeeldingen (bv. van
// stedenbouwkundige inlichtingen) lezen we de intrinsieke afmetingen dus zelf
// uit de PNG-/JPEG-header, zodat ze op een leesbare breedte geschaald kunnen
// worden zonder de beeldverhouding te vervormen.

export interface AfbeeldingAfmetingen {
  breedte: number;
  hoogte: number;
  type: "png" | "jpg";
}

/** True voor de PNG-signatuurbytes (89 50 4E 47 0D 0A 1A 0A). */
function isPng(buf: Buffer): boolean {
  return (
    buf.length >= 24 &&
    buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47 &&
    buf[4] === 0x0d && buf[5] === 0x0a && buf[6] === 0x1a && buf[7] === 0x0a
  );
}

/** True voor de JPEG-signatuurbytes (FF D8). */
function isJpeg(buf: Buffer): boolean {
  return buf.length >= 4 && buf[0] === 0xff && buf[1] === 0xd8;
}

/** PNG: breedte/hoogte staan op vaste positie in de eerste chunk (IHDR). */
function pngAfmetingen(buf: Buffer): { breedte: number; hoogte: number } {
  return { breedte: buf.readUInt32BE(16), hoogte: buf.readUInt32BE(20) };
}

/**
 * JPEG: scan de markers tot een SOFx-segment (Start Of Frame, bevat de
 * afmetingen) — geen volledige JPEG-parser, enkel de markers die voor
 * afmetingen relevant zijn.
 */
function jpegAfmetingen(buf: Buffer): { breedte: number; hoogte: number } | null {
  let i = 2;
  while (i + 9 < buf.length) {
    if (buf[i] !== 0xff) {
      i++;
      continue;
    }
    const marker = buf[i + 1];
    // SOF0-SOF15, exclusief DHT (C4), JPG (C8) en DAC (CC) — die zijn geen SOF.
    const isSof = marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc;
    if (isSof) {
      return { hoogte: buf.readUInt16BE(i + 5), breedte: buf.readUInt16BE(i + 7) };
    }
    const segmentLengte = buf.readUInt16BE(i + 2);
    i += 2 + segmentLengte;
  }
  return null;
}

/**
 * Leidt het beeldtype en de intrinsieke afmetingen (in pixels) af uit de
 * ruwe bytes van een PNG- of JPEG-afbeelding. Onherkend formaat of te korte
 * buffer → null (de aanroeper slaat de afbeelding dan over i.p.v. te falen).
 */
export function afmetingenUitBuffer(buf: Buffer): AfbeeldingAfmetingen | null {
  if (isPng(buf)) {
    const { breedte, hoogte } = pngAfmetingen(buf);
    if (breedte > 0 && hoogte > 0) return { breedte, hoogte, type: "png" };
    return null;
  }
  if (isJpeg(buf)) {
    const afmetingen = jpegAfmetingen(buf);
    if (afmetingen && afmetingen.breedte > 0 && afmetingen.hoogte > 0) return { ...afmetingen, type: "jpg" };
    return null;
  }
  return null;
}

/** Schaalt (breedte, hoogte) naar een maximale breedte, met behoud van de beeldverhouding. */
export function schaalNaarBreedte(breedte: number, hoogte: number, maxBreedte: number): { breedte: number; hoogte: number } {
  if (breedte <= maxBreedte) return { breedte, hoogte };
  const factor = maxBreedte / breedte;
  return { breedte: maxBreedte, hoogte: Math.round(hoogte * factor) };
}
