// The loading card's backdrop: the pond as it opens, with not a duck in it,
// shot at one device shape and squeezed into a progressive JPEG small enough to
// be down before the module is — the card blurs it anyway, so it wants to be
// cheap rather than sharp. Usage:
//   node scripts/loader-shot.mjs [url] [out] [width] [height] [dpr] [outWidth] [quality]
// The raw PNG is kept under temp/ so the capture can be looked at unblurred.
// Needs `npm i --no-save sharp` — the only thing in the repo that uses it.
import puppeteer from 'puppeteer';
import sharp from 'sharp';
import { mkdirSync } from 'node:fs';
import { dirname, resolve, basename } from 'node:path';

const url = process.argv[2] || 'http://localhost:5180/';
const out = resolve(process.argv[3] || 'public/pond-loader.jpg');
const width = Number(process.argv[4]) || 430;
const height = Number(process.argv[5]) || 932;
const dpr = Number(process.argv[6]) || 2;
const outWidth = Number(process.argv[7]) || width;
const quality = Number(process.argv[8]) || 50;

const browser = await puppeteer.launch({
	headless: true,
	args: ['--enable-unsafe-swiftshader', '--hide-scrollbars'],
});

try {
	const page = await browser.newPage();
	await page.setViewport({ width, height, deviceScaleFactor: dpr, isMobile: dpr > 1, hasTouch: dpr > 1 });
	page.on('pageerror', (err) => console.log(`[pageerror] ${err.message}`));
	await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
	await page.waitForFunction('window.quack && window.quack.app.started', { timeout: 30000 });

	// hold the pond at the pose it opens on, with the flock out of the shot, the
	// odd feather or droplet out of it too, and the card itself out of the shot,
	// then wait for the frame it is drawn in
	await page.evaluate(async () => {
		const q = window.quack;
		q.app.paused = true;
		document.getElementById('loading')?.remove();
		for (const d of q.pond.ducks) d.root.visible = false;
		for (const pool of [q.effects.feathers, q.effects.bits, q.effects.leaves, q.effects.snowflakes]) {
			pool.mesh.visible = false;
		}
		for (const r of q.effects.ripples) r.mesh.visible = false;
		await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
	});

	const raw = resolve('temp/loader', basename(out).replace(/\.jpe?g$/i, '.png'));
	mkdirSync(dirname(raw), { recursive: true });
	await page.screenshot({ path: raw, type: 'png' });

	const png = await sharp(raw);
	const meta = await png.metadata();
	mkdirSync(dirname(out), { recursive: true });
	const info = await png
		.resize({ width: outWidth, kernel: 'lanczos3' })
		.jpeg({ quality, progressive: true, mozjpeg: true, chromaSubsampling: '4:2:0' })
		.toFile(out);

	console.log(
		`${out}  ${info.width}x${info.height}  ${(info.size / 1024).toFixed(1)} kB  ` +
			`(from ${meta.width}x${meta.height} at ${dpr}x)  raw: ${raw}`,
	);
} finally {
	await browser.close();
}