<script lang="ts">
	import * as Tabs from '$lib/components/ui/tabs/index.js';
	import UploadLauncherGrid from '$lib/components/dashboard/csv-upload/UploadLauncherGrid.svelte';
	import CsvParamsBar from '$lib/components/dashboard/csv-upload/CsvParamsBar.svelte';
	import ProcessingResultModal from '$lib/components/dashboard/csv-upload/ProcessingResultModal.svelte';
	import {
		catalogosConfig,
		transportesConfig,
		importacionConfig,
		exportacionConfig,
		tabSettings,
		globalCsvParams,
		type CsvUploadItem
	} from '$lib/config/csv-upload';
	import { api } from '$lib/api';
	import { toast } from 'svelte-sonner';
	import { companyStore } from '$lib/stores/company.svelte';

	/** Intenta extraer un objeto tipo scan desde string tipo repr de Python. */
	function parsePythonReprScan(s: string): Record<string, unknown> | null {
		const jobIdMatch = s.match(/'job_id':\s*'([^']*)'/);
		const totalRowsMatch = s.match(/'total_rows':\s*(\d+)/);
		if (!jobIdMatch || !totalRowsMatch) return null;
		const job_id = jobIdMatch[1];
		const total_rows = parseInt(totalRowsMatch[1], 10);
		const errorCountMatch = s.match(/'error_count':\s*(\d+)/);
		const validRowsMatch = s.match(/'valid_rows':\s*(\d+)/);
		const error_count = errorCountMatch ? parseInt(errorCountMatch[1], 10) : 0;
		const valid_rows = validRowsMatch ? parseInt(validRowsMatch[1], 10) : 0;
		const errors: { line: number; col: string; msg: string; solution?: string; warning?: boolean }[] = [];
		// Buscar cada diccionario de error en la cadena.
		// Nota: el backend suele serializar dicts con claves extra (p.ej. 'solution', 'warning'),
		// así que el regex no puede asumir que el dict termina justo después de 'msg'.
		const errRegex =
			/\{'line':\s*(\d+),\s*'col':\s*'([^']*)',\s*'msg':\s*'((?:[^'\\]|\\.)*)'(?:,\s*'solution':\s*'((?:[^'\\]|\\.)*)')?(?:,\s*'warning':\s*(True|False))?[^}]*\}/g;
		let m: RegExpExecArray | null;
		while ((m = errRegex.exec(s)) !== null) {
			errors.push({
				line: parseInt(m[1], 10),
				col: m[2],
				msg: m[3].replace(/\\'/g, "'"),
				solution: m[4]?.replace(/\\'/g, "'") ?? '',
				warning: m[5] ? m[5] === 'True' : false
			});
		}
		return {
			status: 'waiting_confirmation',
			job_id,
			total_rows,
			error_count,
			valid_rows,
			errors
		};
	}

	/** Intenta extraer un resultado tipo commit (finished/warning) desde repr Python. */
	function parsePythonReprCommit(s: string): Record<string, unknown> | null {
		if (!s || typeof s !== 'string') return null;

		const unescapePy = (v: string) =>
			v.replace(/\\'/g, "'").replace(/\\\\n/g, '\n').replace(/\\\\t/g, '\t').replace(/\\\\r/g, '\r');

		const safeInt = (value: unknown): number => {
			if (value === null || value === undefined) return 0;
			const raw = String(value).replace(/['"]/g, '').trim();
			const n = parseInt(raw, 10);
			return Number.isFinite(n) ? n : 0;
		};

		// Acepta tanto repr Python como JSON (comillas simples/dobles).
		const statusMatch =
			s.match(/['"]status['"]:\s*['"]([^'"]+)['"]/) || s.match(/['"]status['"]:\s*([^,}]+)/);
		if (!statusMatch) return null;
		const status = String(statusMatch[1] ?? '').replace(/['"]/g, '').trim();
		if (status !== 'finished' && status !== 'warning') return null;

		const insertedMatch = s.match(/['"]inserted['"]:\s*['"]?(-?\d+)['"]?/) || s.match(/['"]inserted['"]:\s*([^,}]+)/);
		const inserted = insertedMatch ? safeInt(insertedMatch[1]) : 0;

		const updatedMatch = s.match(/['"]updated['"]:\s*['"]?(-?\d+)['"]?/) || s.match(/['"]updated['"]:\s*([^,}]+)/);
		const updated = updatedMatch ? safeInt(updatedMatch[1]) : 0;

		const skippedInvalidMatch =
			s.match(/['"]skipped_invalid['"]:\s*['"]?(\d+)['"]?/) || s.match(/['"]skipped_invalid['"]:\s*([^,}]+)/);
		const skippedMissingFkMatch =
			s.match(/['"]skipped_missing_fk['"]:\s*['"]?(\d+)['"]?/) || s.match(/['"]skipped_missing_fk['"]:\s*([^,}]+)/);
		const skippedDuplicateMatch =
			s.match(/['"]skipped_duplicate['"]:\s*['"]?(\d+)['"]?/) || s.match(/['"]skipped_duplicate['"]:\s*([^,}]+)/);

		const skipped_invalid = skippedInvalidMatch ? safeInt(skippedInvalidMatch[1]) : 0;
		const skipped_missing_fk = skippedMissingFkMatch
			? safeInt(skippedMissingFkMatch[1])
			: 0;
		const skipped_duplicate = skippedDuplicateMatch
			? safeInt(skippedDuplicateMatch[1])
			: 0;

		// Detalle opcional: lista de dicts con {line, reason, solution?}
		const skipped_details: Array<{ line: number; reason: string; solution?: string }> = [];
		const detailRegex =
			/\{'line':\s*(\d+),\s*'reason':\s*'((?:[^'\\]|\\.)*)'(?:,\s*'solution':\s*'((?:[^'\\]|\\.)*)')?[^}]*\}/g;
		let m: RegExpExecArray | null;
		while ((m = detailRegex.exec(s)) !== null) {
			skipped_details.push({
				line: parseInt(m[1], 10),
				reason: unescapePy(m[2]),
				solution: m[3] ? unescapePy(m[3]) : undefined
			});
		}

		const messageMatch =
			s.match(/'message':\s*'((?:[^'\\]|\\.)*)'/) ||
			s.match(/"message":\s*"((?:[^"\\]|\\.)*)"/);
		const message = messageMatch ? unescapePy(messageMatch[1]) : undefined;

		// Si no hay contadores en el texto, no es un commit.
		if (inserted === 0 && updated === 0 && skipped_invalid === 0 && skipped_missing_fk === 0 && skipped_duplicate === 0) {
			return null;
		}

		// Mínimo requerido por el modal
		return {
			status,
			inserted,
			updated,
			skipped_invalid,
			skipped_missing_fk,
			skipped_duplicate,
			skipped_details,
			...(message ? { message } : {})
		};
	}

	// We no longer need modal state
	let activeTab = $state('catalogos');

	let isUploading = $state(false);
	let currentJobId = $state<string | null>(null);
	let activeModelTarget = $state<string | null>(null);
	let scanResults = $state<any>(null);
	let commitResults = $state<any>(null);
	let showResultModal = $state(false);
	// Cuando es true, usamos API de importación de Agentes Aduanales (customs_brokers/imports)
	let useCustomsBrokerImport = $state(false);
	// Cuando es true, usamos API de importación de Clientes y Proveedores (clients_and_providers/imports)
	let useClientProviderImport = $state(false);
	// Cuando es true, usamos API de importación de Tipos de Cambio (exchange_rate/imports)
	let useExchangeRateImport = $state(false);
	// Cuando es true, usamos API de importación de Fracción Americana (us_tariff_fractions/imports)
	let useAmericanFractionImport = $state(false);
	// Cuando es true, usamos API de importación de Pedimentos (pedimentos/imports)
	let usePedimentosImport = $state(false);
	// Cuando es true, usamos API de importación de Clases de Materiales (classes/imports)
	let useMaterialClassesImport = $state(false);
	// Cuando es true, usamos API de importación de Vehículos / Transportes (vehicles/imports)
	let useVehicleImport = $state(false);
	// Cuando es true, usamos API de importación de Conductores (drivers/imports)
	let useDriverImport = $state(false);
	// Cuando es true, usamos API de importación de Trailers y Cajas (trailers/imports)
	let useTrailerImport = $state(false);
	// Cuando es true, usamos API de importación de Transportistas (transporters/imports)
	let useTransporterImport = $state(false);
	// Cuando es true, usamos API de importación de Números de parte (parts/imports)
	let usePartNumbersImport = $state(false);
	// Cuando es true, usamos API de importación de BOMs (boms/imports)
	let useBomImport = $state(false);
	// Cuando es true, usamos API de importación de Exportación (layouts_csv/exportacion)
	let useExportacionImport = $state(false);

	// Initialize settings for all tabs upfront to avoid reactivity loops (sync init so child never receives undefined)
	const _initialSettings: Record<string, any> = {};
	for (const tab in tabSettings) {
		_initialSettings[tab] = {};
		tabSettings[tab].forEach((f) => {
			_initialSettings[tab][f.name] = f.defaultValue;
		});
	}
	let allSettings = $state<Record<string, any>>(_initialSettings);

	// Global parameters for all CSV loads (merged with tab settings when sending footer_config)
	const _initialGlobal: Record<string, string> = {};
	globalCsvParams.forEach((p) => {
		_initialGlobal[p.name] = String(p.defaultValue);
	});
	let globalSettings = $state<Record<string, string>>(_initialGlobal);

	/** Coerce string 'true'/'false' to boolean for API payload. */
	function coerceFooterConfig(obj: Record<string, any>): Record<string, any> {
		const booleanKeys = [
			'autonumber_series',
			'load_subpartidas',
			'recalculate_pedimento_date',
			'autonumber_remesas',
			'recalculate_dates',
			'is_regime_change'
		];
		const out = { ...obj };
		for (const k of booleanKeys) {
			if (k in out && typeof out[k] === 'string') {
				out[k] = out[k] === 'true';
			}
		}
		return out;
	}

	async function handleUpload(file: File, config: CsvUploadItem) {
		console.log('handleUpload started', { file, config });
		isUploading = true;
		activeModelTarget = config.modelTarget || null;
		scanResults = null;
		useCustomsBrokerImport = config.id === 'customs_brokers';
		useClientProviderImport = config.id === 'clients_providers';
		useExchangeRateImport = config.id === 'exchange_rates';
		useAmericanFractionImport = config.id === 'american_fractions';
		usePedimentosImport = config.id === 'pedimentos';
		useMaterialClassesImport = config.id === 'material_classes';
		useVehicleImport = config.id === 'transports';
		useDriverImport = config.id === 'drivers';
		useTrailerImport = config.id === 'trailers';
		useTransporterImport = config.id === 'transporters';
		usePartNumbersImport = config.id === 'part_numbers';
		useBomImport = config.id === 'boms';
		useExportacionImport = activeTab === 'exportacion';

		const companyId = companyStore.activeCompany?.id || 1;

		if (useCustomsBrokerImport) {
			try {
				const res = await api.customsBrokerImports.upload(file, companyId);
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		if (useClientProviderImport) {
			try {
				const res = await api.clientProviderImports.upload(file, companyId);
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		if (useExchangeRateImport) {
			try {
				const catalogosSettings = allSettings['catalogos'] || {};
				const globalMode = globalSettings['mode'] ?? catalogosSettings['mode'] ?? 'update';
				const reemplazar_sin_preguntar = globalMode === 'replace';
				// Formato activo del selector global (Formato de Fecha); mismo default que la barra
				const dateFormat =
					globalSettings['dateFormat'] ?? catalogosSettings['dateFormat'] ?? globalCsvParams.find((p) => p.name === 'dateFormat')?.defaultValue ?? 'dd/mm/yyyy';
				const res = await api.exchangeRateImports.upload(file, companyId, {
					reemplazar_sin_preguntar,
					date_format: dateFormat
				});
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		if (useAmericanFractionImport) {
			try {
				const res = await api.americanFractionImports.upload(file, companyId);
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		if (usePedimentosImport) {
			try {
				const catalogosSettings = allSettings['catalogos'] || {};
				const actualizar = catalogosSettings['mode'] === 'update';
				const dateFormat =
					globalSettings['dateFormat'] ?? catalogosSettings['dateFormat'] ?? globalCsvParams.find((p) => p.name === 'dateFormat')?.defaultValue ?? 'dd/mm/yyyy';
				const res = await api.pedimentosImports.upload(file, companyId, {
					actualizar,
					dateFormat
				});
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		if (useMaterialClassesImport) {
			try {
				const catalogosSettings = allSettings['catalogos'] || {};
				const actualizar = catalogosSettings['mode'] === 'update';
				const res = await api.materialClassImports.upload(file, companyId, {
					actualizar,
					siempre_toda: false
				});
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		if (useVehicleImport) {
			try {
				const catalogosSettings = allSettings['catalogos'] || {};
				const actualizar = catalogosSettings['mode'] === 'update';
				const res = await api.vehicleImports.upload(file, companyId, { actualizar });
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		if (useDriverImport) {
			try {
				const res = await api.driverImports.upload(file, companyId);
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		if (useTrailerImport) {
			try {
				const transportesSettings = allSettings['transportes'] || {};
				const actualizar = transportesSettings['mode'] === 'update';
				const res = await api.trailerImports.upload(file, companyId, { actualizar });
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		if (useTransporterImport) {
			try {
				const transportesSettings = allSettings['transportes'] || {};
				const actualizar = transportesSettings['mode'] === 'update';
				const res = await api.transporterImports.upload(file, companyId, { actualizar });
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		if (usePartNumbersImport) {
			try {
				const catalogosSettings = allSettings['catalogos'] || {};
				const actualizar = catalogosSettings['mode'] === 'update';
				const res = await api.partNumberImports.upload(file, companyId, {
					actualizar,
					reemplazar_sin_preguntar: true
				});
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		if (useBomImport) {
			try {
				const res = await api.bomImports.upload(file, companyId);
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		const currentTabSettings = allSettings[activeTab] || {};
		const footerConfig = coerceFooterConfig({
			...globalSettings,
			...currentTabSettings
		});
		if (activeTab === 'importacion') {
			footerConfig.invoice_type = config.id?.startsWith('imp_def_') ? 'DEF' : 'TEM';
		}

		if (useExportacionImport) {
			try {
				const res = await api.exportacionImports.upload(
					file,
					config.modelTarget || '',
					footerConfig,
					companyId,
					config.templateId || config.id
				);
				if (res.data?.job_id) {
					currentJobId = res.data.job_id;
					pollStatus();
				} else {
					toast.error(res.error || 'Error al subir el archivo');
					isUploading = false;
				}
			} catch (e) {
				console.error('Upload exception', e);
				toast.error('Error inesperado al subir el archivo');
				isUploading = false;
			}
			return;
		}

		const opType = activeTab === 'exportacion' ? 'exp' : 'imp';

		try {
			const res = await api.imports.upload(
				file,
				config.modelTarget || '',
				footerConfig,
				companyId,
				opType,
				config.templateId || config.id
			);
			if (res.data?.job_id) {
				currentJobId = res.data.job_id;
				pollStatus();
			} else {
				toast.error(res.error || 'Error al subir el archivo');
				isUploading = false;
			}
		} catch (e) {
			console.error('Upload exception', e);
			toast.error('Error inesperado al subir el archivo');
			isUploading = false;
		}
	}

	async function pollStatus() {
		if (!currentJobId) return;

		try {
			const res = useCustomsBrokerImport
				? await api.customsBrokerImports.status(currentJobId)
				: useClientProviderImport
					? await api.clientProviderImports.status(currentJobId)
					: useExchangeRateImport
						? await api.exchangeRateImports.status(currentJobId)
						: useAmericanFractionImport
							? await api.americanFractionImports.status(currentJobId)
							: usePedimentosImport
								? await api.pedimentosImports.status(currentJobId)
								: useMaterialClassesImport
									? await api.materialClassImports.status(currentJobId)
									: useVehicleImport
										? await api.vehicleImports.status(currentJobId)
										: useDriverImport
											? await api.driverImports.status(currentJobId)
											: useTrailerImport
												? await api.trailerImports.status(currentJobId)
												: useTransporterImport
													? await api.transporterImports.status(currentJobId)
													: usePartNumbersImport
														? await api.partNumberImports.status(currentJobId)
														: useBomImport
															? await api.bomImports.status(currentJobId)
															: useExportacionImport
																? await api.exportacionImports.status(currentJobId)
																: await api.imports.status(currentJobId);
			console.log('Poll response', res);
			if (res.error && !res.data) {
				toast.error(res.error || 'Error al consultar el estado');
				isUploading = false;
				currentJobId = null;
				return;
			}
			// Tratar como resultado de escaneo si viene status waiting_confirmation O si el payload tiene forma de scan (job_id + total_rows)
			const looksLikeScanResult =
				res.data?.status === 'waiting_confirmation' ||
				(res.data?.job_id && typeof res.data?.total_rows === 'number');
			if (looksLikeScanResult) {
				scanResults = res.data;
				showResultModal = true;
				toast.success('Escaneo completado. Revisa los resultados.');
				isUploading = false;
			} else if (res.data?.status === 'failed' || res.data?.status === 'FAILURE') {
				const errRaw = res.data.error;
				// Si el backend devolvió el resultado del scan dentro de error (p. ej. string JSON), usarlo para mostrar el modal
					const errStringCandidate =
						typeof errRaw === 'string'
							? errRaw
							: errRaw && typeof errRaw === 'object' && typeof (errRaw as any).message === 'string'
								? (errRaw as any).message
								: null;

					const parsedCommit = errStringCandidate ? parsePythonReprCommit(errStringCandidate) : null;
					if (parsedCommit) {
						commitResults = parsedCommit;
						showResultModal = true;
						toast.success('Importación completada. Revisa el listado de registros.');
						isUploading = false;
						currentJobId = null;
						return;
					}

				let parsedScan: Record<string, unknown> | null = null;
				if (typeof errRaw === 'string' && (errRaw.includes('waiting_confirmation') || (errRaw.includes('total_rows') && errRaw.includes('job_id')))) {
					try {
						const parsed = JSON.parse(errRaw) as Record<string, unknown>;
						if (parsed && typeof parsed.job_id === 'string' && typeof parsed.total_rows === 'number') {
							parsedScan = parsed;
						}
					} catch {
						// No es JSON; intentar parsear como repr de Python
						parsedScan = parsePythonReprScan(errRaw);
					}
				}
				if (parsedScan) {
					scanResults = parsedScan;
					showResultModal = true;
					toast.success('Escaneo completado. Revisa los resultados.');
					isUploading = false;
				} else {
					// Mensaje parece resultado de escaneo pero no se pudo parsear (p. ej. repr Python) → no asustar con error
					const looksLikeScanInError =
						typeof errRaw === 'string' &&
						(errRaw.includes('waiting_confirmation') || (errRaw.includes('total_rows') && errRaw.includes('job_id')));
					if (looksLikeScanInError) {
						toast.info('El escaneo terminó. Si no ves el modal, revisa el listado de registros.');
						isUploading = false;
						currentJobId = null;
						return;
					}
					let errText: string;
					if (typeof errRaw === 'string') {
						errText =
							errRaw.includes('finished') && errRaw.includes('inserted')
								? 'La importación pudo completarse. Revisa el listado de registros.'
								: errRaw.includes("'status'") && errRaw.includes('waiting_confirmation')
									? 'Error al obtener el resultado. Revisa el modal de resultados.'
									: errRaw;
					} else if (typeof errRaw === 'object' && errRaw !== null) {
						errText = (errRaw as { message?: string })?.message || 'Error en el procesamiento. Revisa el modal o los detalles.';
					} else {
						errText = 'Error desconocido';
					}
					// No mostrar como error si el mensaje indica éxito
					if (errText.includes('pudo completarse') || errText.includes('Revisa el listado')) {
						toast.success(errText);
					} else {
						toast.error('Error en el procesamiento: ' + errText);
					}
					isUploading = false;
					currentJobId = null;
					scanResults = null;
					commitResults = null;
					showResultModal = false;
				}
			} else if (res.data?.status === 'warning') {
				// Caso cuando no se insertaron registros pero hay información de rechazo
				commitResults = res.data;
				showResultModal = true;
				const inserted = res.data?.inserted || 0;
				const skippedInvalid = res.data?.skipped_invalid || 0;
				const skippedFk = res.data?.skipped_missing_fk || 0;
				const skippedDup = res.data?.skipped_duplicate || 0;
				const totalSkipped = skippedInvalid + skippedFk + skippedDup;
				const backendMessage = res.data?.message;

				if (inserted === 0) {
					toast.error(backendMessage || `No se insertaron registros. ${totalSkipped} fueron rechazados.`);
				} else {
					toast.warning(backendMessage || `Solo se insertaron ${inserted} de ${inserted + totalSkipped} registros.`);
				}
				isUploading = false;
			} else if (res.data?.status === 'finished') {
				commitResults = res.data;
				showResultModal = true;
				const inserted = res.data?.inserted || 0;
				const updated = res.data?.updated || 0;
				const skippedInvalid = res.data?.skipped_invalid || 0;
				const skippedFk = res.data?.skipped_missing_fk || 0;
				const skippedDup = res.data?.skipped_duplicate || 0;
				const skippedDetails = res.data?.skipped_details || [];

				if (inserted > 0 || updated > 0) {
					const parts = [];
					if (inserted > 0) parts.push(`${inserted} insertados`);
					if (updated > 0) parts.push(`${updated} actualizados`);
					toast.success(`Importación completada: ${parts.join(', ')}`);
					if (skippedInvalid > 0 || skippedFk > 0 || skippedDup > 0) {
						const totalSkipped = skippedInvalid + skippedFk + skippedDup;
						toast.warning(`${totalSkipped} registros fueron rechazados u omitidos`);
					}
				} else {
					toast.error('No se insertaron registros. Revisa los errores a continuación.');
				}
				isUploading = false;
			} else {
				// Continue polling
				console.log('Status not final, polling again in 2s...', res.data?.status);
				setTimeout(pollStatus, 2000);
			}
		} catch (e) {
			console.error('Poll exception', e);
			// Retry on network error? Or fail?
			// For now, let's keep retrying a few times or hard fail.
			// Let's just log and retry.
			setTimeout(pollStatus, 2000);
		}
	}
</script>

<div class="flex flex-col flex-1 min-h-0 -m-4 overflow-hidden">
	<!-- Single scroll: content scrolls here; padding at bottom reserves space for fixed params bar -->
	<div class="flex-1 min-h-0 overflow-y-auto p-4 md:p-8 space-y-4">
		<div class="flex items-center gap-4">
			<h1 class="text-lg font-semibold md:text-2xl">Importación Masiva de Datos (CSV)</h1>
		</div>

		<Tabs.Root bind:value={activeTab} class="w-full">
			<Tabs.List class="grid w-full grid-cols-2 md:grid-cols-4 lg:w-auto">
				<Tabs.Trigger value="catalogos">Catálogos</Tabs.Trigger>
				<Tabs.Trigger value="transportes">Transportes</Tabs.Trigger>
				<Tabs.Trigger value="importacion">Importación</Tabs.Trigger>
				<Tabs.Trigger value="exportacion">Exportación</Tabs.Trigger>
			</Tabs.List>

			<div class="mt-6">
				<Tabs.Content value="catalogos" class="space-y-4">
					<!-- Catálogos: backend layouts_csv (customs_brokers, clients_and_providers, parts, boms, etc.) -->
					<div class="flex items-center justify-between">
						<h2 class="text-lg font-medium tracking-tight">Catálogos Generales</h2>
					</div>
					<UploadLauncherGrid items={catalogosConfig} onUpload={handleUpload} />
				</Tabs.Content>

				<Tabs.Content value="transportes" class="space-y-4">
					<!-- Logística: backend layouts_csv (vehicles, drivers, trailers); transportistas sin layouts_csv -->
					<div class="flex items-center justify-between">
						<h2 class="text-lg font-medium tracking-tight">Logística y Transporte</h2>
					</div>
					<UploadLauncherGrid items={transportesConfig} onUpload={handleUpload} />
				</Tabs.Content>

				<Tabs.Content value="importacion" class="space-y-4">
					<!-- Operaciones de Importación: backend layouts_csv/facturas (api.imports) -->
					<div class="flex items-center justify-between">
						<h2 class="text-lg font-medium tracking-tight">Operaciones de Importación</h2>
					</div>
					<UploadLauncherGrid items={importacionConfig} onUpload={handleUpload} />
				</Tabs.Content>

				<Tabs.Content value="exportacion" class="space-y-4">
					<div class="flex items-center justify-between">
						<h2 class="text-lg font-medium tracking-tight">Operaciones de Exportación</h2>
					</div>
					<UploadLauncherGrid items={exportacionConfig} onUpload={handleUpload} />
				</Tabs.Content>
			</div>
		</Tabs.Root>

		<!-- Spacer at end of page: reserves space for fixed params bar so content is not cut off -->
		<div class="h-[var(--csv-params-bar-height,6rem)] shrink-0" aria-hidden="true"></div>
	</div>

	<!-- Fixed params bar (always visible on this view) -->
	<CsvParamsBar bind:globalSettings {activeTab} bind:tabSettingsValues={allSettings[activeTab]} />
</div>

{#if scanResults || commitResults}
	<ProcessingResultModal
		bind:open={showResultModal}
		{scanResults}
		{commitResults}
		{isUploading}
		scanErrorsDownloadType={
			useCustomsBrokerImport
				? 'customs_brokers'
				: useClientProviderImport
					? 'clients_providers'
					: useExchangeRateImport
						? 'exchange_rate'
						: useAmericanFractionImport
							? 'us_tariff_fractions'
							: usePedimentosImport
								? 'pedimentos'
								: useMaterialClassesImport
									? 'classes'
									: useVehicleImport
										? 'vehicles'
										: useDriverImport
											? 'drivers'
											: useTrailerImport
												? 'trailers'
												: useTransporterImport
													? 'transporters'
													: usePartNumbersImport
														? 'parts'
														: useBomImport
															? 'boms'
															: useExportacionImport
																? 'exportacion'
																: 'imports'
		}
		onConfirm={async () => {
			if (!currentJobId) return;
			try {
				isUploading = true;
				const res = useCustomsBrokerImport
					? await api.customsBrokerImports.commit(currentJobId)
					: useClientProviderImport
						? await api.clientProviderImports.commit(currentJobId)
						: useExchangeRateImport
							? await api.exchangeRateImports.commit(currentJobId)
							: useAmericanFractionImport
								? await api.americanFractionImports.commit(currentJobId)
								: usePedimentosImport
									? await api.pedimentosImports.commit(currentJobId)
									: useMaterialClassesImport
										? await api.materialClassImports.commit(currentJobId)
										: useVehicleImport
											? await api.vehicleImports.commit(currentJobId)
											: useDriverImport
												? await api.driverImports.commit(currentJobId)
												: useTrailerImport
													? await api.trailerImports.commit(currentJobId)
													: useTransporterImport
														? await api.transporterImports.commit(currentJobId)
														: usePartNumbersImport
															? await api.partNumberImports.commit(currentJobId)
															: useBomImport
																? await api.bomImports.commit(currentJobId)
																: useExportacionImport
																	? await api.exportacionImports.commit(currentJobId, activeModelTarget || '')
																	: await api.imports.commit(currentJobId, activeModelTarget || '');
				if (res.data?.commit_job_id) {
					currentJobId = res.data.commit_job_id;
					pollStatus();
				}
			} catch (err) {
				toast.error('Error al iniciar la importación');
				isUploading = false;
			}
		}}
		onCancel={() => {
			currentJobId = null;
			scanResults = null;
			commitResults = null;
			showResultModal = false;
		}}
		onClose={() => {
			currentJobId = null;
			scanResults = null;
			commitResults = null;
			showResultModal = false;
		}}
	/>
{/if}
