<script lang="ts">
	import {
		selectedSheet,
		currentStep,
		columnMapping,
	} from '$lib/stores';
	import { userEmail } from '$lib/google';
	import { hashString } from '$lib/utils';
	import type { ColumnMappingType, SheetInfoType } from '$lib/stores';
	import { getSheetNames, getSheetData, ensureToken } from '$lib/google';
	import { onMount } from 'svelte';
	import Navigator from './subcomponents/Navigator.svelte';

	let isLoadingSheets = $state(false);
	let isLoadingData = $state(false);
	let availableSheets = $state<string[]>([]);
	let selectedSheetName = $state('');
	let error = $state('');
	let sheetHeaders = $state<string[]>([]);
	let previewData = $state<string[][]>([]);
	let mappingComplete = $state(false);
	let hasSavedMapping = $state(false);
	let showMappingEditor = $state(false);
	let savedSheetInfo = $state<SheetInfoType | null>(null);
	let mappedIndices = $state<ColumnMappingType>({
		name: -1,
		nationality: -1,
		birthday: -1,
		pictureUrl: -1,
		alreadyPrinted: -1,
		sheetName: ''
	});

	const requiredFields = [
		{ key: 'name', label: 'Full Name', required: true },
		{ key: 'nationality', label: 'Nationality', required: true },
		{ key: 'birthday', label: 'Birthday', required: true },
		{ key: 'pictureUrl', label: 'Photo URL', required: true },
		{ key: 'alreadyPrinted', label: 'Already Printed', required: false }
	];

	async function getRecentSheetsKey() {
		const email = $userEmail;
		if (email) {
			return `recentSheets_${await hashString(email)}`;
		}
		return 'recentSheets_anonymous';
	}

	// Load available sheets when component mounts
	onMount(async () => {
		ensureToken();
		if ($selectedSheet) {
			console.log('Selected sheet on mount:', $selectedSheet);

			// Check if we already have saved mapping data
			const key = await getRecentSheetsKey();
			const recentSheetsData = localStorage.getItem(key);

			if (recentSheetsData) {
				try {
					const recentSheets = JSON.parse(recentSheetsData);
					if (recentSheets && recentSheets.length > 0) {
						// Find a sheet that matches the current spreadsheet
						const savedSheet = recentSheets.find(
							(sheet: SheetInfoType) => sheet.id === $selectedSheet.id
						);

						if (savedSheet) {
							console.log('Found saved sheet configuration:', savedSheet);
							// We have a saved sheet for this spreadsheet
							selectedSheetName = savedSheet.columnMapping.sheetName;
							savedSheetInfo = savedSheet;

							if (savedSheet.columnMapping) {
								// Set the mapped indices from saved data
								mappedIndices = {
									name: savedSheet.columnMapping.name,
									nationality: savedSheet.columnMapping.nationality,
									birthday: savedSheet.columnMapping.birthday,
									pictureUrl: savedSheet.columnMapping.pictureUrl,
									alreadyPrinted: savedSheet.columnMapping.alreadyPrinted,
									sheetName: selectedSheetName
								};

								hasSavedMapping = true;
								updateMappingStatus();

								return;
							}
						}
					}
				} catch (err) {
					console.error('Error parsing saved sheets data:', err);
				}
			}

			// If no saved data was found or it couldn't be used, load sheets as usual
			await loadAvailableSheets();
		} else {
			console.error('No spreadsheet selected on mount');
		}
	});

	async function loadAvailableSheets() {
		if (!$selectedSheet) {
			console.error('Cannot load available sheets: no sheet selected');
			return;
		}

		console.log('Loading available sheets for spreadsheet:', $selectedSheet.id);
		isLoadingSheets = true;
		error = '';

		try {
			const sheetNames = await getSheetNames($selectedSheet.id);
			console.log('Loaded sheet names:', sheetNames);
			availableSheets = sheetNames;
		} catch (err) {
			console.error('Error loading sheet names:', err);
			error = 'Failed to load sheet names. Please try again.';
		} finally {
			isLoadingSheets = false;
		}
	}

	function handleSheetSelect(sheetName: string) {
		console.log('Sheet selected:', sheetName);
		selectedSheetName = sheetName;

		// Clear any previous data when selecting a new sheet
		sheetHeaders = [];
		previewData = [];
		mappedIndices = {
			name: -1,
			nationality: -1,
			birthday: -1,
			pictureUrl: -1,
			alreadyPrinted: -1,
			sheetName: sheetName
		};
		mappingComplete = false;
		hasSavedMapping = false;
		showMappingEditor = true;

		// Load sheet data
		if (sheetName) {
			loadSheetData(sheetName);
		}
	}

	async function loadSheetData(sheetName: string) {
		if (!$selectedSheet) {
			console.error('Cannot load sheet data: no sheet selected');
			return;
		}

		console.log('Loading sheet data for spreadsheet:', $selectedSheet.id, 'sheet:', sheetName);
		isLoadingData = true;
		error = '';

		try {
			// Fetch first 10 rows for headers and preview
			const range = `${sheetName}!A1:Z10`;
			const data = await getSheetData($selectedSheet.id, range);

			if (data && data.length > 0) {
				console.log('Loaded sheet data with', data.length, 'rows');
				sheetHeaders = data[0];
				previewData = data.slice(1, Math.min(4, data.length)); // Get up to 3 rows for preview
				// We don't need to set all the raw data here

				// Try to auto-map columns
				autoMapColumns();

				// Check if we have saved column mapping for this sheet
				await loadSavedColumnMapping();
			} else {
				error = 'The selected sheet appears to be empty.';
				console.warn('Sheet is empty');
			}
		} catch (err) {
			console.error('Error loading sheet data:', err);
			error = 'Failed to load sheet data. Please try again.';
		} finally {
			isLoadingData = false;
		}
	}

	function autoMapColumns() {
		// Reset mappings
		mappedIndices = {
			name: -1,
			nationality: -1,
			birthday: -1,
			pictureUrl: -1,
			alreadyPrinted: -1,
			sheetName: selectedSheetName
		};

		// Auto-mapping patterns
		const patterns: Record<keyof Omit<ColumnMappingType, 'sheetName'>, RegExp> = {
			name: /full[\s_-]*name|name/i,
			nationality: /nationality|country|nation/i,
			birthday: /birth|date[\s_-]*of[\s_-]*birth|birthday|dob/i,
			pictureUrl: /photo|picture|image|url|avatar/i,
			alreadyPrinted: /already[\s_-]*printed|printed|status/i
		};

		sheetHeaders.forEach((header, index) => {
			for (const [field, pattern] of Object.entries(patterns)) {
				const key = field as keyof ColumnMappingType;
				if (pattern.test(header) && mappedIndices[key] === -1) {
					mappedIndices[key] = index;
					break;
				}
			}
		});

		// If "Already Printed" column wasn't found, try to find the first empty column
		if (mappedIndices.alreadyPrinted === -1 && previewData.length > 0) {
			// Check up to 26 columns (A-Z) or the number of headers, whichever is larger
			const maxColumns = Math.max(sheetHeaders.length, 26);

			for (let colIndex = 0; colIndex < maxColumns; colIndex++) {
				// Check if this column is empty (all preview rows are empty for this column)
				const isEmpty = previewData.every(
					(row) => !row[colIndex] || String(row[colIndex]).trim() === ''
				);

				// Also check if this column isn't already mapped to another field
				const isAlreadyMapped = Object.entries(mappedIndices).some(
					([field, index]) =>
						field !== 'alreadyPrinted' &&
						index === colIndex &&
						field !== 'sheetName' &&
						index === colIndex
				);

				if (isEmpty && !isAlreadyMapped) {
					mappedIndices.alreadyPrinted = colIndex;
					break;
				}
			}
		}

		console.log('Auto-mapped columns:', mappedIndices);
		updateMappingStatus();
	}

	async function loadSavedColumnMapping() {
		if (!$selectedSheet || !selectedSheetName) {
			console.log('Cannot load saved column mapping: missing selectedSheet or selectedSheetName');
			return;
		}

		try {
			const key = await getRecentSheetsKey();
			const existingData = localStorage.getItem(key);

			if (existingData) {
				const recentSheets = JSON.parse(existingData);
				const savedSheet = recentSheets.find(
					(sheet: SheetInfoType) => sheet.id === $selectedSheet.id
				);

				if (savedSheet && savedSheet.columnMapping) {
					console.log('Found saved column mapping for current sheet:', savedSheet.columnMapping);

					// Override auto-mapping with saved mapping
					mappedIndices = {
						name: savedSheet.columnMapping.name ?? -1,
						nationality: savedSheet.columnMapping.nationality ?? -1,
						birthday: savedSheet.columnMapping.birthday ?? -1,
						pictureUrl: savedSheet.columnMapping.pictureUrl ?? -1,
						alreadyPrinted: savedSheet.columnMapping.alreadyPrinted ?? -1,
						sheetName: selectedSheetName
					};

					hasSavedMapping = true;
					savedSheetInfo = savedSheet;
					updateMappingStatus();
				} else {
					console.log('No saved column mapping found for the current sheet');
				}
			}
		} catch (err) {
			console.error('Failed to load saved column mapping:', err);
		}
	}

	function handleColumnMapping(field: keyof ColumnMappingType, index: number) {
		if (!mappedIndices) {
			mappedIndices = {
				name: -1,
				nationality: -1,
				birthday: -1,
				pictureUrl: -1,
				alreadyPrinted: -1,
				sheetName: selectedSheetName
			};
		}
		mappedIndices[field] = index;
		updateMappingStatus();
	}

	function updateMappingStatus() {
		if (!mappedIndices) {
			mappingComplete = false;
			return;
		}
		// Only check required fields for completion
		const requiredIndices = {
			name: mappedIndices.name,
			nationality: mappedIndices.nationality,
			birthday: mappedIndices.birthday,
			pictureUrl: mappedIndices.pictureUrl,
			sheetName: selectedSheetName
		};

		mappingComplete = Object.values(requiredIndices).every((index) => index !== -1);
		console.log('Mapping complete:', mappingComplete);

		// Update the column mapping store
		columnMapping.set({
			name: mappedIndices.name,
			nationality: mappedIndices.nationality,
			birthday: mappedIndices.birthday,
			pictureUrl: mappedIndices.pictureUrl,
			alreadyPrinted: mappedIndices.alreadyPrinted,
			sheetName: selectedSheetName
		});
	}

	async function handleContinue() {
		if (!mappingComplete || !$selectedSheet || !selectedSheetName) return;

		// Save column mapping to localStorage for the selected sheet
		try {
			const key = await getRecentSheetsKey();
			const existingData = localStorage.getItem(key);
			let recentSheets = existingData ? JSON.parse(existingData) : [];

			// Find the current sheet in recent sheets and update its column mapping
			const sheetIndex = recentSheets.findIndex(
				(sheet: SheetInfoType) => sheet.id === $selectedSheet.id
			);

			const columnMappingData = {
				name: mappedIndices.name,
				nationality: mappedIndices.nationality,
				birthday: mappedIndices.birthday,
				pictureUrl: mappedIndices.pictureUrl,
				alreadyPrinted: mappedIndices.alreadyPrinted,
				sheetName: selectedSheetName
			};

			if (sheetIndex !== -1) {
				// Update existing entry
				recentSheets[sheetIndex].columnMapping = columnMappingData;
				recentSheets[sheetIndex].lastUsed = new Date().toISOString();
			} else {
				// Add new entry
				const newEntry = {
					id: $selectedSheet.id,
					name: $selectedSheet.name,
					columnMapping: columnMappingData,
					lastUsed: new Date().toISOString()
				};

				recentSheets.unshift(newEntry);

				// Keep only the 3 most recent
				if (recentSheets.length > 3) {
					recentSheets = recentSheets.slice(0, 3);
				}
			}

			localStorage.setItem(key, JSON.stringify(recentSheets));
		} catch (err) {
			console.error('Failed to save column mapping to localStorage:', err);
		}
	}

	async function handleShowEditor() {
		showMappingEditor = true;

		// Load available sheets if they haven't been loaded yet
		if (availableSheets.length === 0) {
			await loadAvailableSheets();
		}

		// Ensure we have sheet data if a sheet is already selected
		if (selectedSheetName && sheetHeaders.length === 0) {
			// Load the sheet data but keep mappings intact
			try {
				isLoadingData = true;
				const range = `${selectedSheetName}!A1:Z10`;
				const data = await getSheetData($selectedSheet.id, range);

				if (data && data.length > 0) {
					sheetHeaders = data[0];
					previewData = data.slice(1, Math.min(4, data.length));
				}
			} catch (err) {
				console.error('Error loading sheet data for editor:', err);
			} finally {
				isLoadingData = false;
			}
		}
	}
