// Image pipeline: img/projects sources -> dist/assets/img/projects/<slug>/
// Variants per photo: 800w + 1600w WebP, 1200w JPEG fallback. Never upscales.
// Writes src/data/images.json manifest with final dimensions per variant.
// Usage: npm run images   (re-run only when photos change; build.js just reads the manifest)
const fs = require('fs');
const path = require('path');
const sharp = require('sharp');

const ROOT = path.join(__dirname, '..');
const OUT = path.join(ROOT, 'dist', 'assets', 'img');
const projects = JSON.parse(fs.readFileSync(path.join(ROOT, 'src', 'data', 'projects.json'), 'utf8'));

const VARIANTS = [
  { width: 800, format: 'webp', options: { quality: 78 } },
  { width: 1600, format: 'webp', options: { quality: 74 } },
  { width: 1200, format: 'jpeg', options: { quality: 72, mozjpeg: true } },
];

async function processOne(slug, srcRel, index) {
  const srcAbs = path.join(ROOT, srcRel);
  if (!fs.existsSync(srcAbs)) return { srcRel, error: 'missing source' };
  const dir = path.join(OUT, 'projects', slug);
  fs.mkdirSync(dir, { recursive: true });
  const base = sharp(srcAbs).rotate(); // respect EXIF orientation
  const meta = await base.metadata();
  const srcW = meta.autoOrient ? meta.autoOrient.width : meta.width;
  const srcH = meta.autoOrient ? meta.autoOrient.height : meta.height;
  const name = String(index + 1).padStart(2, '0');
  const entry = { source: srcRel, width: srcW, height: srcH, variants: [] };
  for (const v of VARIANTS) {
    const w = Math.min(v.width, srcW);
    const file = `${name}-${v.width}.${v.format === 'jpeg' ? 'jpg' : v.format}`;
    const outPath = path.join(dir, file);
    if (!fs.existsSync(outPath)) {
      await base.clone().resize({ width: w, withoutEnlargement: true })[v.format](v.options).toFile(outPath);
    }
    const h = Math.round(srcH * (w / srcW));
    entry.variants.push({ file: `assets/img/projects/${slug}/${file}`, width: w, height: h, format: v.format });
  }
  return entry;
}

(async () => {
  const manifest = {};
  let done = 0, failed = 0;
  const total = projects.reduce((n, p) => n + p.images.length, 0);
  for (const p of projects) {
    manifest[p.slug] = [];
    // limited parallelism: sharp saturates cores on its own thread pool
    const queue = p.images.map((src, i) => () => processOne(p.slug, src, i));
    while (queue.length) {
      const batch = queue.splice(0, 4).map(fn => fn());
      for (const r of await Promise.all(batch)) {
        if (r.error) { failed++; console.error('MISSING:', r.source || r.srcRel); }
        manifest[p.slug].push(r);
        done++;
      }
    }
    console.log(`${p.slug}: ${manifest[p.slug].length} images (${done}/${total})`);
  }
  fs.writeFileSync(path.join(ROOT, 'src', 'data', 'images.json'), JSON.stringify(manifest, null, 1));
  console.log(`DONE. processed=${done} failed=${failed}`);
})();
