<script lang="ts">
	import { goto } from '$app/navigation';
	import {
		uploadFile,
		applyMapping,
		fetchPreview,
		confirmImport,
		fetchImportStatus,
		fetchImportReport,
		type UploadResult,
		type PreviewResult,
		type ImportStatus,
		type ImportReport
	} from '$lib/features/import/api/studentImport';

	// === Wizard Steps ===
	type WizardStep = 'upload' | 'mapping' | 'preview' | 'confirmation';
	const STEPS: { key: WizardStep; label: string }[] = [
		{ key: 'upload', label: 'Upload' },
		{ key: 'mapping', label: 'Mapping' },
		{ key: 'preview', label: 'Aperçu' },
		{ key: 'confirmation', label: 'Import' }
	];

	let currentStep = $state<WizardStep>('upload');
	let currentStepIndex = $derived(STEPS.findIndex((s) => s.key === currentStep));

	// === Global state ===
	let error = $state<string | null>(null);
	let batchId = $state<string | null>(null);

	// === Step 1: Upload ===
	let isDragOver = $state(false);
	let isUploading = $state(false);
	let uploadResult = $state<UploadResult | null>(null);
	let fileInput = $state<HTMLInputElement>();

	// === Step 2: Mapping ===
	let mapping = $state<Record<string, string>>({});
	let detectedFormat = $state('custom');
	let isSavingMapping = $state(false);

	const CLASSEO_FIELDS: { value: string; label: string; required: boolean }[] = [
		{ value: 'lastName', label: 'Nom', required: true },
		{ value: 'firstName', label: 'Prénom', required: true },
		{ value: 'fullName', label: 'Nom complet (NOM Prénom)', required: false },
		{ value: 'className', label: 'Classe', required: true },
		{ value: 'email', label: 'Email', required: false },
		{ value: 'birthDate', label: 'Date de naissance', required: false },
		{ value: 'gender', label: 'Genre', required: false },
		{ value: 'studentNumber', label: 'Numéro élève', required: false }
	];

	let requiredFieldsMapped = $derived(() => {
		const mappedValues = Object.values(mapping);
		const hasFullName = mappedValues.includes('fullName');

		return CLASSEO_FIELDS.filter((f) => f.required).every((f) => {
			if (hasFullName && (f.value === 'lastName' || f.value === 'firstName')) {
				return true;
			}
			return mappedValues.includes(f.value);
		});
	});

	// === Step 3: Preview ===
	let isLoadingPreview = $state(false);
	let previewResult = $state<PreviewResult | null>(null);
	let createMissingClasses = $state(false);
	let importValidOnly = $state(true);

	// Adjusted preview rows: when createMissingClasses is checked, treat class-not-found errors as resolved
	let adjustedPreviewRows = $derived.by(() => {
		if (!previewResult) return [];
		if (!createMissingClasses) return previewResult.rows;
		return previewResult.rows.map((row) => {
			if (row.valid) return row;
			const remainingErrors = row.errors.filter((e) => e.column !== 'className');
			return { ...row, valid: remainingErrors.length === 0, errors: remainingErrors };
		});
	});
	let adjustedValidCount = $derived(adjustedPreviewRows.filter((r) => r.valid).length);
	let adjustedErrorCount = $derived(adjustedPreviewRows.filter((r) => !r.valid).length);
	let duplicateCount = $derived(
		adjustedPreviewRows.filter((r) => r.errors.some((e) => e.column === '_duplicate')).length
	);

	// === Step 4: Confirmation ===
	let isConfirming = $state(false);
	let importStatus = $state<ImportStatus | null>(null);
	let importReport = $state<ImportReport | null>(null);
	let pollingInterval = $state<ReturnType<typeof setInterval> | null>(null);

	// === Upload handlers ===
	function handleDragOver(e: DragEvent) {
		e.preventDefault();
		isDragOver = true;
	}

	function handleDragLeave() {
		isDragOver = false;
	}

	function handleDrop(e: DragEvent) {
		e.preventDefault();
		isDragOver = false;

		const file = e.dataTransfer?.files[0];
		if (file) processFile(file);
	}

	function handleFileSelect() {
		const file = fileInput?.files?.[0];
		if (file) processFile(file);
	}

	async function processFile(file: File) {
		const extension = file.name.split('.').pop()?.toLowerCase();
		if (!['csv', 'txt', 'xlsx', 'xls'].includes(extension ?? '')) {
			error = 'Format non supporté. Utilisez CSV ou XLSX.';
			return;
		}

		if (file.size > 10 * 1024 * 1024) {
			error = 'Le fichier dépasse la taille maximale de 10 Mo.';
			return;
		}

		try {
			isUploading = true;
			error = null;

			const result = await uploadFile(file);
			uploadResult = result;
			batchId = result.id;
			detectedFormat = result.detectedFormat;

			// Initialize mapping from suggested
			mapping = { ...result.suggestedMapping };

			currentStep = 'mapping';
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur lors de l\'upload';
		} finally {
			isUploading = false;
			if (fileInput) fileInput.value = '';
		}
	}

	// === Mapping handlers ===
	function handleMappingChange(column: string, field: string) {
		if (field === '') {
			const newMapping = { ...mapping };
			delete newMapping[column];
			mapping = newMapping;
		} else {
			// Remove this field from other columns first
			const newMapping: Record<string, string> = {};
			for (const [col, val] of Object.entries(mapping)) {
				if (val !== field) {
					newMapping[col] = val;
				}
			}
			newMapping[column] = field;
			mapping = newMapping;
		}
	}

	function getFieldForColumn(column: string): string {
		return mapping[column] ?? '';
	}

	function isFieldUsed(fieldValue: string, excludeColumn: string): boolean {
		return Object.entries(mapping).some(
			([col, val]) => val === fieldValue && col !== excludeColumn
		);
	}

	function isFieldMapped(fieldValue: string): boolean {
		return Object.values(mapping).includes(fieldValue);
	}

	// === Drag & Drop mapping ===
	let draggedField = $state<string | null>(null);
	let dropTargetColumn = $state<string | null>(null);

	function handleFieldDragStart(e: DragEvent, fieldValue: string) {
		draggedField = fieldValue;
		e.dataTransfer?.setData('text/plain', fieldValue);
		if (e.dataTransfer) e.dataTransfer.effectAllowed = 'move';
	}

	function handleFieldDragEnd() {
		draggedField = null;
		dropTargetColumn = null;
	}

	function handleMappingRowDragOver(e: DragEvent, column: string) {
		e.preventDefault();
		if (e.dataTransfer) e.dataTransfer.dropEffect = 'move';
		dropTargetColumn = column;
	}

	function handleMappingRowDragLeave(column: string) {
		if (dropTargetColumn === column) dropTargetColumn = null;
	}

	function handleMappingRowDrop(e: DragEvent, column: string) {
		e.preventDefault();
		dropTargetColumn = null;
		const fieldValue = e.dataTransfer?.getData('text/plain');
		if (fieldValue) handleMappingChange(column, fieldValue);
	}

	async function submitMapping() {
		if (!batchId) return;

		try {
			isSavingMapping = true;
			error = null;

			await applyMapping(batchId, mapping, detectedFormat);

			// Load preview
			isLoadingPreview = true;
			const preview = await fetchPreview(batchId);
			previewResult = preview;

			currentStep = 'preview';
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur lors du mapping';
		} finally {
			isSavingMapping = false;
			isLoadingPreview = false;
		}
	}

	// === Preview handlers ===
	async function launchImport() {
		if (!batchId) return;

		try {
			isConfirming = true;
			error = null;

			await confirmImport(batchId, {
				createMissingClasses,
				importValidOnly
			});

			currentStep = 'confirmation';

			// Start polling for progress
			startPolling();
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur lors de la confirmation';
		} finally {
			isConfirming = false;
		}
	}

	// === Progress polling ===
	const MAX_POLL_COUNT = 300; // 5 minutes at 1s interval
	let pollCount = $state(0);

	function startPolling() {
		if (!batchId) return;

		pollCount = 0;
		const id = batchId;
		pollingInterval = setInterval(async () => {
			pollCount++;
			if (pollCount >= MAX_POLL_COUNT) {
				stopPolling();
				error = 'L\'import semble prendre trop de temps. Vérifiez le statut ultérieurement.';
				return;
			}

			try {
				const status = await fetchImportStatus(id);
				importStatus = status;

				if (status.status === 'completed' || status.status === 'failed') {
					stopPolling();
					const report = await fetchImportReport(id);
					importReport = report;
				}
			} catch {
				// Polling errors are silent
			}
		}, 1000);
	}

	function stopPolling() {
		if (pollingInterval) {
			clearInterval(pollingInterval);
			pollingInterval = null;
		}
	}

	// === Navigation ===
	function goBack() {
		if (currentStep === 'mapping') {
			currentStep = 'upload';
			uploadResult = null;
			batchId = null;
		} else if (currentStep === 'preview') {
			currentStep = 'mapping';
			previewResult = null;
		}
	}

	function resetWizard() {
		stopPolling();
		currentStep = 'upload';
		uploadResult = null;
		batchId = null;
		mapping = {};
		previewResult = null;
		importStatus = null;
		importReport = null;
		error = null;
		pollCount = 0;
	}

	function downloadReport() {
		if (!importReport) return;

		const lines = [
			`Rapport d'import - ${new Date().toLocaleDateString('fr-FR')}`,
			'',
			`Total : ${importReport.totalRows} lignes`,
			`Importés : ${importReport.importedCount} élèves`,
			`Erreurs : ${importReport.errorCount}`,
			'',
			...importReport.report,
			''
		];

		if (importReport.errors.length > 0) {
			lines.push('--- Détail des erreurs ---', '');
			for (const err of importReport.errors) {
				for (const e of err.errors) {
					lines.push(`Ligne ${err.line} : ${e.column} - ${e.message}`);
				}
			}
		}

		const blob = new Blob([lines.join('\n')], { type: 'text/plain;charset=utf-8' });
		const url = URL.createObjectURL(blob);
		const a = document.createElement('a');
		a.href = url;
		a.download = `rapport-import-${batchId}.txt`;
		a.click();
		URL.revokeObjectURL(url);
	}
