// Analyse une image étape par étape pour repérer précisément où elle bloque.
// Usage : glisser le fichier sur diagnostic.cmd, ou : node diagnostic.mjs "chemin"
import sharp from 'sharp';
import { stat, readFile } from 'node:fs/promises';

sharp.cache(false);

const chemin = process.argv[2];
if (!chemin) {
  console.log('\n  Glissez une image sur diagnostic.cmd, ou passez son chemin en argument.\n');
  process.exit(1);
}

const mo = () => Math.round(process.memoryUsage().rss / 1048576);
const etape = (n, t) => console.log(`\n[${n}] ${t}`);

console.log('\n================ DIAGNOSTIC POIDS PLUME ================');
console.log('fichier : ' + chemin);

etape(1, 'Lecture du fichier');
let octets;
try {
  const infos = await stat(chemin);
  octets = await readFile(chemin);
  console.log(`    OK — ${Math.round(infos.size / 1024)} Ko sur le disque, ${octets.length} octets lus`);
  console.log(`    premiers octets : ${octets.subarray(0, 8).toString('hex')}`);
} catch (e) {
  console.log('    ECHEC — ' + e.message);
  process.exit(1);
}

etape(2, 'Lecture des caractéristiques');
let meta = null;
try {
  meta = await sharp(octets, { failOn: 'none' }).metadata();
  const mpx = ((meta.width * meta.height) / 1e6).toFixed(1);
  console.log(`    OK — ${meta.format} ${meta.width} x ${meta.height} (${mpx} megapixels)`);
  console.log(`    canaux ${meta.channels}, profondeur ${meta.depth}, alpha ${meta.hasAlpha}, entrelace ${meta.isProgressive}`);
  console.log(`    espace ${meta.space}, palette ${meta.paletteBitDepth ?? 'non'}, pages ${meta.pages ?? 1}`);
  console.log(`    profil ICC ${meta.icc ? meta.icc.length + ' octets' : 'aucun'}, EXIF ${meta.exif ? meta.exif.length + ' octets' : 'aucun'}`);

  const ramMo = Math.round((meta.width * meta.height * (meta.channels || 4)) / 1048576);
  console.log(`    memoire necessaire pour la decompresser : environ ${ramMo} Mo`);
  if (ramMo > 1500) console.log('    >>> C EST ENORME. C est tres probablement la cause du plantage.');
  if (meta.isProgressive) console.log('    >>> Image entrelacee : elle doit etre chargee entierement en memoire.');
} catch (e) {
  console.log('    ECHEC — ' + e.message);
  console.log('    >>> Le decodeur principal refuse ce fichier. Le repli HEIC sera tente a l etape 3.');
}

etape(3, 'Decodage complet des pixels');
try {
  const t = Date.now();
  const { info } = await sharp(octets, { failOn: 'none' })
    .resize({ width: 200 })
    .raw()
    .toBuffer({ resolveWithObject: true });
  console.log(`    OK — reduit en ${info.width}x${info.height} en ${((Date.now() - t) / 1000).toFixed(1)}s, memoire ${mo()} Mo`);
} catch (e) {
  console.log('    ECHEC — ' + e.message);
}

etape(4, 'Analyse de la transparence');
if (meta?.hasAlpha) {
  try {
    const t = Date.now();
    const s = await sharp(octets, { failOn: 'none' }).stats();
    console.log(`    OK — opaque : ${s.isOpaque} (${((Date.now() - t) / 1000).toFixed(1)}s, memoire ${mo()} Mo)`);
  } catch (e) {
    console.log('    ECHEC — ' + e.message);
  }
} else {
  console.log('    ignoree (pas de canal alpha)');
}

etape(5, 'Chaine complete de Poids Plume');
try {
  const { traiter } = await import('./lib/traitement.mjs');
  const t = Date.now();
  const r = await traiter({ octets }, { largeurs: [1200, 800, 400], budgetKo: 120 });
  console.log(`    OK — ${r.sorties.length} tailles produites en ${((Date.now() - t) / 1000).toFixed(1)}s`);
  for (const s of r.sorties) console.log(`         ${s.largeur}x${s.hauteur} : ${Math.round(s.taille / 1024)} Ko (qualite ${s.qualite})`);
  console.log(`    memoire maximale : ${mo()} Mo`);
  console.log('\n    >>> Ce fichier passe sans probleme. Le blocage est ailleurs.');
} catch (e) {
  console.log('    ECHEC — ' + e.message);
  console.log('\n    >>> Voila l erreur a me transmettre.');
}

console.log('\n=======================================================');
console.log('Copiez tout ce texte et transmettez-le.\n');
