<script lang="ts">
	const DEFAULT_ACCEPTED_TYPES = ['application/pdf', 'image/jpeg', 'image/png'];
	const DEFAULT_ACCEPT_ATTR = '.pdf,.jpg,.jpeg,.png';
	const DEFAULT_HINT = 'PDF, JPEG ou PNG — 10 Mo max par fichier';
	const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 Mo

	interface UploadedFile {
		id: string;
		filename: string;
		fileSize: number;
		mimeType: string;
	}

	let {
		existingFiles = [],
		onUpload,
		onDelete,
		disabled = false,
		acceptedTypes = DEFAULT_ACCEPTED_TYPES,
		acceptAttr = DEFAULT_ACCEPT_ATTR,
		hint = DEFAULT_HINT,
		showDelete = true
	}: {
		existingFiles?: UploadedFile[];
		onUpload: (file: File) => Promise<UploadedFile>;
		onDelete: (fileId: string) => Promise<void>;
		disabled?: boolean;
		acceptedTypes?: string[];
		acceptAttr?: string;
		hint?: string;
		showDelete?: boolean;
	} = $props();

	let files = $state<UploadedFile[]>(existingFiles);
	let pendingFiles = $state<{ name: string; size: number }[]>([]);
	let error = $state<string | null>(null);
	let fileInput: HTMLInputElement;

	$effect(() => {
		files = existingFiles;
	});

	function formatFileSize(bytes: number): string {
		if (bytes < 1024) return `${bytes} o`;
		if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} Ko`;
		return `${(bytes / (1024 * 1024)).toFixed(1)} Mo`;
	}

	function getFileIcon(mimeType: string): string {
		if (mimeType === 'application/pdf') return '📄';
		if (mimeType.startsWith('image/')) return '🖼️';
		return '📎';
	}

	function validateFile(file: File): string | null {
		if (!acceptedTypes.includes(file.type)) {
			return `Type de fichier non accepté : ${file.type}.`;
		}
		if (file.size > MAX_FILE_SIZE) {
			return `Le fichier dépasse la taille maximale de 10 Mo (${formatFileSize(file.size)}).`;
		}
		return null;
	}

	async function handleFileSelect(event: Event) {
		const input = event.target as HTMLInputElement;
		const selectedFiles = input.files;
		if (!selectedFiles || selectedFiles.length === 0) return;

		error = null;

		for (const file of selectedFiles) {
			const validationError = validateFile(file);
			if (validationError) {
				error = validationError;
				continue;
			}

			pendingFiles = [...pendingFiles, { name: file.name, size: file.size }];

			try {
				const uploaded = await onUpload(file);
				files = [...files, uploaded];
			} catch {
				error = `Erreur lors de l'envoi de "${file.name}".`;
			} finally {
				pendingFiles = pendingFiles.filter((p) => p.name !== file.name);
			}
		}

		input.value = '';
	}

	async function handleDelete(fileId: string) {
		error = null;

		try {
			await onDelete(fileId);
			files = files.filter((f) => f.id !== fileId);
		} catch {
			error = 'Erreur lors de la suppression du fichier.';
		}
	}
</script>

<div class="file-upload" class:disabled>
	{#if error}
		<p class="upload-error" role="alert">{error}</p>
	{/if}

	{#if files.length > 0 || pendingFiles.length > 0}
		<ul class="file-list">
			{#each files as file}
				<li class="file-item">
					<span class="file-icon">{getFileIcon(file.mimeType)}</span>
					<span class="file-name">{file.filename}</span>
					<span class="file-size">{formatFileSize(file.fileSize)}</span>
					{#if !disabled && showDelete}
						<button
							type="button"
							class="file-remove"
							onclick={() => handleDelete(file.id)}
							title="Supprimer {file.filename}"
							aria-label="Supprimer {file.filename}"
						>
							✕
						</button>
					{/if}
				</li>
			{/each}
			{#each pendingFiles as pending}
				<li class="file-item file-pending">
					<span class="file-icon">⏳</span>
					<span class="file-name">{pending.name}</span>
					<span class="file-size">{formatFileSize(pending.size)}</span>
					<span class="file-uploading">Envoi...</span>
				</li>
			{/each}
		</ul>
	{/if}

	{#if !disabled}
		<button type="button" class="upload-btn" onclick={() => fileInput.click()}>
			<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
				<path d="M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48" />
			</svg>
			Ajouter un fichier
		</button>
		<input
			bind:this={fileInput}
			type="file"
			accept={acceptAttr}
			onchange={handleFileSelect}
			class="file-input-hidden"
			aria-hidden="true"
			tabindex="-1"
		/>
		<p class="upload-hint">{hint}</p>
	{/if}
</div>

<style>
	.file-upload {
		display: flex;
		flex-direction: column;
		gap: 0.5rem;
	}

	.file-upload.disabled {
		opacity: 0.6;
	}

	.upload-error {
		margin: 0;
		padding: 0.5rem 0.75rem;
		background: #fee2e2;
		border-radius: 0.375rem;
		color: #991b1b;
		font-size: 0.8125rem;
	}

	.file-list {
		list-style: none;
		margin: 0;
		padding: 0;
		display: flex;
		flex-direction: column;
		gap: 0.375rem;
	}

	.file-item {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		padding: 0.5rem 0.75rem;
		background: #f9fafb;
		border: 1px solid #e5e7eb;
		border-radius: 0.375rem;
		font-size: 0.875rem;
	}

	.file-pending {
		opacity: 0.6;
	}

	.file-icon {
		flex-shrink: 0;
	}

	.file-name {
		flex: 1;
		color: #374151;
		font-weight: 500;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	.file-size {
		color: #9ca3af;
		font-size: 0.75rem;
		flex-shrink: 0;
	}

	.file-uploading {
		color: #3b82f6;
		font-size: 0.75rem;
		flex-shrink: 0;
	}

	.file-remove {
		display: flex;
		align-items: center;
		justify-content: center;
		width: 1.5rem;
		height: 1.5rem;
		border: none;
		border-radius: 50%;
		background: #e5e7eb;
		color: #6b7280;
		font-size: 0.625rem;
		cursor: pointer;
		flex-shrink: 0;
		transition: background-color 0.15s;
	}

	.file-remove:hover {
		background: #fecaca;
		color: #dc2626;
	}

	.upload-btn {
		display: inline-flex;
		align-items: center;
		gap: 0.375rem;
		padding: 0.5rem 0.75rem;
		border: 1px dashed #d1d5db;
		border-radius: 0.375rem;
		background: white;
		color: #374151;
		font-size: 0.875rem;
		cursor: pointer;
		transition: border-color 0.15s, background-color 0.15s;
		align-self: flex-start;
	}

	.upload-btn:hover {
		border-color: #3b82f6;
		background: #eff6ff;
		color: #2563eb;
	}

	.file-input-hidden {
		position: absolute;
		width: 0;
		height: 0;
		overflow: hidden;
		opacity: 0;
	}

	.upload-hint {
		margin: 0;
		font-size: 0.75rem;
		color: #9ca3af;
	}
</style>