</script>

<div class="p-6">
	<div class="mb-6">
		<h2 class="mb-2 text-xl font-semibold text-gray-900">Select Sheet and Map Columns</h2>

		<p class="mb-4 text-sm text-gray-700">
			First, select which sheet contains your member data, then map the columns to the required
			fields.
		</p>
	</div>

	{#if hasSavedMapping && !showMappingEditor}
		<!-- Simplified view when we have saved mapping -->
		<div class="mb-6 rounded-lg border border-blue-200 bg-blue-50 p-4">
			<div class="flex">
				<div class="flex-shrink-0">
					<svg
						class="h-5 w-5 text-blue-400"
						xmlns="http://www.w3.org/2000/svg"
						viewBox="0 0 20 20"
						fill="currentColor"
						aria-hidden="true"
					>
						<path
							fill-rule="evenodd"
							d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zm-4 4a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
							clip-rule="evenodd"
						/>
					</svg>
				</div>
				<div class="ml-3 flex-1 md:flex md:justify-between">
					<div>
						<h3 class="text-sm font-medium text-blue-800">Saved Configuration Found</h3>
						<div class="mt-2 text-sm text-blue-700">
							<p>
								Using saved mapping for sheet <span class="font-semibold"
									>"{selectedSheetName}"</span
								>
								from spreadsheet <span class="font-semibold">"{savedSheetInfo?.name}"</span>.
							</p>
						</div>
					</div>
					<div class="mt-3 md:mt-0 md:ml-6">
						<button
							onclick={handleShowEditor}
							class="rounded-md border border-transparent bg-blue-600 px-4 py-2 text-sm font-medium whitespace-nowrap text-white shadow-sm hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-none"
						>
							Edit Mapping
						</button>
					</div>
				</div>
			</div>
		</div>
	{:else}
		<!-- Sheet Selection -->
		<div class="mb-6 rounded-lg border border-gray-200 bg-gray-50 p-4">
			<h3 class="mb-3 text-sm font-medium text-gray-700">Step 1: Select Sheet</h3>

			{#if isLoadingSheets}
				<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-gray-600">Loading sheets...</span>
				</div>
			{:else if error}
				<div class="mb-3 rounded-lg border border-red-300 bg-red-50 p-3">
					<p class="text-sm text-red-800">{error}</p>
					<button
						class="mt-2 text-sm text-blue-600 hover:text-blue-800"
						onclick={loadAvailableSheets}
					>
						Try again
					</button>
				</div>
			{:else if availableSheets.length === 0}
				<div class="rounded border border-gray-200 bg-white py-6 text-center">
					<svg
						class="mx-auto h-12 w-12 text-gray-400"
						fill="none"
						viewBox="0 0 24 24"
						stroke="currentColor"
					>
						<path
							stroke-linecap="round"
							stroke-linejoin="round"
							stroke-width="2"
							d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
						/>
					</svg>
					<h3 class="mt-2 text-sm font-medium text-gray-900">No sheets found</h3>
					<p class="mt-1 text-sm text-gray-500">
						This spreadsheet doesn't appear to contain any sheets.
					</p>
				</div>
			{:else}
				<div class="space-y-3">
					<p class="text-sm text-gray-600">
						Spreadsheet: <span class="font-medium">{$selectedSheet?.name}</span>
					</p>

					<div>
						<p class="mb-3 block text-sm font-medium text-gray-700">Choose sheet:</p>

						<div class="space-y-2">
							{#each availableSheets as sheetName}
								<div
									role="button"
									tabindex="0"
									class="cursor-pointer rounded-lg border p-3 transition-colors hover:bg-gray-50
                           {selectedSheetName === sheetName
										? 'border-blue-500 bg-blue-50'
										: 'border-gray-200'}"
									onclick={() => handleSheetSelect(sheetName)}
									onkeydown={(e) => e.key === 'Enter' && handleSheetSelect(sheetName)}
								>
									<div class="flex items-center">
										<div class="flex-shrink-0">
											<div
												class="flex h-4 w-4 items-center justify-center rounded-full border-2
                                    {selectedSheetName === sheetName
													? 'border-blue-500 bg-blue-500'
													: 'border-gray-300'}"
											>
												{#if selectedSheetName === sheetName}
													<div class="h-2 w-2 rounded-full bg-white"></div>
												{/if}
											</div>
										</div>

										<div class="ml-3 flex-grow">
											<p class="text-sm font-medium text-gray-900">{sheetName}</p>
										</div>

										{#if selectedSheetName === sheetName}
											<div class="flex-shrink-0">
												<svg class="h-5 w-5 text-blue-600" fill="currentColor" viewBox="0 0 20 20">
													<path
														fill-rule="evenodd"
														d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
														clip-rule="evenodd"
													/>
												</svg>
											</div>
										{/if}
									</div>
								</div>
							{/each}
						</div>
					</div>
				</div>
			{/if}
		</div>

		<!-- Column Mapping Section -->
		<div class="mb-6 rounded-lg border border-gray-200 bg-gray-50 p-4">
			<h3 class="mb-3 text-sm font-medium text-gray-700">Step 2: Map Columns</h3>

			{#if isLoadingData}
				<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-gray-600">Loading sheet data...</span>
				</div>
			{:else if sheetHeaders.length === 0}
				<div class="py-8 text-center text-gray-500">
					<p class="text-sm">Select a sheet above to map columns</p>
				</div>
			{:else}
				<div class="space-y-4">
					<p class="mb-4 text-sm text-gray-600">
						Map the columns from your sheet to the required fields:
					</p>

					<!-- Column mapping dropdowns -->
					<div class="grid gap-4">
						{#each requiredFields as field}
							<div class="flex items-center">
								<div class="w-32 flex-shrink-0">
									<label for={`field-${field.key}`} class="text-sm font-medium text-gray-700">
										{field.label}
										{#if field.required}
											<span class="text-red-500">*</span>
										{/if}
									</label>
								</div>

								<div class="flex-grow">
									<select
										id={`field-${field.key}`}
										bind:value={mappedIndices[field.key]}
										onchange={() =>
											handleColumnMapping(
												field.key as keyof ColumnMappingType,
												mappedIndices[field.key]
											)}
										class="w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-gray-900 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-none"
									>
										<option value={-1}>-- Select column --</option>
										{#each Array.from({ length: Math.max(sheetHeaders.length, 26) }, (_, i) => i) as index}
											<option value={index}>
												{sheetHeaders[index] || `Column ${String.fromCharCode(65 + index)}`}
												{#if !sheetHeaders[index]}
													(empty)
												{/if}
											</option>
										{/each}
									</select>
								</div>
							</div>
						{/each}
					</div>

					<!-- Data preview -->
					{#if previewData.length > 0}
						<div class="mt-6">
							<h4 class="mb-3 text-sm font-medium text-gray-700">Data Preview:</h4>
							<div class="overflow-x-auto">
								<table
									class="min-w-full divide-y divide-gray-200 rounded-lg border border-gray-200"
								>
									<thead class="bg-gray-50">
										<tr>
											{#each Array.from({ length: Math.min(Math.max(sheetHeaders.length, previewData[0]?.length || 0), 26) }, (_, i) => i) as index}
												<th
													class="px-3 py-2 text-left text-xs font-medium tracking-wider text-gray-500 uppercase
                                     {Object.values(mappedIndices).includes(index)
														? 'bg-blue-100'
														: ''}"
												>
													{sheetHeaders[index] || `Column ${String.fromCharCode(65 + index)}`}
													{#if Object.values(mappedIndices).includes(index)}
														<div class="mt-1 text-xs text-blue-600">
															{requiredFields.find((f) => mappedIndices[f.key] === index)?.label}
														</div>
													{/if}
												</th>
											{/each}
										</tr>
									</thead>
									<tbody class="divide-y divide-gray-200 bg-white">
										{#each previewData as row}
											<tr>
												{#each Array.from({ length: Math.min(Math.max(sheetHeaders.length, row.length), 26) }, (_, i) => i) as index}
													<td
														class="max-w-xs truncate px-3 py-2 text-sm text-gray-500
                                       {Object.values(mappedIndices).includes(index)
															? 'bg-blue-50'
															: ''}"
													>
														{row[index] || ''}
													</td>
												{/each}
											</tr>
										{/each}
									</tbody>
								</table>
							</div>
						</div>
					{/if}

					{#if mappingComplete}
						<div class="rounded-md border border-green-200 bg-green-50 p-4">
							<div class="flex">
								<div class="flex-shrink-0">
									<svg
										class="h-5 w-5 text-green-400"
										xmlns="http://www.w3.org/2000/svg"
										viewBox="0 0 20 20"
										fill="currentColor"
										aria-hidden="true"
									>
										<path
											fill-rule="evenodd"
											d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
											clip-rule="evenodd"
										/>
									</svg>
								</div>
								<div class="ml-3">
									<p class="text-sm font-medium text-green-800">
										All required fields are mapped. You can now proceed.
									</p>
								</div>
							</div>
						</div>
					{:else}
						<div class="rounded-md bg-yellow-50 p-4">
							<div class="flex">
								<div class="flex-shrink-0">
									<svg
										class="h-5 w-5 text-yellow-400"
										xmlns="http://www.w3.org/2000/svg"
										viewBox="0 0 20 20"
										fill="currentColor"
										aria-hidden="true"
									>
										<path
											fill-rule="evenodd"
											d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 3.01-1.742 3.01H4.42c-1.53 0-2.493-1.676-1.743-3.01l5.58-9.92zM10 5a1 1 0 011 1v3a1 1 0 01-2 0V6a1 1 0 011-1zm1 5a1 1 0 10-2 0v2a1 1 0 102 0v-2z"
											clip-rule="evenodd"
										/>
									</svg>
								</div>
								<div class="ml-3">
									<p class="text-sm text-yellow-800">
										Please map all required fields (<span class="text-red-500">*</span>) to
										continue.
									</p>
								</div>
							</div>
						</div>
					{/if}
				</div>
			{/if}
		</div>
	{/if}

	<!-- Navigation -->
	<Navigator
		canProceed={mappingComplete}
		{currentStep}
		textBack="Back to Sheet Selection"
		textForwardDisabled="Select a column mapping"
		textForwardEnabled="Continue to Row Selection"
		onForward={handleContinue}
	/>
</div>
