<script lang="ts">
	import {
		sheetData,
		columnMapping,
		selectedSheet,
		currentStep,
	} from '$lib/stores';
	import type { RowData } from '$lib/stores';
	import { getSheetData, ensureToken } from '$lib/google';
	import { v4 as uuid } from 'uuid';
	import Navigator from './subcomponents/Navigator.svelte';
	import { onMount } from 'svelte';
	import { parseAndFormatDate } from '$lib/utils/date';

	let isLoading = $state(true);
	let error = $state<string | null>(null);
	let rows = $state<RowData[]>([]);

	let sortColumn = $state<keyof RowData | null>(null);
	let sortDirection = $state<'asc' | 'desc'>('asc');
	let lastCheckedId: string | null = $state(null);

	const ROW_LIMIT = 200;

	// Fetch and process data from the Google Sheet
	async function fetchAndProcessData() {
		isLoading = true;
		error = null;
		try {
			const sheet = $selectedSheet;
			const mapping = $columnMapping;

			if (!sheet || !mapping || !mapping.sheetName) {
				error = 'Sheet information or column mapping is missing.';
				isLoading = false;
				rows = [];
				return;
			}

			const range = `${mapping.sheetName}!A:Z`;
			const rawData = await getSheetData(sheet.id, range);

			if (!rawData || rawData.length < 2) {
				// Handle case with no data or only headers
				rows = [];
				isLoading = false;
				return;
			}

			const dataRows = rawData.slice(1);

			const processedData = dataRows
				.map((row, index): RowData | null => {
					const name = mapping.name !== -1 ? row[mapping.name] || '' : '';
					const pictureUrl = mapping.pictureUrl !== -1 ? row[mapping.pictureUrl] || '' : '';

					const birthdayRaw = mapping.birthday !== -1 ? row[mapping.birthday] : '';
					const birthday = parseAndFormatDate(birthdayRaw);

					if (!name && !pictureUrl) {
						return null; // Skip entirely empty rows
					}

					const alreadyPrinted =
						mapping.alreadyPrinted !== -1
							? (row[mapping.alreadyPrinted] || '').toLowerCase() === 'true'
							: false;

					const isValid = !!(name && pictureUrl);

					return {
						id: uuid(),
						name,
						nationality: mapping.nationality !== -1 ? row[mapping.nationality] || '' : '',
						birthday,
						pictureUrl,
						alreadyPrinted,
						_rowIndex: index + 1,
						_valid: isValid,
						_checked: false
					};
				})
				.filter((row): row is RowData => row !== null);

			rows = processedData;
		} catch (e: any) {
			error = e.message || 'An unknown error occurred while fetching data.';
			console.error(e);
			rows = [];
		} finally {
			isLoading = false;
		}
	}

	function handleRowClick(event: MouseEvent, clickedId: string) {
		const clickedRow = rows.find((r) => r.id === clickedId);
		if (!clickedRow || !clickedRow._valid) return;

		// Handle shift-clicking for range selection
		if (event.shiftKey && lastCheckedId) {
			const lastIndex = displayData.findIndex((r) => r.id === lastCheckedId);
			const currentIndex = displayData.findIndex((r) => r.id === clickedId);

			if (lastIndex !== -1 && currentIndex !== -1) {
				const start = Math.min(lastIndex, currentIndex);
				const end = Math.max(lastIndex, currentIndex);
				const isChecked = !clickedRow._checked; // The state to apply to the range

				for (let i = start; i <= end; i++) {
					const rowToSelect = displayData[i];
					if (rowToSelect && rowToSelect._valid) {
						// Prevent checking more than the limit
						if (isChecked && selectedCount >= ROW_LIMIT && !rowToSelect._checked) {
							continue;
						}
						rowToSelect._checked = isChecked;
					}
				}
			}
		} else {
			// Normal click, just toggle the state
			if (!clickedRow._checked && selectedCount >= ROW_LIMIT) {
				// Do not allow checking more than the limit
			} else {
				clickedRow._checked = !clickedRow._checked;
			}
		}

		// Update the last checked ID for the next shift-click
		lastCheckedId = clickedId;
	}

	// Run on component mount
	onMount(() => {
		ensureToken();
		fetchAndProcessData();
	});

	// Function to toggle select-all: selects first 200 eligible items in current view
	function toggleSelectAll(event: Event) {
		const target = event.target as HTMLInputElement;
		const shouldCheck = target.checked;

		// Determine eligible rows in the current display order
		const eligible = displayData.filter((r) => r._valid && !r.alreadyPrinted);
		const firstBatch = eligible.slice(0, ROW_LIMIT);

		if (shouldCheck) {
			// Check only the first batch, uncheck the rest
			rows.forEach((row) => (row._checked = false));
			firstBatch.forEach((row) => (row._checked = true));
		} else {
			// Uncheck all
			rows.forEach((row) => (row._checked = false));
		}
	}

	// Function to handle sorting
	function sortBy(column: keyof RowData) {
		if (sortColumn === column) {
			sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
		} else {
			sortColumn = column;
			sortDirection = 'asc';
		}
	}

	// Derived state for sorted data to be displayed
	const displayData = $derived.by(() => {
		if (!sortColumn) return rows;

		return [...rows].sort((a, b) => {
			const aValue = a[sortColumn];
			const bValue = b[sortColumn];

			if (aValue === bValue) return 0;

			let comparison = 0;
			if (aValue > bValue) {
				comparison = 1;
			} else {
				comparison = -1;
			}

			return sortDirection === 'asc' ? comparison : -comparison;
		});
	});

	// Derived state: master checkbox reflects if first 200 eligible items in current view are selected
	const allValidRowsSelected = $derived.by(() => {
		const eligible = displayData.filter((r) => r._valid && !r.alreadyPrinted);
		const firstBatch = eligible.slice(0, ROW_LIMIT);
		if (firstBatch.length === 0) return false;
		return firstBatch.every((row) => row._checked);
	});

	const selectedCount = $derived(rows.filter((row) => row._checked).length);

	function handleContinue() {
		$sheetData = rows.filter((row) => row._checked);
	}