</script>

<svelte:head>
	<title>Import élèves - Classeo</title>
</svelte:head>

<div class="page">
	<!-- Header -->
	<header class="page-header">
		<div>
			<h1>Import d'élèves</h1>
			<p class="subtitle">Importez vos élèves depuis un fichier CSV ou Excel</p>
		</div>
		<a href="/admin/students" class="btn-secondary">
			Retour aux élèves
		</a>
	</header>

	<!-- Stepper -->
	<nav class="stepper" aria-label="Étapes de l'import">
		{#each STEPS as step, i}
			<div class="step" class:active={i === currentStepIndex} class:completed={i < currentStepIndex}>
				<div class="step-number">
					{#if i < currentStepIndex}
						<svg viewBox="0 0 20 20" fill="currentColor" class="check-icon" aria-hidden="true">
							<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
						</svg>
					{:else}
						{i + 1}
					{/if}
				</div>
				<span class="step-label">{step.label}</span>
				{#if i < STEPS.length - 1}
					<div class="step-connector" class:completed={i < currentStepIndex}></div>
				{/if}
			</div>
		{/each}
	</nav>

	<!-- Error alert -->
	{#if error}
		<div class="alert alert-error" role="alert">
			{error}
			<button class="alert-close" onclick={() => (error = null)} aria-label="Fermer">x</button>
		</div>
	{/if}

	<!-- Step 1: Upload -->
	{#if currentStep === 'upload'}
		<div class="step-content">
			<div
				class="dropzone"
				class:dragover={isDragOver}
				class:uploading={isUploading}
				ondragover={handleDragOver}
				ondragleave={handleDragLeave}
				ondrop={handleDrop}
				onclick={() => fileInput?.click()}
				role="button"
				tabindex="0"
				aria-label="Zone de dépôt de fichier"
				onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') fileInput?.click(); }}
			>
				{#if isUploading}
					<div class="upload-loading">
						<div class="spinner"></div>
						<p>Analyse du fichier en cours...</p>
					</div>
				{:else}
					<div class="dropzone-content">
						<svg class="dropzone-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
							<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" />
						</svg>
						<p class="dropzone-title">Glissez votre fichier ici</p>
						<p class="dropzone-subtitle">ou cliquez pour parcourir</p>
						<p class="dropzone-hint">CSV, XLSX - Max 10 Mo</p>
					</div>
				{/if}

				<input
					type="file"
					accept=".csv,.txt,.xlsx,.xls"
					bind:this={fileInput}
					onchange={handleFileSelect}
					hidden
					aria-hidden="true"
				/>
			</div>

			<!-- File format help -->
			<div class="format-help">
				<h3>Formats supportés</h3>
				<div class="format-cards">
					<div class="format-card">
						<strong>Pronote</strong>
						<p>Export élèves depuis Pronote (CSV avec colonnes Nom de l'élève, Prénom, Classe...)</p>
					</div>
					<div class="format-card">
						<strong>EcoleDirecte</strong>
						<p>Export depuis EcoleDirecte (CSV avec colonnes NOM, PRENOM, CLASSE...)</p>
					</div>
					<div class="format-card">
						<strong>Personnalisé</strong>
						<p>Tout fichier CSV ou Excel avec au minimum : Nom, Prénom, Classe</p>
					</div>
				</div>
			</div>
		</div>
	{/if}

	<!-- Step 2: Mapping -->
	{#if currentStep === 'mapping'}
		<div class="step-content">
			{#if uploadResult}
				<div class="mapping-header">
					<div class="file-info">
						<strong>{uploadResult.filename}</strong> - {uploadResult.totalRows} lignes détectées
						{#if detectedFormat !== 'custom'}
							<span class="format-badge">
								Format {detectedFormat === 'pronote' ? 'Pronote' : 'EcoleDirecte'} détecté
							</span>
						{/if}
					</div>
				</div>

				<!-- Preview of first rows -->
				{#if uploadResult.preview.length > 0}
					<div class="preview-section">
						<h3>Aperçu des données ({Math.min(5, uploadResult.preview.length)} premières lignes)</h3>
						<div class="table-scroll">
							<table class="preview-table">
								<thead>
									<tr>
										<th>#</th>
										{#each uploadResult.columns as col}
											<th>{col}</th>
										{/each}
									</tr>
								</thead>
								<tbody>
									{#each uploadResult.preview.slice(0, 5) as row}
										<tr>
											<td class="row-num">{row.line}</td>
											{#each uploadResult.columns as col}
												<td>{row.data[mapping[col] ?? ''] ?? Object.values(row.data)[uploadResult.columns.indexOf(col)] ?? ''}</td>
											{/each}
										</tr>
									{/each}
								</tbody>
							</table>
						</div>
					</div>
				{/if}

				<!-- Column mapping -->
				<div class="mapping-section">
					<h3>Association des colonnes</h3>
					<p class="mapping-hint">Glissez-déposez les champs Classeo sur les colonnes de votre fichier, ou utilisez les menus déroulants. Les champs marqués * sont obligatoires.</p>

					<!-- Draggable field palette -->
					<div class="field-palette">
						<span class="palette-label">Champs Classeo :</span>
						<div class="palette-chips">
							{#each CLASSEO_FIELDS as field}
								<span
									class="field-chip"
									class:mapped={isFieldMapped(field.value)}
									class:required={field.required}
									class:dragging={draggedField === field.value}
									draggable={!isFieldMapped(field.value)}
									ondragstart={(e) => handleFieldDragStart(e, field.value)}
									ondragend={handleFieldDragEnd}
									role="button"
									tabindex={isFieldMapped(field.value) ? -1 : 0}
									aria-label="{field.label}{field.required ? ' (obligatoire)' : ''}"
								>
									{field.label}{field.required ? ' *' : ''}
								</span>
							{/each}
						</div>
					</div>

					<div class="mapping-grid">
						{#each uploadResult.columns as column}
							<div
								class="mapping-row"
								class:drop-target={dropTargetColumn === column}
								ondragover={(e) => handleMappingRowDragOver(e, column)}
								ondragleave={() => handleMappingRowDragLeave(column)}
								ondrop={(e) => handleMappingRowDrop(e, column)}
							>
								<div class="mapping-source">
									<span class="column-name">{column}</span>
								</div>
								<div class="mapping-arrow">
									<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
										<path fill-rule="evenodd" d="M3 10a.75.75 0 01.75-.75h10.638L10.23 5.29a.75.75 0 111.04-1.08l5.5 5.25a.75.75 0 010 1.08l-5.5 5.25a.75.75 0 11-1.04-1.08l4.158-3.96H3.75A.75.75 0 013 10z" clip-rule="evenodd" />
									</svg>
								</div>
								<div class="mapping-target">
									<select
										value={getFieldForColumn(column)}
										onchange={(e) => handleMappingChange(column, (e.target as HTMLSelectElement).value)}
									>
										<option value="">-- Ignorer --</option>
										{#each CLASSEO_FIELDS as field}
											<option
												value={field.value}
												disabled={isFieldUsed(field.value, column)}
											>
												{field.label}{field.required ? ' *' : ''}
												{#if isFieldUsed(field.value, column)} (déjà associé){/if}
											</option>
										{/each}
									</select>
								</div>
							</div>
						{/each}
					</div>

					{#if !requiredFieldsMapped}
						<p class="mapping-warning">
							Tous les champs obligatoires (*) doivent être associés pour continuer.
						</p>
					{/if}
				</div>

				<div class="step-actions">
					<button class="btn-secondary" onclick={goBack}>
						Retour
					</button>
					<button
						class="btn-primary"
						onclick={submitMapping}
						disabled={!requiredFieldsMapped || isSavingMapping}
					>
						{#if isSavingMapping}
							Validation...
						{:else}
							Valider le mapping
						{/if}
					</button>
				</div>
			{/if}
		</div>
	{/if}

	<!-- Step 3: Preview -->
	{#if currentStep === 'preview'}
		<div class="step-content">
			{#if isLoadingPreview}
				<div class="loading-state">
					<div class="spinner"></div>
					<p>Validation des données en cours...</p>
				</div>
			{:else if previewResult}
				<!-- Summary -->
				<div class="preview-summary">
					<div class="summary-card valid">
						<span class="summary-number">{adjustedValidCount}</span>
						<span class="summary-label">Lignes valides</span>
					</div>
					<div class="summary-card error">
						<span class="summary-number">{adjustedErrorCount}</span>
						<span class="summary-label">Lignes en erreur</span>
					</div>
					{#if duplicateCount > 0}
						<div class="summary-card duplicate">
							<span class="summary-number">{duplicateCount}</span>
							<span class="summary-label">Doublons détectés</span>
						</div>
					{/if}
					<div class="summary-card total">
						<span class="summary-number">{previewResult.totalRows}</span>
						<span class="summary-label">Total</span>
					</div>
				</div>

				<!-- Unknown classes -->
				{#if previewResult.unknownClasses.length > 0}
					<div class="unknown-classes" class:resolved={createMissingClasses}>
						{#if createMissingClasses}
							<h3>Classes qui seront créées</h3>
							<p>Les classes suivantes seront créées automatiquement lors de l'import :</p>
						{:else}
							<h3>Classes non trouvées</h3>
							<p>Les classes suivantes n'existent pas encore dans Classeo :</p>
						{/if}
						<div class="class-tags">
							{#each previewResult.unknownClasses as cls}
								<span class="class-tag">{cls}</span>
							{/each}
						</div>
						<label class="checkbox-label">
							<input type="checkbox" bind:checked={createMissingClasses} />
							Créer automatiquement ces classes
						</label>
					</div>
				{/if}

				<!-- Import options -->
				{#if adjustedErrorCount > 0}
					<div class="import-options">
						<label class="radio-label">
							<input type="radio" name="importMode" value={true} bind:group={importValidOnly} />
							Importer uniquement les {adjustedValidCount} lignes valides
						</label>
						<label class="radio-label">
							<input type="radio" name="importMode" value={false} bind:group={importValidOnly} />
							Tenter d'importer toutes les lignes ({previewResult.totalRows})
						</label>
					</div>
				{/if}

				<!-- Data table -->
				<div class="preview-table-section">
					<h3>Détail des données</h3>
					<div class="table-scroll">
						<table class="preview-table">
							<thead>
								<tr>
									<th>Ligne</th>
									<th>Nom</th>
									<th>Prénom</th>
									<th>Classe</th>
									<th>Email</th>
									<th>Statut</th>
								</tr>
							</thead>
							<tbody>
								{#each adjustedPreviewRows as row}
									<tr class:row-valid={row.valid} class:row-error={!row.valid}>
										<td>{row.line}</td>
										<td>{row.data['lastName'] ?? ''}</td>
										<td>{row.data['firstName'] ?? ''}</td>
										<td>{row.data['className'] ?? ''}</td>
										<td>{row.data['email'] ?? ''}</td>
										<td>
											{#if row.valid}
												<span class="status-badge status-valid">Valide</span>
											{:else}
												<span class="status-badge status-error" title={row.errors.map(e => `${e.column}: ${e.message}`).join(', ')}>
													Erreur
												</span>
											{/if}
										</td>
									</tr>
									{#if !row.valid}
										<tr class="error-detail-row">
											<td colspan="6">
												{#each row.errors as err}
													<span class="error-detail">{err.column} : {err.message}</span>
												{/each}
											</td>
										</tr>
									{/if}
								{/each}
							</tbody>
						</table>
					</div>
				</div>

				<div class="step-actions">
					<button class="btn-secondary" onclick={goBack}>
						Retour au mapping
					</button>
					<button class="btn-text" onclick={resetWizard}>
						Recommencer
					</button>
					<button
						class="btn-primary"
						onclick={launchImport}
						disabled={isConfirming || (adjustedValidCount === 0 && importValidOnly)}
					>
						{#if isConfirming}
							Lancement...
						{:else}
							Lancer l'import ({importValidOnly ? adjustedValidCount : previewResult.totalRows} élèves)
						{/if}
					</button>
				</div>
			{/if}
		</div>
	{/if}

	<!-- Step 4: Confirmation -->
	{#if currentStep === 'confirmation'}
		<div class="step-content">
			{#if importStatus?.status === 'completed' || importStatus?.status === 'failed'}
				<!-- Final report -->
				<div class="import-report">
					{#if importStatus.status === 'completed'}
						<div class="report-header success">
							<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="report-icon" aria-hidden="true">
								<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
							</svg>
							<h2>Import terminé</h2>
						</div>
					{:else}
						<div class="report-header failure">
							<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="report-icon" aria-hidden="true">
								<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
							</svg>
							<h2>Import échoué</h2>
						</div>
					{/if}

					<div class="report-stats">
						<div class="stat">
							<span class="stat-value">{importStatus.importedCount}</span>
							<span class="stat-label">élèves importés</span>
						</div>
						<div class="stat">
							<span class="stat-value">{importStatus.errorCount}</span>
							<span class="stat-label">erreurs</span>
						</div>
					</div>

					{#if importReport}
						<!-- Report lines -->
						{#if importReport.report.length > 0}
							<div class="report-details">
								<h3>Rapport</h3>
								<ul>
									{#each importReport.report as line}
										<li>{line}</li>
									{/each}
								</ul>
							</div>
						{/if}

						<!-- Error details -->
						{#if importReport.errors.length > 0}
							<div class="report-errors">
								<h3>Détail des erreurs</h3>
								<div class="table-scroll">
									<table class="preview-table">
										<thead>
											<tr>
												<th>Ligne</th>
												<th>Erreur</th>
											</tr>
										</thead>
										<tbody>
											{#each importReport.errors as err}
												<tr>
													<td>{err.line}</td>
													<td>
														{#each err.errors as e}
															<span class="error-detail">{e.column} : {e.message}</span>
														{/each}
													</td>
												</tr>
											{/each}
										</tbody>
									</table>
								</div>
							</div>
						{/if}
					{/if}

					<div class="step-actions">
						{#if importReport}
							<button class="btn-secondary" onclick={downloadReport}>
								Télécharger le rapport
							</button>
						{/if}
						<button class="btn-primary" onclick={() => goto('/admin/students')}>
							Voir les élèves
						</button>
						<button class="btn-text" onclick={resetWizard}>
							Nouvel import
						</button>
					</div>
				</div>
			{:else}
				<!-- Progress -->
				<div class="import-progress">
					<div class="progress-header">
						<h2>Import en cours...</h2>
						<p>Veuillez patienter pendant l'import de vos élèves.</p>
					</div>

					<div class="progress-bar-container">
						<div
							class="progress-bar"
							style="width: {importStatus?.progression ?? 0}%"
							role="progressbar"
							aria-valuenow={importStatus?.progression ?? 0}
							aria-valuemin={0}
							aria-valuemax={100}
						></div>
					</div>
					<p class="progress-text">
						{importStatus?.progression ?? 0}%
						{#if importStatus}
							- {importStatus.importedCount + importStatus.errorCount} / {importStatus.totalRows} lignes traitées
						{/if}
					</p>
				</div>
			{/if}
		</div>
	{/if}
</div>

<style>
	.page {
		max-width: 960px;
		margin: 0 auto;
		padding: 1.5rem;
	}

	.page-header {
		display: flex;
		justify-content: space-between;
		align-items: flex-start;
		margin-bottom: 2rem;
	}

	.page-header h1 {
		font-size: 1.5rem;
		font-weight: 700;
		color: #111827;
		margin: 0;
	}

	.subtitle {
		color: #6b7280;
		font-size: 0.875rem;
		margin: 0.25rem 0 0;
	}

	/* === Stepper === */
	.stepper {
		display: flex;
		align-items: center;
		justify-content: center;
		gap: 0;
		margin-bottom: 2rem;
		padding: 1rem 0;
	}

	.step {
		display: flex;
		align-items: center;
		gap: 0.5rem;
	}

	.step-number {
		width: 2rem;
		height: 2rem;
		border-radius: 50%;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 0.875rem;
		font-weight: 600;
		background: #e5e7eb;
		color: #6b7280;
		flex-shrink: 0;
	}

	.step.active .step-number {
		background: var(--btn-primary-bg, #3b82f6);
		color: white;
	}

	.step.completed .step-number {
		background: #10b981;
		color: white;
	}

	.check-icon {
		width: 1rem;
		height: 1rem;
	}

	.step-label {
		font-size: 0.875rem;
		font-weight: 500;
		color: #6b7280;
		white-space: nowrap;
	}

	.step.active .step-label {
		color: #111827;
		font-weight: 600;
	}

	.step.completed .step-label {
		color: #10b981;
	}

	.step-connector {
		width: 3rem;
		height: 2px;
		background: #e5e7eb;
		margin: 0 0.5rem;
	}

	.step-connector.completed {
		background: #10b981;
	}

	/* === Alerts === */
	.alert {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 0.75rem;
		padding: 1rem;
		border-radius: 0.5rem;
		margin-bottom: 1rem;
	}

	.alert-error {
		background: #fef2f2;
		border: 1px solid #fecaca;
		color: #dc2626;
	}

	.alert-close {
		background: none;
		border: none;
		color: inherit;
		cursor: pointer;
		font-size: 1.25rem;
		padding: 0;
		line-height: 1;
	}

	/* === Dropzone === */
	.dropzone {
		border: 2px dashed #d1d5db;
		border-radius: 0.75rem;
		padding: 3rem 2rem;
		text-align: center;
		cursor: pointer;
		transition: all 0.2s;
		background: white;
	}

	.dropzone:hover,
	.dropzone.dragover {
		border-color: var(--btn-primary-bg, #3b82f6);
		background: #eff6ff;
	}

	.dropzone.uploading {
		cursor: wait;
		opacity: 0.8;
	}

	.dropzone-content {
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: 0.5rem;
	}

	.dropzone-icon {
		width: 3rem;
		height: 3rem;
		color: #9ca3af;
	}

	.dropzone.dragover .dropzone-icon {
		color: var(--btn-primary-bg, #3b82f6);
	}

	.dropzone-title {
		font-size: 1rem;
		font-weight: 600;
		color: #374151;
		margin: 0;
	}

	.dropzone-subtitle {
		font-size: 0.875rem;
		color: #6b7280;
		margin: 0;
	}

	.dropzone-hint {
		font-size: 0.75rem;
		color: #9ca3af;
		margin: 0.5rem 0 0;
	}

	.upload-loading {
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: 1rem;
	}

	.upload-loading p {
		color: #6b7280;
		margin: 0;
	}

	/* === Format help === */
	.format-help {
		margin-top: 2rem;
	}

	.format-help h3 {
		font-size: 1rem;
		font-weight: 600;
		color: #374151;
		margin: 0 0 1rem;
	}

	.format-cards {
		display: grid;
		grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
		gap: 1rem;
	}

	.format-card {
		padding: 1rem;
		border: 1px solid #e5e7eb;
		border-radius: 0.5rem;
		background: white;
	}

	.format-card strong {
		display: block;
		color: #111827;
		margin-bottom: 0.25rem;
	}

	.format-card p {
		font-size: 0.8125rem;
		color: #6b7280;
		margin: 0;
		line-height: 1.4;
	}

	/* === Mapping === */
	.step-content {
		background: white;
		border: 1px solid #e5e7eb;
		border-radius: 0.75rem;
		padding: 1.5rem;
	}

	.mapping-header {
		margin-bottom: 1.5rem;
	}

	.file-info {
		font-size: 0.875rem;
		color: #374151;
		display: flex;
		align-items: center;
		gap: 0.75rem;
		flex-wrap: wrap;
	}

	.format-badge {
		display: inline-block;
		padding: 0.125rem 0.5rem;
		background: #eff6ff;
		color: var(--btn-primary-bg, #3b82f6);
		border-radius: 9999px;
		font-size: 0.75rem;
		font-weight: 500;
	}

	.preview-section {
		margin-bottom: 1.5rem;
	}

	.preview-section h3,
	.mapping-section h3,
	.preview-table-section h3 {
		font-size: 0.9375rem;
		font-weight: 600;
		color: #374151;
		margin: 0 0 0.75rem;
	}

	.table-scroll {
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
	}

	.preview-table {
		width: 100%;
		border-collapse: collapse;
		font-size: 0.8125rem;
	}

	.preview-table th {
		text-align: left;
		padding: 0.5rem 0.75rem;
		font-weight: 600;
		color: #6b7280;
		text-transform: uppercase;
		letter-spacing: 0.05em;
		font-size: 0.6875rem;
		border-bottom: 1px solid #e5e7eb;
		background: #f9fafb;
		white-space: nowrap;
	}

	.preview-table td {
		padding: 0.5rem 0.75rem;
		color: #374151;
		border-bottom: 1px solid #f3f4f6;
	}

	.row-num {
		color: #9ca3af;
		font-size: 0.75rem;
	}

	/* === Field palette === */
	.field-palette {
		display: flex;
		align-items: flex-start;
		gap: 0.5rem;
		padding: 0.75rem;
		background: #f9fafb;
		border: 1px solid #e5e7eb;
		border-radius: 0.5rem;
		margin-bottom: 1rem;
		flex-wrap: wrap;
	}

	.palette-label {
		font-size: 0.8125rem;
		font-weight: 500;
		color: #6b7280;
		white-space: nowrap;
		padding-top: 0.25rem;
	}

	.palette-chips {
		display: flex;
		flex-wrap: wrap;
		gap: 0.375rem;
	}

	.field-chip {
		display: inline-block;
		padding: 0.25rem 0.625rem;
		border-radius: 0.375rem;
		font-size: 0.8125rem;
		font-weight: 500;
		background: white;
		border: 1px solid #d1d5db;
		color: #374151;
		cursor: grab;
		user-select: none;
		transition: all 0.15s;
	}

	.field-chip:hover:not(.mapped) {
		border-color: var(--btn-primary-bg, #3b82f6);
		background: #eff6ff;
	}

	.field-chip.required {
		border-color: #f59e0b;
	}

	.field-chip.mapped {
		opacity: 0.4;
		cursor: default;
		text-decoration: line-through;
	}

	.field-chip.dragging {
		opacity: 0.5;
	}

	/* === Mapping grid === */
	.mapping-hint {
		font-size: 0.8125rem;
		color: #6b7280;
		margin: 0 0 1rem;
	}

	.mapping-grid {
		display: flex;
		flex-direction: column;
		gap: 0.75rem;
	}

	.mapping-row {
		display: flex;
		align-items: center;
		gap: 0.75rem;
		padding: 0.375rem;
		border-radius: 0.375rem;
		border: 2px solid transparent;
		transition: border-color 0.15s, background 0.15s;
	}

	.mapping-row.drop-target {
		border-color: var(--btn-primary-bg, #3b82f6);
		background: #eff6ff;
	}

	.mapping-source {
		flex: 1;
		min-width: 0;
	}

	.column-name {
		display: inline-block;
		padding: 0.5rem 0.75rem;
		background: #f3f4f6;
		border-radius: 0.375rem;
		font-size: 0.875rem;
		font-weight: 500;
		color: #374151;
		width: 100%;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	.mapping-arrow {
		flex-shrink: 0;
		color: #9ca3af;
	}

	.mapping-arrow svg {
		width: 1.25rem;
		height: 1.25rem;
	}

	.mapping-target {
		flex: 1;
		min-width: 0;
	}

	.mapping-target select {
		width: 100%;
		padding: 0.5rem 0.75rem;
		border: 1px solid #d1d5db;
		border-radius: 0.375rem;
		font-size: 0.875rem;
		background: white;
		color: #374151;
	}

	.mapping-target select:focus {
		outline: none;
		border-color: var(--btn-primary-bg, #3b82f6);
		box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
	}

	.mapping-warning {
		margin: 1rem 0 0;
		font-size: 0.8125rem;
		color: #d97706;
		font-weight: 500;
	}

	/* === Preview summary === */
	.preview-summary {
		display: grid;
		grid-template-columns: repeat(3, 1fr);
		gap: 1rem;
		margin-bottom: 1.5rem;
	}

	.summary-card {
		display: flex;
		flex-direction: column;
		align-items: center;
		padding: 1rem;
		border-radius: 0.5rem;
		border: 1px solid #e5e7eb;
	}

	.summary-card.valid {
		background: #f0fdf4;
		border-color: #bbf7d0;
	}

	.summary-card.error {
		background: #fef2f2;
		border-color: #fecaca;
	}

	.summary-card.duplicate {
		background: #fffbeb;
		border-color: #fde68a;
	}

	.summary-card.total {
		background: #f9fafb;
	}

	.summary-number {
		font-size: 1.5rem;
		font-weight: 700;
		color: #111827;
	}

	.summary-card.valid .summary-number {
		color: #16a34a;
	}

	.summary-card.error .summary-number {
		color: #dc2626;
	}

	.summary-card.duplicate .summary-number {
		color: #d97706;
	}

	.summary-label {
		font-size: 0.75rem;
		color: #6b7280;
		text-transform: uppercase;
		letter-spacing: 0.05em;
	}

	/* === Row status === */
	.row-valid td {
		background: #f0fdf4;
	}

	.row-error td {
		background: #fef2f2;
	}

	.error-detail-row td {
		background: #fef2f2;
		padding: 0.25rem 0.75rem 0.5rem;
		border-bottom: 1px solid #fecaca;
	}

	.error-detail {
		display: inline-block;
		font-size: 0.75rem;
		color: #dc2626;
		margin-right: 1rem;
	}

	.status-badge {
		display: inline-block;
		padding: 0.125rem 0.5rem;
		border-radius: 9999px;
		font-size: 0.75rem;
		font-weight: 500;
	}

	.status-valid {
		background: #f0fdf4;
		color: #16a34a;
	}

	.status-error {
		background: #fef2f2;
		color: #dc2626;
	}

	/* === Unknown classes === */
	.unknown-classes {
		background: #fffbeb;
		border: 1px solid #fde68a;
		border-radius: 0.5rem;
		padding: 1rem;
		margin-bottom: 1.5rem;
	}

	.unknown-classes.resolved {
		background: #f0fdf4;
		border-color: #bbf7d0;
	}

	.unknown-classes h3 {
		font-size: 0.9375rem;
		font-weight: 600;
		color: #92400e;
		margin: 0 0 0.5rem;
	}

	.unknown-classes.resolved h3 {
		color: #166534;
	}

	.unknown-classes p {
		font-size: 0.8125rem;
		color: #92400e;
		margin: 0 0 0.75rem;
	}

	.unknown-classes.resolved p {
		color: #166534;
	}

	.class-tags {
		display: flex;
		flex-wrap: wrap;
		gap: 0.5rem;
		margin-bottom: 0.75rem;
	}

	.class-tag {
		display: inline-block;
		padding: 0.25rem 0.625rem;
		background: #fef3c7;
		color: #92400e;
		border-radius: 0.375rem;
		font-size: 0.8125rem;
		font-weight: 500;
	}

	/* === Import options === */
	.import-options {
		display: flex;
		flex-direction: column;
		gap: 0.5rem;
		margin-bottom: 1.5rem;
		padding: 1rem;
		background: #f9fafb;
		border-radius: 0.5rem;
	}

	.checkbox-label,
	.radio-label {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		font-size: 0.875rem;
		color: #374151;
		cursor: pointer;
	}

	.checkbox-label input,
	.radio-label input {
		accent-color: var(--btn-primary-bg, #3b82f6);
	}

	/* === Progress === */
	.import-progress {
		text-align: center;
		padding: 3rem 2rem;
	}

	.progress-header h2 {
		font-size: 1.25rem;
		font-weight: 600;
		color: #111827;
		margin: 0 0 0.5rem;
	}

	.progress-header p {
		font-size: 0.875rem;
		color: #6b7280;
		margin: 0 0 2rem;
	}

	.progress-bar-container {
		width: 100%;
		height: 0.75rem;
		background: #e5e7eb;
		border-radius: 9999px;
		overflow: hidden;
	}

	.progress-bar {
		height: 100%;
		background: var(--btn-primary-bg, #3b82f6);
		border-radius: 9999px;
		transition: width 0.3s ease;
	}

	.progress-text {
		font-size: 0.875rem;
		color: #6b7280;
		margin: 0.75rem 0 0;
	}

	/* === Report === */
	.import-report {
		text-align: center;
	}

	.report-header {
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: 0.75rem;
		margin-bottom: 2rem;
	}

	.report-icon {
		width: 3rem;
		height: 3rem;
	}

	.report-header.success {
		color: #16a34a;
	}

	.report-header.failure {
		color: #dc2626;
	}

	.report-header h2 {
		font-size: 1.25rem;
		font-weight: 600;
		margin: 0;
	}

	.report-stats {
		display: flex;
		justify-content: center;
		gap: 3rem;
		margin-bottom: 2rem;
	}

	.stat {
		display: flex;
		flex-direction: column;
		align-items: center;
	}

	.stat-value {
		font-size: 2rem;
		font-weight: 700;
		color: #111827;
	}

	.stat-label {
		font-size: 0.8125rem;
		color: #6b7280;
	}

	.report-details,
	.report-errors {
		text-align: left;
		margin-bottom: 1.5rem;
	}

	.report-details h3,
	.report-errors h3 {
		font-size: 0.9375rem;
		font-weight: 600;
		color: #374151;
		margin: 0 0 0.75rem;
	}

	.report-details ul {
		list-style: none;
		padding: 0;
		margin: 0;
	}

	.report-details li {
		padding: 0.375rem 0;
		font-size: 0.8125rem;
		color: #374151;
		border-bottom: 1px solid #f3f4f6;
	}

	.preview-table-section {
		margin: 1.5rem 0;
	}

	/* === Step actions === */
	.step-actions {
		display: flex;
		justify-content: space-between;
		align-items: center;
		gap: 0.75rem;
		padding-top: 1.5rem;
		border-top: 1px solid #e5e7eb;
		margin-top: 1.5rem;
	}

	/* === Buttons === */
	.btn-primary {
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
		padding: 0.75rem 1.25rem;
		background: var(--btn-primary-bg, #3b82f6);
		color: white;
		border: none;
		border-radius: 0.5rem;
		font-weight: 600;
		font-size: 0.875rem;
		cursor: pointer;
		transition: background 0.2s;
		text-decoration: none;
	}

	.btn-primary:hover:not(:disabled) {
		background: var(--btn-primary-hover-bg, #2563eb);
	}

	.btn-primary:disabled {
		opacity: 0.6;
		cursor: not-allowed;
	}

	.btn-secondary {
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
		padding: 0.75rem 1.25rem;
		background: white;
		color: #374151;
		border: 1px solid #d1d5db;
		border-radius: 0.5rem;
		font-weight: 500;
		font-size: 0.875rem;
		cursor: pointer;
		transition: all 0.2s;
		text-decoration: none;
	}

	.btn-secondary:hover:not(:disabled) {
		background: #f3f4f6;
	}

	.btn-text {
		padding: 0.75rem 1rem;
		background: none;
		color: #6b7280;
		border: none;
		border-radius: 0.375rem;
		font-weight: 500;
		font-size: 0.875rem;
		cursor: pointer;
		transition: color 0.2s;
	}

	.btn-text:hover {
		color: #374151;
	}

	/* === Loading === */
	.loading-state {
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: 1rem;
		padding: 3rem;
	}

	.loading-state p {
		color: #6b7280;
		margin: 0;
	}

	.spinner {
		width: 2rem;
		height: 2rem;
		border: 3px solid #e5e7eb;
		border-top-color: var(--btn-primary-bg, #3b82f6);
		border-radius: 50%;
		animation: spin 0.8s linear infinite;
	}

	@keyframes spin {
		to {
			transform: rotate(360deg);
		}
	}

	/* === Responsive === */
	@media (max-width: 640px) {
		.stepper {
			flex-wrap: wrap;
			gap: 0.5rem;
		}

		.step-connector {
			display: none;
		}

		.step-label {
			display: none;
		}

		.preview-summary {
			grid-template-columns: 1fr;
		}

		.mapping-row {
			flex-direction: column;
			align-items: stretch;
		}

		.mapping-arrow {
			display: none;
		}

		.step-actions {
			flex-direction: column;
		}

		.step-actions button,
		.step-actions a {
			width: 100%;
			justify-content: center;
		}

		.report-stats {
			flex-direction: column;
			gap: 1rem;
		}

		.page-header {
			flex-direction: column;
			gap: 1rem;
		}
	}
</style>
