<script lang="ts">
	import { onMount } from 'svelte';
	import { sheetData, currentStep, pictures, cropRects, cardDetails, selectedCard } from '$lib/stores';
	import type { Card } from '$lib/cards/types';
	import { PDFDocument, StandardFonts, rgb, type PDFPage } from 'pdf-lib';
	import * as fontkit from 'fontkit';
	import { clear } from 'idb-keyval';
	import {
		BORDER_CONFIG,
		TEXT_CONFIG,
		calculateGrid,
		getAbsolutePositionPt,
		getAbsolutePhotoDimensionsPt,
		getImageBlob,
		MM_TO_PT
	} from '$lib/pdfLayout';
	import { PAGE_SETTINGS } from '$lib/pdfSettings';
	import type { PageSettings } from '$lib/pdfSettings';
	import Navigator from './subcomponents/Navigator.svelte';

	type FileGenerationState = 'idle' | 'generating' | 'done' | 'error';

	type GeneratedFile = {
		name: string;
		displayName: string;
		state: FileGenerationState;
		url: string | null;
		size: number | null;
		error: string | null;
		downloadName?: string;
	};

	const initialFiles: GeneratedFile[] = [
		{
			name: 'esncards_text.pdf',
			displayName: 'Text PDF',
			state: 'idle',
			url: null,
			size: null,
			error: null
		},
		{
			name: 'esncards_photos.pdf',
			displayName: 'Photos PDF',
			state: 'idle',
			url: null,
			size: null,
			error: null
		}
	];

	let files = $state<GeneratedFile[]>(JSON.parse(JSON.stringify(initialFiles)));

	// Cleanup function to clear IndexedDB and sensitive data
	async function clearSensitiveData() {
		try {
			await clear(); // Clear all data from IndexedDB
			console.log('IndexedDB cleared for security');
		} catch (error) {
			console.error('Failed to clear IndexedDB:', error);
		}
	}

	// Handle tab close or page unload
	function handleBeforeUnload() {
		clearSensitiveData();
	}

	onMount(() => {
		handleGenerateAll();
		// Add event listener for page unload
		window.addEventListener('beforeunload', handleBeforeUnload);

		// Cleanup function when component unmounts
		return () => {
			window.removeEventListener('beforeunload', handleBeforeUnload);
			clearSensitiveData();
		};
	});

	async function handleGenerateAll() {
		if (!$selectedCard) return;

		// Reset file states and revoke old URLs
		files.forEach((f) => {
			if (f.url) URL.revokeObjectURL(f.url);
		});
		files = JSON.parse(JSON.stringify(initialFiles));

		// Generate both
		await handleGenerate('esncards_text.pdf');
		await handleGenerate('esncards_photos.pdf');
	}

	const generationStarted = $derived(files.some((f) => f.state !== 'idle'));

	// Load Roboto font
	async function loadRobotoFont() {
		try {
			const fontResponse = await fetch('/fonts/Roboto-Regular.ttf');
			if (!fontResponse.ok) {
				throw new Error('Failed to load Roboto font');
			}
			return await fontResponse.arrayBuffer();
		} catch (error: any) {
			console.warn('Could not load Roboto font, falling back to standard font:', error);
			return null;
		}
	}

	// Create a formatted timestamp string
	function getTimestamp(): string {
		const d = new Date();
		const year = d.getFullYear();
		const month = (d.getMonth() + 1).toString().padStart(2, '0');
		const day = d.getDate().toString().padStart(2, '0');
		const hours = d.getHours().toString().padStart(2, '0');
		const minutes = d.getMinutes().toString().padStart(2, '0');
		return `${year}-${month}-${day}-${hours}-${minutes}`;
	}

	// Draw a very wide 'H' (10 cm length) at the top and left margins as registration marks
	function drawHMarks(page: PDFPage, font: any, pageSettings: PageSettings) {
		const color = rgb(0, 0, 0); // pure black
		const lengthPt = 100 * MM_TO_PT; // 10 cm
		const tickLenPt = 2 * MM_TO_PT; // 2 mm tick
		const strokePt = 0.7; // visual thickness

		// Top margin center
		const centerTopX = (pageSettings.pageWidth / 2) * MM_TO_PT;
		const centerTopY = (pageSettings.pageHeight - pageSettings.margin / 2) * MM_TO_PT;
		const leftTopX = centerTopX - lengthPt / 2;
		const rightTopX = centerTopX + lengthPt / 2;

		// Horizontal bar (top)
		page.drawRectangle({
			x: leftTopX,
			y: centerTopY - strokePt / 2,
			width: lengthPt,
			height: strokePt,
			color
		});
		// Left vertical tick (top)
		page.drawRectangle({
			x: leftTopX - strokePt / 2,
			y: centerTopY - tickLenPt / 2,
			width: strokePt,
			height: tickLenPt,
			color
		});
		// Right vertical tick (top)
		page.drawRectangle({
			x: rightTopX - strokePt / 2,
			y: centerTopY - tickLenPt / 2,
			width: strokePt,
			height: tickLenPt,
			color
		});

		// Label under the top bar, centered
		const label = 'Print gauge - if not 10 cm long, the page is not printed correctly!';
		const labelSize = 7;
		const labelWidth = font.widthOfTextAtSize(label, labelSize);
		const labelX = centerTopX - labelWidth / 2; // center horizontally
		const labelY = centerTopY - 3 * MM_TO_PT; // ~3mm below the bar
		page.drawText(label, {
			x: labelX,
			y: labelY,
			size: labelSize,
			font,
			color
		});

		// Left margin center (vertical bar)
		const centerLeftX = (pageSettings.margin / 2) * MM_TO_PT;
		const centerLeftY = (pageSettings.pageHeight / 2) * MM_TO_PT;

		// Vertical bar (left)
		page.drawRectangle({
			x: centerLeftX - strokePt / 2,
			y: centerLeftY - lengthPt / 2,
			width: strokePt,
			height: lengthPt,
			color
		});
		// Top horizontal tick (left)
		page.drawRectangle({
			x: centerLeftX - tickLenPt / 2,
			y: centerLeftY + lengthPt / 2 - strokePt / 2,
			width: tickLenPt,
			height: strokePt,
			color
		});
		// Bottom horizontal tick (left)
		page.drawRectangle({
			x: centerLeftX - tickLenPt / 2,
			y: centerLeftY - lengthPt / 2 - strokePt / 2,
			width: tickLenPt,
			height: strokePt,
			color
		});
	}

	// Format a YYYY-MM-DD string into "DD   MM   YY"
	function formatDateDDMMYY(value: string): string {
		if (!value) return '';
		const trimmed = value.trim();

		// Expects YYYY-MM-DD and splits it
		const parts = trimmed.split('-');
		if (parts.length === 3) {
			const [y, mo, d] = parts;
			if (y.length === 4 && mo.length === 2 && d.length === 2) {
				return `${d}   ${mo}   ${y.slice(-2)}`;
			}
		}

		// Fallback for any other format that might slip through
		console.warn(`Unexpected date format received in formatDateDDMMYY: "${trimmed}"`);
		return trimmed;
	}

	// Crop image using canvas
	async function cropImage(
		imageBlob: Blob,
		crop: { x: number; y: number; width: number; height: number }
	): Promise<Uint8Array> {
		return new Promise((resolve, reject) => {
			const img = new Image();
			const canvas = document.createElement('canvas');
			const ctx = canvas.getContext('2d');

			if (!ctx) {
				reject(new Error('Could not get canvas context'));
				return;
			}

			img.onload = () => {
				// Set canvas size to crop dimensions
				canvas.width = crop.width;
				canvas.height = crop.height;

				// Draw the cropped portion of the image
				ctx.drawImage(
					img,
					crop.x,
					crop.y,
					crop.width,
					crop.height, // Source rectangle
					0,
					0,
					crop.width,
					crop.height // Destination rectangle
				);

				// Convert canvas to blob then to array buffer
				canvas.toBlob(
					(blob) => {
						if (blob) {
							blob
								.arrayBuffer()
								.then((buffer) => {
									resolve(new Uint8Array(buffer));
								})
								.catch(reject);
						} else {
							reject(new Error('Failed to create blob from canvas'));
						}
					},
					'image/jpeg',
					0.9
				);
			};

			img.onerror = () => reject(new Error('Failed to load image'));
			img.src = URL.createObjectURL(imageBlob);
		});
	}

	async function handleGenerate(fileName: string) {
		const fileToUpdate = files.find((f) => f.name === fileName);
		if (!fileToUpdate || fileToUpdate.state === 'generating') return;

		fileToUpdate.state = 'generating';
		fileToUpdate.error = null;

		try {
			const pdfBytes =
				fileName === 'esncards_text.pdf' ? await generateTextPDF() : await generatePhotoPDF();

			// Convert Uint8Array to ArrayBuffer slice to satisfy BlobPart typing
			const arrayBuffer = pdfBytes.buffer.slice(
				pdfBytes.byteOffset,
				pdfBytes.byteOffset + pdfBytes.byteLength
			);
			const blob = new Blob([arrayBuffer as ArrayBuffer], { type: 'application/pdf' });

			// Revoke old URL if it exists
			if (fileToUpdate.url) {
				URL.revokeObjectURL(fileToUpdate.url);
			}

			fileToUpdate.url = URL.createObjectURL(blob);
			fileToUpdate.size = pdfBytes.length;
			fileToUpdate.state = 'done';

			const timestamp = getTimestamp();
			const baseName = fileName.replace('.pdf', '');
			fileToUpdate.downloadName = `${baseName}_${timestamp}.pdf`;
		} catch (error: any) {
			console.error(`PDF generation failed for ${fileName}:`, error);
			fileToUpdate.state = 'error';
			fileToUpdate.error = error.message || 'An unknown error occurred';
		}
	}

	async function generateTextPDF() {
		const card = $selectedCard;
		if (!card) throw new Error('No card type selected');

		const pdfDoc = await PDFDocument.create();
		pdfDoc.registerFontkit(fontkit);

		const robotoFontBytes = await loadRobotoFont();
		const font = robotoFontBytes
			? await pdfDoc.embedFont(robotoFontBytes)
			: await pdfDoc.embedFont(StandardFonts.TimesRoman);

		const gridLayout = calculateGrid(
			PAGE_SETTINGS.pageWidth,
			PAGE_SETTINGS.pageHeight,
			PAGE_SETTINGS.margin,
			card.textCard.width,
			card.textCard.height
		);
		const pageDimsPt = {
			width: PAGE_SETTINGS.pageWidth * MM_TO_PT,
			height: PAGE_SETTINGS.pageHeight * MM_TO_PT
		};

		let page = pdfDoc.addPage([pageDimsPt.width, pageDimsPt.height]);
		drawHMarks(page, font, PAGE_SETTINGS);
		let currentRow = 0;
		let currentCol = 0;

		const validRows = $sheetData.filter((row) => row._valid);
		const details = $cardDetails;
		const studiesAtAll = details?.studiesAt ?? '';
		const esnSectionAll = details?.esnSection ?? '';
		const validityStartAll = details?.validityStart ?? '';

		for (let i = 0; i < validRows.length; i++) {
			const row = validRows[i];

			// Calculate cell position in mm
			const cellX_mm = PAGE_SETTINGS.margin + currentCol * gridLayout.cellWidth;
			const cellY_mm = PAGE_SETTINGS.margin + currentRow * gridLayout.cellHeight;

			// Get field values
			const name = row.name;
			const nationality = row.nationality;
			const birthday = row.birthday;
			const studiesAt = studiesAtAll;
			const esnSection = esnSectionAll;
			const validityStart = validityStartAll;
			const birthdayFmt = formatDateDDMMYY(birthday);
			const validityStartFmt = formatDateDDMMYY(validityStart);

			// Row 1: Name
			const namePos = getAbsolutePositionPt(
				cellX_mm,
				cellY_mm,
				PAGE_SETTINGS.pageHeight,
				card.textFields.name
			);
			page.drawText(`${name}`, {
				...namePos,
				font,
				color: rgb(TEXT_CONFIG.color.r, TEXT_CONFIG.color.g, TEXT_CONFIG.color.b)
			});

			// Row 2 left: Nationality
			const natPos = getAbsolutePositionPt(
				cellX_mm,
				cellY_mm,
				PAGE_SETTINGS.pageHeight,
				card.textFields.nationality
			);
			page.drawText(`${nationality}`, {
				...natPos,
				font,
				color: rgb(TEXT_CONFIG.color.r, TEXT_CONFIG.color.g, TEXT_CONFIG.color.b)
			});

			// Row 2 right: Date of birth
			const bdayPos = getAbsolutePositionPt(
				cellX_mm,
				cellY_mm,
				PAGE_SETTINGS.pageHeight,
				card.textFields.birthday
			);
			// Row 3: Studies at
			const studiesPos = getAbsolutePositionPt(
				cellX_mm,
				cellY_mm,
				PAGE_SETTINGS.pageHeight,
				card.textFields.studiesAt
			);
			page.drawText(`${studiesAt}`, {
				...studiesPos,
				font,
				color: rgb(TEXT_CONFIG.color.r, TEXT_CONFIG.color.g, TEXT_CONFIG.color.b)
			});

			// Row 4 left: ESN Section
			const sectionPos = getAbsolutePositionPt(
				cellX_mm,
				cellY_mm,
				PAGE_SETTINGS.pageHeight,
				card.textFields.esnSection
			);
			page.drawText(`${esnSection}`, {
				...sectionPos,
				font,
				color: rgb(TEXT_CONFIG.color.r, TEXT_CONFIG.color.g, TEXT_CONFIG.color.b)
			});

			// Row 4 right: Valid from
			const validPos = getAbsolutePositionPt(
				cellX_mm,
				cellY_mm,
				PAGE_SETTINGS.pageHeight,
				card.textFields.validityStart
			);
			page.drawText(`${validityStartFmt}`, {
				...validPos,
				font,
				color: rgb(TEXT_CONFIG.color.r, TEXT_CONFIG.color.g, TEXT_CONFIG.color.b)
			});
			page.drawText(`${birthdayFmt}`, {
				...bdayPos,
				font,
				color: rgb(TEXT_CONFIG.color.r, TEXT_CONFIG.color.g, TEXT_CONFIG.color.b)
			});

			// Draw cell border in points
			page.drawRectangle({
				x: cellX_mm * MM_TO_PT,
				y: pageDimsPt.height - (cellY_mm + gridLayout.cellHeight) * MM_TO_PT,
				width: gridLayout.cellWidth * MM_TO_PT,
				height: gridLayout.cellHeight * MM_TO_PT,
				borderColor: rgb(BORDER_CONFIG.color.r, BORDER_CONFIG.color.g, BORDER_CONFIG.color.b),
				borderWidth: BORDER_CONFIG.width
			});

			// Move to next cell
			currentCol++;
			if (currentCol >= gridLayout.cols) {
				currentCol = 0;
				currentRow++;
				if (currentRow >= gridLayout.rows) {
					page = pdfDoc.addPage([pageDimsPt.width, pageDimsPt.height]);
					drawHMarks(page, font, PAGE_SETTINGS);
					currentRow = 0;
				}
			}
		}

		return await pdfDoc.save();
	}

	async function generatePhotoPDF() {
		const card = $selectedCard;
		if (!card) throw new Error('No card type selected');

		const pdfDoc = await PDFDocument.create();
		pdfDoc.registerFontkit(fontkit);

		const robotoFontBytes = await loadRobotoFont();
		const font = robotoFontBytes
			? await pdfDoc.embedFont(robotoFontBytes)
			: await pdfDoc.embedFont(StandardFonts.TimesRoman);

		const gridLayout = calculateGrid(
			PAGE_SETTINGS.pageWidth,
			PAGE_SETTINGS.pageHeight,
			PAGE_SETTINGS.margin,
			card.photoCard.width,
			card.photoCard.height
		);
		const pageDimsPt = {
			width: PAGE_SETTINGS.pageWidth * MM_TO_PT,
			height: PAGE_SETTINGS.pageHeight * MM_TO_PT
		};

		let page = pdfDoc.addPage([pageDimsPt.width, pageDimsPt.height]);
		drawHMarks(page, font, PAGE_SETTINGS);
		let currentRow = 0;
		let currentCol = 0;

		const validRows = $sheetData.filter((row) => row._valid);

		for (let i = 0; i < validRows.length; i++) {
			const row = validRows[i];

			// Calculate cell position in mm
			const cellX_mm = PAGE_SETTINGS.margin + currentCol * gridLayout.cellWidth;
			const cellY_mm = PAGE_SETTINGS.margin + currentRow * gridLayout.cellHeight;

			// Get photo dimensions in points
			const photoDimsPt = getAbsolutePhotoDimensionsPt(
				cellX_mm,
				cellY_mm,
				PAGE_SETTINGS.pageHeight,
				card.photoFields.photo
			);

			const pictureUrl = row.pictureUrl;
			const pictureInfo = $pictures[pictureUrl];
			const cropData = $cropRects[pictureUrl];

			if (pictureInfo && cropData) {
				try {
					// Get blob from IndexedDB instead of the store
					const imageBlob = await getImageBlob(pictureUrl);
					if (imageBlob) {
						const croppedImageBytes = await cropImage(imageBlob, cropData);
						const embeddedImage = await pdfDoc.embedJpg(croppedImageBytes);

						const imageAspectRatio = embeddedImage.width / embeddedImage.height;
						const photoBoxAspectRatio = photoDimsPt.width / photoDimsPt.height;

						let imageWidth, imageHeight;
						if (imageAspectRatio > photoBoxAspectRatio) {
							imageWidth = photoDimsPt.width;
							imageHeight = photoDimsPt.width / imageAspectRatio;
						} else {
							imageHeight = photoDimsPt.height;
							imageWidth = photoDimsPt.height * imageAspectRatio;
						}

						const imageX = photoDimsPt.x + (photoDimsPt.width - imageWidth) / 2;
						const imageY = photoDimsPt.y + (photoDimsPt.height - imageHeight) / 2;

						page.drawImage(embeddedImage, {
							x: imageX,
							y: imageY,
							width: imageWidth,
							height: imageHeight
						});
					} else {
						console.warn(`Image blob not found in IndexedDB for ${pictureUrl}`);
						// Draw placeholder when blob not found
						page.drawRectangle({
							...photoDimsPt,
							borderColor: rgb(BORDER_CONFIG.color.r, BORDER_CONFIG.color.g, BORDER_CONFIG.color.b),
							borderWidth: BORDER_CONFIG.width
						});
					}
				} catch (error: any) {
					console.error(`Failed to embed photo for ${row.name}:`, error);
					// Draw placeholder on error
					page.drawRectangle({
						...photoDimsPt,
						borderColor: rgb(BORDER_CONFIG.color.r, BORDER_CONFIG.color.g, BORDER_CONFIG.color.b),
						borderWidth: BORDER_CONFIG.width
					});
				}
			} else {
				// Draw placeholder if no photo
				page.drawRectangle({
					...photoDimsPt,
					borderColor: rgb(BORDER_CONFIG.color.r, BORDER_CONFIG.color.g, BORDER_CONFIG.color.b),
					borderWidth: BORDER_CONFIG.width
				});
			}

			// Draw name
			const name = row.name;
			const namePos = getAbsolutePositionPt(
				cellX_mm,
				cellY_mm,
				PAGE_SETTINGS.pageHeight,
				card.photoFields.name
			);
			page.drawText(`${name}`, {
				...namePos,
				font,
				color: rgb(TEXT_CONFIG.color.r, TEXT_CONFIG.color.g, TEXT_CONFIG.color.b)
			});

			// Move to next cell
			currentCol++;
			if (currentCol >= gridLayout.cols) {
				currentCol = 0;
				currentRow++;
				if (currentRow >= gridLayout.rows) {
					page = pdfDoc.addPage([pageDimsPt.width, pageDimsPt.height]);
					drawHMarks(page, font, PAGE_SETTINGS);
					currentRow = 0;
				}
			}
		}

		return await pdfDoc.save();
	}

	function downloadFile(file: GeneratedFile) {
		if (!file.url) return;
		const link = document.createElement('a');
		link.href = file.url;
		link.download = file.downloadName || file.name;
		document.body.appendChild(link);
		link.click();
		document.body.removeChild(link);
	}

	function resetAndStartOver() {
		files.forEach((file) => {
			if (file.url) {
				URL.revokeObjectURL(file.url);
			}
		});
		files = JSON.parse(JSON.stringify(initialFiles));

		// Clear sensitive data when starting over
		clearSensitiveData();

		currentStep.set(0);
	}

	function formatFileSize(bytes: number | null): string {
		if (bytes === null || bytes === 0) return '0 Bytes';
		const k = 1024;
		const sizes = ['Bytes', 'KB', 'MB', 'GB'];
		const i = Math.floor(Math.log(bytes) / Math.log(k));
		return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
	}