</script>

<div class="container max-w-none p-6">
	<div class="mb-4 flex items-center justify-between">
		<div>
			<h2 class="mb-2 text-xl font-semibold text-gray-900">Filter and Select Rows</h2>
			<p class="text-sm text-gray-700">
				Review your data and select which rows to include. Select a batch of max 200 items by using
				the top checkbox.
			</p>
			<p class="mt-1 text-sm text-gray-700">
				Tip: Hold <kbd
					class="rounded-md border border-gray-400 bg-gray-200 px-1.5 py-0.5 text-xs font-semibold"
					>Shift</kbd
				> and click two checkboxes to select a range of rows.
			</p>
			<p class="mt-1 text-sm text-gray-700">
				Already printed or invalid data is marked in the status column.
			</p>
		</div>
		<div class="flex flex-col space-y-2">
			{#if $selectedSheet?.id}
				<a
					href={`https://docs.google.com/spreadsheets/d/${$selectedSheet.id}/edit`}
					target="_blank"
					rel="noopener noreferrer"
					class="inline-flex items-center justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
				>
					Open Sheet
				</a>
			{/if}
			<button
				onclick={fetchAndProcessData}
				class="inline-flex items-center justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:cursor-wait disabled:opacity-50"
				disabled={isLoading}
			>
				{#if isLoading}
					<svg
						class="-ml-1 mr-2 h-5 w-5 animate-spin text-gray-500"
						xmlns="http://www.w3.org/2000/svg"
						fill="none"
						viewBox="0 0 24 24"
					>
						<circle
							class="opacity-25"
							cx="12"
							cy="12"
							r="10"
							stroke="currentColor"
							stroke-width="4"
						></circle>
						<path
							class="opacity-75"
							fill="currentColor"
							d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
						></path>
					</svg>
					Refreshing...
				{:else}
					Refresh Data
				{/if}
			</button>
		</div>
	</div>

	{#if isLoading}
		<div class="py-12 text-center">
			<p class="text-lg">Loading data from Google Sheet...</p>
			<p class="text-gray-500">Please wait a moment.</p>
		</div>
	{:else if error}
		<div
			class="rounded-md border border-red-400 bg-red-50 p-4"
		>
			<div class="flex">
				<div class="flex-shrink-0">
					<svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
						<path
							fill-rule="evenodd"
							d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z"
							clip-rule="evenodd"
						/>
					</svg>
				</div>
				<div class="ml-3">
					<h3 class="text-sm font-medium text-red-800">An Error Occurred</h3>
					<div class="mt-2 text-sm text-red-700">
						<p>{error}</p>
					</div>
				</div>
			</div>
		</div>
	{:else if rows.length === 0}
		<div class="py-12 text-center">
			<h3 class="text-lg font-medium text-gray-900">No Data Found</h3>
			<p class="mt-1 text-sm text-gray-500">
				The selected sheet appears to be empty or could not be read.
			</p>
		</div>
	{:else}
		<div class="overflow-hidden rounded-lg border border-gray-200">
			<div class="overflow-x-auto">
				<table class="min-w-full divide-y divide-gray-200">
					<thead class="bg-gray-50">
						<tr>
							<th class="px-4 py-3 text-left">
								<input
									type="checkbox"
									class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
									onchange={toggleSelectAll}
									checked={allValidRowsSelected}
								/>
							</th>
							<th
								class="cursor-pointer px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-gray-600 hover:bg-gray-100"
								onclick={() => sortBy('_rowIndex')}>#</th
							>
							<th
								class="cursor-pointer px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-gray-600 hover:bg-gray-100"
								onclick={() => sortBy('name')}>Full Name</th
							>
							<th
								class="cursor-pointer px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-gray-600 hover:bg-gray-100"
								onclick={() => sortBy('nationality')}>Nationality</th
							>
							<th
								class="cursor-pointer px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-gray-600 hover:bg-gray-100"
								onclick={() => sortBy('birthday')}>Birthday</th
							>
							<th
								class="cursor-pointer px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-gray-600 hover:bg-gray-100"
								onclick={() => sortBy('pictureUrl')}>Picture URL</th
							>
							<th
								class="cursor-pointer px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-gray-600 hover:bg-gray-100"
								onclick={() => sortBy('alreadyPrinted')}>Printed</th
							>
							<th
								class="cursor-pointer px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-gray-600 hover:bg-gray-100"
								onclick={() => sortBy('_valid')}>Status</th
							>
						</tr>
					</thead>
					<tbody class="divide-y divide-gray-200 bg-white">
						{#each displayData as row (row.id)}
							<tr
								class="hover:bg-gray-50"
								class:bg-gray-100={!row._valid}
								class:text-gray-400={!row._valid || row.alreadyPrinted}
								class:bg-orange-50={row.alreadyPrinted}
							>
								<td class="px-4 py-3">
									<input
										type="checkbox"
										class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 disabled:cursor-not-allowed disabled:bg-gray-200"
										checked={row._checked}
										disabled={!row._valid || (selectedCount >= ROW_LIMIT && !row._checked)}
										onclick={(e) => handleRowClick(e, row.id)}
									/>
								</td>
								<td class="whitespace-nowrap px-4 py-3 text-sm">{row._rowIndex}</td>
								<td class="whitespace-nowrap px-4 py-3 text-sm">{row.name}</td>
								<td class="whitespace-nowrap px-4 py-3 text-sm">{row.nationality}</td>
								<td class="whitespace-nowrap px-4 py-3 text-sm">{row.birthday}</td>
								<td class="whitespace-nowrap px-4 py-3 text-sm">
									<a
										href={row.pictureUrl}
										target="_blank"
										rel="noopener noreferrer"
										class="text-blue-600 hover:underline"
										title={row.pictureUrl}>link</a
									>
								</td>
								<td class="whitespace-nowrap px-4 py-3 text-sm">
									{#if row.alreadyPrinted}
										<span
											class="inline-flex rounded-full bg-orange-100 px-2 text-xs font-semibold leading-5 text-orange-800"
											>Yes</span
										>
									{:else}
										<span
											class="inline-flex rounded-full bg-gray-100 px-2 text-xs font-semibold leading-5 text-gray-800"
											>No</span
										>
									{/if}
								</td>
								<td class="whitespace-nowrap px-4 py-3 text-sm">
									{#if row._valid}
										<span
											class="inline-flex rounded-full bg-green-100 px-2 text-xs font-semibold leading-5 text-green-800"
											>Valid</span
										>
									{:else}
										<span
											class="inline-flex rounded-full bg-red-100 px-2 text-xs font-semibold leading-5 text-red-800"
											>Invalid</span
										>
									{/if}
								</td>
							</tr>
						{/each}
					</tbody>
				</table>
			</div>
		</div>
	{/if}

	<div class="mt-6">
		<Navigator
			canProceed={selectedCount > 0}
			currentStep={currentStep}
			onForward={handleContinue}
			textBack="Back to Column Mapping"
			textForwardEnabled="Continue to Card Details"
			textForwardDisabled="Select at least one valid row"
		/>
	</div>
</div>
