/**
 * Shared PNG export for charts.
 *
 * Each chart composites itself (plot + icon bands + optional title + legend)
 * onto a canvas via `getExportImage`; those are stacked vertically over the
 * current theme background and downloaded as one PNG.
 */

/** A chart that can composite itself (plot + icons + legend) for export. */
export interface ExportableChart {
	getExportImage(opts?: { title?: string }): Promise<HTMLCanvasElement | null>;
}

/** One chart to export, with the title to render above it (e.g. panel name). */
export interface ChartExportItem {
	chart: ExportableChart | null | undefined;
	title?: string;
}

/** Resolves the page background so exports match the current theme. */
function exportBackground(): string {
	const bg = getComputedStyle(document.documentElement).getPropertyValue('--background').trim();
	return bg || '#ffffff';
}

function triggerDownload(url: string, name: string): void {
	const link = document.createElement('a');
	link.href = url;
	link.download = name;
	link.style.display = 'none';
	document.body.appendChild(link);
	link.click();
	requestAnimationFrame(() => {
		document.body.removeChild(link);
	});
}

/** Normalise either a bare chart or a {chart, title} item. */
function toItem(x: ChartExportItem | ExportableChart | null | undefined): ChartExportItem {
	if (x && 'getExportImage' in x) return { chart: x };
	return (x as ChartExportItem) ?? { chart: null };
}

/**
 * Stitch the given charts into one PNG and download it. Resolves once the
 * download has been triggered (or immediately if there is nothing to export).
 */
export async function downloadChartsPng(
	charts: Array<ChartExportItem | ExportableChart | null | undefined>,
	fileName: string
): Promise<void> {
	const items = charts.map(toItem).filter((it) => it.chart != null);
	if (items.length === 0) return;

	const canvases = (
		await Promise.all(items.map((it) => it.chart!.getExportImage({ title: it.title })))
	).filter((c): c is HTMLCanvasElement => c != null && c.width > 0 && c.height > 0);
	if (canvases.length === 0) return;

	const maxWidth = Math.max(...canvases.map((c) => c.width));
	const totalHeight = canvases.reduce((sum, c) => sum + c.height, 0);

	const canvas = document.createElement('canvas');
	canvas.width = maxWidth;
	canvas.height = totalHeight;

	const ctx = canvas.getContext('2d');
	if (!ctx) return;

	ctx.fillStyle = exportBackground();
	ctx.fillRect(0, 0, maxWidth, totalHeight);

	let y = 0;
	for (const c of canvases) {
		ctx.drawImage(c, 0, y);
		y += c.height;
	}

	triggerDownload(canvas.toDataURL('image/png'), `${fileName}.png`);
}
