<script lang="ts">
	import * as Card from '$lib/components/ui/card/index.js';
	import type { CsvUploadItem } from '$lib/config/csv-upload';
	import { UploadCloud, Lock } from 'lucide-svelte';
	import { cn } from '$lib/utils';
	import { toast } from 'svelte-sonner';
	import { browser } from '$app/environment';
	import { api } from '$lib/api';
	import { cookieName, getLocale } from '$lib/paraglide/runtime';
	import { csvMsg } from '$lib/i18n/csv-msg';

	/** Misma fuente que el switch de idioma (cookie Paraglide); `getLocale()` puede quedar desincronizado. */
	function csvTemplateLocale(): 'es' | 'en' {
		if (browser) {
			const cookies = document.cookie.split(';').map((c) => c.trim());
			const localeCookie = cookies.find((c) => c.startsWith(`${cookieName}=`));
			const current = localeCookie ? localeCookie.split('=')[1] : '';
			if (current) return current.toLowerCase().startsWith('en') ? 'en' : 'es';
		}
		return String(getLocale()).toLowerCase().startsWith('en') ? 'en' : 'es';
	}

	let {
		items,
		onUpload,
		busy = false
	}: {
		items: CsvUploadItem[];
		onUpload: (file: File, config: CsvUploadItem) => void;
		/** Bloquea nuevas cargas (p. ej. importación en curso sin overlay). */
		busy?: boolean;
	} = $props();

	const gridLocked = $derived(busy);

	let dragOverId = $state<string | null>(null);

	// Group items
	let groupedItems = $derived.by(() => {
		const groups: Record<string, CsvUploadItem[]> = {};
		const ungrouped: CsvUploadItem[] = [];

		items.forEach((item) => {
			if (item.group) {
				if (!groups[item.group]) groups[item.group] = [];
				groups[item.group].push(item);
			} else {
				ungrouped.push(item);
			}
		});

		return { groups, ungrouped };
	});

	function handleDragEnter(e: DragEvent, id: string, disabled?: boolean) {
		if (disabled || gridLocked) return;
		e.preventDefault();
		e.stopPropagation();
		dragOverId = id;
	}

	function handleDragLeave(e: DragEvent) {
		e.preventDefault();
		e.stopPropagation();
		dragOverId = null;
	}

	function handleDragOver(e: DragEvent, disabled?: boolean) {
		if (disabled || gridLocked) return;
		e.preventDefault();
		e.stopPropagation();
		dragOverId = null;
	}

	function validateAndUpload(file: File, item: CsvUploadItem) {
		const isValidExtension = file.name.toLowerCase().endsWith('.csv');

		if (!isValidExtension) {
			toast.error(csvMsg('toast.invalid_csv'));
			return;
		}

		onUpload(file, item);
	}

	function handleDrop(e: DragEvent, item: CsvUploadItem) {
		if (item.disabled || gridLocked) return;
		e.preventDefault();
		e.stopPropagation();
		dragOverId = null;

		if (e.dataTransfer && e.dataTransfer.files.length > 0) {
			validateAndUpload(e.dataTransfer.files[0], item);
		}
	}

	function handleClick(id: string, disabled?: boolean) {
		if (disabled || gridLocked) return;
		const input = document.getElementById(`file-input-${id}`) as HTMLInputElement;
		if (input) input.click();
	}

	function handleFileChange(e: Event, item: CsvUploadItem) {
		if (gridLocked) return;
		const target = e.target as HTMLInputElement;
		if (target.files && target.files.length > 0) {
			validateAndUpload(target.files[0], item);
			target.value = '';
		}
	}

	async function handleContextMenu(e: MouseEvent, item: CsvUploadItem) {
		if (item.disabled || gridLocked) {
			e.preventDefault();
			return;
		}

		e.preventDefault();

		if (!item.templateId) return;

		try {
			const itemLabel = csvMsg(`items.${item.id}`);
			toast.info(`${csvMsg('toast.download_loading')} ${itemLabel}`);
			const { blob, filename } = await api.getCsvTemplateDownload(
				item.templateId,
				csvTemplateLocale()
			);
			const url = URL.createObjectURL(blob);
			const link = document.createElement('a');
			link.href = url;
			link.download = filename;
			document.body.appendChild(link);
			link.click();
			document.body.removeChild(link);
			URL.revokeObjectURL(url);
			toast.success(`${csvMsg('toast.download_ok')} ${filename}`);
		} catch (err) {
			toast.error(err instanceof Error ? err.message : csvMsg('toast.download_err'));
		}
	}
</script>

<div
	class="flex flex-col gap-6 select-none transition-opacity"
	class:opacity-60={gridLocked}
	aria-busy={gridLocked ? true : undefined}