</script>

<div class="p-6">
	<div class="max-w-5xl mx-auto">
		<div class="mb-6">
			<h2 class="text-xl font-semibold text-gray-900 mb-2">Generating PDFs...</h2>
			<p class="text-sm text-gray-700 mb-4">
				Your PDF documents are being created. Please wait a moment.
			</p>
		</div>

		{#if files.some((f) => f.state === 'generating')}
			<div class="mb-6 rounded-lg border border-blue-200 bg-blue-50 p-4">
				<div class="flex items-center justify-between">
					<div class="flex items-center">
						<div
							class="mr-3 h-5 w-5 animate-spin rounded-full border-2 border-blue-600 border-t-transparent"
						></div>
						<span class="text-sm text-blue-800"> Processing... </span>
					</div>
				</div>
			</div>
		{/if}

		{#if generationStarted}
			<!-- Generated Files -->
			<div class="bg-white border border-gray-200 rounded-lg overflow-hidden mb-6">
				<div class="p-4 border-b border-gray-200">
					<h3 class="text-lg font-medium text-gray-900">Available Downloads</h3>
				</div>

				<div class="divide-y divide-gray-200">
					{#each files as file (file.name)}
						<div class="p-4 flex items-center justify-between">
							<div class="flex items-center">
								{#if file.displayName === 'Text PDF'}
									<svg
										class="w-8 h-8 text-red-600 mr-3"
										viewBox="0 0 24 24"
										fill="none"
										stroke="currentColor"
										stroke-width="2"
										stroke-linecap="round"
										stroke-linejoin="round"
									>
										<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
										<polyline points="14 2 14 8 20 8"></polyline>
										<line x1="12" y1="18" x2="12" y2="12"></line>
										<line x1="9" y1="12" x2="15" y2="12"></line>
									</svg>
								{:else if file.displayName === 'Photos PDF'}
									<svg
										class="w-8 h-8 text-red-600 mr-3"
										viewBox="0 0 24 24"
										fill="none"
										stroke="currentColor"
										stroke-width="2"
										stroke-linecap="round"
										stroke-linejoin="round"
									>
										<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
										<polyline points="14 2 14 8 20 8"></polyline>
										<circle cx="12" cy="13" r="2"></circle>
										<path d="M15 17.5c-1.5-1-4.5-1-6 0"></path>
									</svg>
								{/if}
								<div>
									<h4 class="text-sm font-medium text-gray-900">{file.displayName}</h4>
									{#if file.state === 'done' && file.size}
										<p class="text-xs text-gray-500">{formatFileSize(file.size)}</p>
									{:else if file.state === 'error'}
										<p class="text-xs text-red-500">Error: {file.error}</p>
									{:else if file.state === 'generating'}
										<p class="text-xs text-gray-500">Generating...</p>
									{:else if file.state === 'idle'}
										<p class="text-xs text-gray-500">Waiting...</p>
									{/if}
								</div>
							</div>

							{#if file.state === 'idle'}
								<div class="px-4 py-2 text-gray-500 text-sm">Waiting...</div>
							{:else if file.state === 'generating'}
								<button
									disabled
									aria-label="Generating..."
									class="px-4 py-2 bg-gray-400 text-white rounded-md text-sm font-medium cursor-wait"
								>
									<div class="flex items-center justify-center">
										<div
											class="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"
										></div>
									</div>
								</button>
							{:else if file.state === 'done'}
								<button
									onclick={() => downloadFile(file)}
									class="px-4 py-2 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700"
								>
									Download
								</button>
							{:else if file.state === 'error'}
								<button
									onclick={() => handleGenerate(file.name)}
									class="px-4 py-2 bg-red-600 text-white rounded-md text-sm font-medium hover:bg-red-700"
								>
									Retry
								</button>
							{/if}
						</div>
					{/each}
				</div>
			</div>
		{/if}

		<!-- Navigation -->
		<div class="mt-10">
			<Navigator
				{currentStep}
				onForward={resetAndStartOver}
				canProceed={files.some((f) => f.state === 'done' || f.state === 'error')}
				textBack="Back to Gallery"
				textForwardEnabled="Start Over"
				textForwardDisabled="Generate PDFs to Continue"
				hideForwardUntilProceedable={true}
			/>
		</div>
	</div>
</div>