>
	{#snippet cardTitle(itemId: string)}
		<div class="font-medium text-sm text-balance">{csvMsg(`items.${itemId}`)}</div>
	{/snippet}

	{#if groupedItems.ungrouped.length > 0}
		<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
			{#each groupedItems.ungrouped as item}
				<div
					class={cn(
						'relative group transition-all duration-200 ease-in-out transform',
						item.disabled || gridLocked ? 'opacity-60 cursor-not-allowed' : 'cursor-pointer',
						!item.disabled && !gridLocked && dragOverId === item.id ? 'scale-105' : ''
					)}
					ondragenter={(e) => handleDragEnter(e, item.id, item.disabled || gridLocked)}
					ondragleave={handleDragLeave}
					ondragover={(e) => handleDragOver(e, item.disabled || gridLocked)}
					ondrop={(e) => handleDrop(e, item)}
					oncontextmenu={(e) => handleContextMenu(e, item)}
					role="button"
					tabindex={item.disabled || gridLocked ? -1 : 0}
					onclick={() => handleClick(item.id, item.disabled || gridLocked)}
					onkeydown={(e) =>
						!item.disabled && !gridLocked && e.key === 'Enter' && handleClick(item.id)}
				>
					<input
						type="file"
						id={`file-input-${item.id}`}
						class="hidden"
						accept=".csv"
						onchange={(e) => handleFileChange(e, item)}
						disabled={item.disabled || gridLocked}
					/>

					<Card.Root
						class={cn(
							'h-full border-2 border-dashed border-transparent transition-colors w-full text-left relative overflow-hidden',
							!item.disabled && !gridLocked && 'hover:border-primary/50 hover:shadow-md',
							!item.disabled && !gridLocked && dragOverId === item.id
								? 'border-primary bg-primary/5 shadow-xl ring-2 ring-primary ring-offset-2'
								: ''
						)}
					>
						{#if item.disabled}
							<div class="absolute inset-0 bg-background/50 z-20 flex items-center justify-center">
								<span
									class="bg-muted px-2 py-1 rounded text-xs font-semibold text-muted-foreground border flex items-center gap-1"
								>
									<Lock class="h-3 w-3" /> {csvMsg('soon')}
								</span>
							</div>
						{/if}

						<Card.Content
							class="flex flex-col items-center justify-center p-6 gap-3 text-center h-full relative z-10"
						>
							{#if !item.disabled && !gridLocked && dragOverId === item.id}
								<div class="animate-bounce">
									<UploadCloud class="h-8 w-8 text-primary" />
								</div>
								<span class="text-sm font-semibold text-primary">{csvMsg('drop_here')}</span>
							{:else}
								<div
									class={cn(
										'p-3 bg-muted rounded-full transition-transform duration-200',
										!item.disabled && !gridLocked && 'group-hover:scale-110'
									)}
								>
									<item.icon class="h-6 w-6 text-primary" />
								</div>
								{@render cardTitle(item.id)}
							{/if}
						</Card.Content>
					</Card.Root>
				</div>
			{/each}
		</div>
	{/if}

	{#each Object.entries(groupedItems.groups) as [groupName, groupItems]}
		<div class="flex flex-col gap-3">
			<h3 class="text-sm font-semibold text-muted-foreground uppercase tracking-wider pl-1">
				{csvMsg(`groups.${groupName}`)}
			</h3>
			<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
				{#each groupItems as item}
					<div
						class={cn(
							'relative group transition-all duration-200 ease-in-out transform',
							item.disabled || gridLocked ? 'opacity-60 cursor-not-allowed' : 'cursor-pointer',
							!item.disabled && !gridLocked && dragOverId === item.id ? 'scale-105' : ''
						)}
						ondragenter={(e) => handleDragEnter(e, item.id, item.disabled || gridLocked)}
						ondragleave={handleDragLeave}
						ondragover={(e) => handleDragOver(e, item.disabled || gridLocked)}
						ondrop={(e) => handleDrop(e, item)}
						oncontextmenu={(e) => handleContextMenu(e, item)}
						role="button"
						tabindex={item.disabled || gridLocked ? -1 : 0}
						onclick={() => handleClick(item.id, item.disabled || gridLocked)}
						onkeydown={(e) =>
							!item.disabled && !gridLocked && e.key === 'Enter' && handleClick(item.id)}
					>
						<input
							type="file"
							id={`file-input-${item.id}`}
							class="hidden"
							accept=".csv"
							onchange={(e) => handleFileChange(e, item)}
							disabled={item.disabled || gridLocked}
						/>

						<Card.Root
							class={cn(
								'h-full border-2 border-dashed border-transparent transition-colors w-full text-left relative overflow-hidden',
								!item.disabled && !gridLocked && 'hover:border-primary/50 hover:shadow-md',
								!item.disabled && !gridLocked && dragOverId === item.id
									? 'border-primary bg-primary/5 shadow-xl ring-2 ring-primary ring-offset-2'
									: ''
							)}
						>
							{#if item.disabled}
								<div
									class="absolute inset-0 bg-background/50 z-20 flex items-center justify-center"
								>
									<span
										class="bg-muted px-2 py-1 rounded text-xs font-semibold text-muted-foreground border flex items-center gap-1"
									>
										<Lock class="h-3 w-3" /> {csvMsg('soon')}
									</span>
								</div>
							{/if}

							<Card.Content
								class="flex flex-col items-center justify-center p-6 gap-3 text-center h-full relative z-10"
							>
								{#if !item.disabled && !gridLocked && dragOverId === item.id}
									<div class="animate-bounce">
										<UploadCloud class="h-8 w-8 text-primary" />
									</div>
									<span class="text-sm font-semibold text-primary">{csvMsg('drop_here')}</span>
								{:else}
									<div
										class={cn(
											'p-3 bg-muted rounded-full transition-transform duration-200',
											!item.disabled && !gridLocked && 'group-hover:scale-110'
										)}
									>
										<item.icon class="h-6 w-6 text-primary" />
									</div>
									{@render cardTitle(item.id)}
								{/if}
							</Card.Content>
						</Card.Root>
					</div>
				{/each}
			</div>
		</div>
	{/each}
</div>
