<!-- #region ValidationTasksPage [C:3] [TYPE Page] [SEMANTICS validation,tasks,list,table] -->
<!-- @BRIEF Validation tasks list page — table layout with status filter, pagination, and inline actions. -->
<!-- @RELATION CALLS -> [ValidationApi] -->
<!-- @UX_STATE Loading -> Skeleton table rows matching column layout -->
<!-- @UX_STATE Loaded -> Data rows with all columns -->
<!-- @UX_STATE Empty -> Centered empty card with CTA to create first task -->
<!-- @UX_STATE Error -> Red banner with error details and retry button -->
<!-- @UX_FEEDBACK Toast on run trigger, delete success, toggle error -->
<!-- @UX_RECOVERY Retry button on load error; inline confirm on delete -->
<script lang="ts">
	import { goto } from '$app/navigation';
	import { t } from '$lib/i18n/index.svelte.js';
	import { addToast } from '$lib/toasts.svelte.js';
	import { api } from '$lib/api.js';
	import { onMount } from 'svelte';
	import { log } from '$lib/cot-logger';

	/** @type {{ data: import('./$types').PageData }} */
	let { data } = $props();

	// ── Derived initial state from load function ───────────────
	/** @type {Array<any>} */ let tasks = $state(data.tasks ?? []);
	/** @type {number} */ let total = $state(data.total ?? 0);
	/** @type {number} */ let currentPage = $state(data.page ?? 1);
	/** @type {number} */ let pageSize = $state(data.page_size ?? 20);
	/** @type {string | null} */ let error = $state(data.error ?? null);
	let isLoading = $state(false);
	let searchQuery = $state('');

	/** @type {Record<string, boolean>} */
	let runningTasks = $state({});
	let deleteConfirmId = $state(/** @type {string | null} */(null));
	let isMounted = $state(true);

	onMount(() => {
		return () => { isMounted = false; };
	});

	// ── Derived ────────────────────────────────────────────────
	let totalPages = $derived(Math.max(1, Math.ceil(total / pageSize)));

	// ── Data fetching ──────────────────────────────────────────
	async function loadTasks() {
		isLoading = true;
		error = null;
		log('ValidationTasksPage', 'REASON', 'Loading validation tasks', {
			page: currentPage, pageSize, search: searchQuery || undefined
		});
		try {
			const result = await api.getValidationTasks({
				page: currentPage,
				page_size: pageSize,
				search: searchQuery || undefined
			});
			if (!isMounted) return;
			const items = result?.tasks ?? result?.results ?? [];
			tasks = items;
			total = result?.total ?? 0;
			log('ValidationTasksPage', 'REFLECT', 'Tasks loaded', { count: items.length, total });
		} catch (e) {
			if (!isMounted) return;
			const msg = e instanceof Error ? e.message : 'Failed to load tasks';
			error = msg;
			log('ValidationTasksPage', 'EXPLORE', 'Failed to load tasks', {}, msg);
		} finally {
			if (isMounted) isLoading = false;
		}
	}

	// ── Search with debounce ──────────────────────────────────
	let searchTimeout = $state(/** @type {ReturnType<typeof setTimeout> | undefined} */(undefined));

	function handleSearchInput(/** @type {string} */ value) {
		searchQuery = value;
		if (searchTimeout) clearTimeout(searchTimeout);
		searchTimeout = setTimeout(() => {
			currentPage = 1;
			loadTasks();
		}, 300);
	}

	// ── Navigation ─────────────────────────────────────────────
	function navToNew() {
		goto('/validation-tasks/new', { invalidateAll: false });
	}

	function navToDetail(/** @type {string} */ id) {
		goto(`/validation-tasks/${encodeURIComponent(id)}`, { invalidateAll: false });
	}

	function navToEdit(/** @type {string} */ id) {
		goto(`/validation-tasks/${encodeURIComponent(id)}/edit`, { invalidateAll: false });
	}

	// ── Actions ─────────────────────────────────────────────────
	async function handleRunNow(/** @type {string} */ id) {
		runningTasks = { ...runningTasks, [id]: true };
		log('ValidationTasksPage', 'REASON', 'Triggering run', { taskId: id });
		try {
			await api.triggerValidationRun(id);
			if (!isMounted) return;
			addToast($t.validation?.run_started || 'Validation task started', 'success');
			log('ValidationTasksPage', 'REFLECT', 'Run triggered', { taskId: id });
		} catch (e) {
			if (!isMounted) return;
			const msg = e instanceof Error ? e.message : 'Failed to trigger run';
			addToast(msg, 'error');
			log('ValidationTasksPage', 'EXPLORE', 'Failed to trigger run', { taskId: id }, msg);
		} finally {
			if (isMounted) runningTasks = { ...runningTasks, [id]: false };
		}
	}

	async function handleDelete(/** @type {string} */ id) {
		log('ValidationTasksPage', 'REASON', 'Deleting task', { taskId: id });
		try {
			await api.deleteValidationTask(id);
			if (!isMounted) return;
			addToast($t.validation?.delete_success || 'Task deleted', 'success');
			deleteConfirmId = null;
			// Refresh list
			tasks = tasks.filter(t => t.id !== id);
			total = Math.max(0, total - 1);
			log('ValidationTasksPage', 'REFLECT', 'Task deleted', { taskId: id });
		} catch (e) {
			if (!isMounted) return;
			const msg = e instanceof Error ? e.message : 'Failed to delete';
			addToast(msg, 'error');
			deleteConfirmId = null;
			log('ValidationTasksPage', 'EXPLORE', 'Failed to delete task', { taskId: id }, msg);
		}
	}

	async function handleToggleStatus(/** @type {any} */ task) {
		const newActive = !(task.is_active !== false);
		log('ValidationTasksPage', 'REASON', 'Toggling status', {
			taskId: task.id, from: task.is_active, to: newActive
		});
		try {
			await api.toggleValidationTaskStatus(task.id, newActive);
			if (!isMounted) return;
			task.is_active = newActive;
			tasks = tasks; // trigger reactivity
			log('ValidationTasksPage', 'REFLECT', 'Status toggled', { taskId: task.id, isActive: newActive });
		} catch (e) {
			if (!isMounted) return;
			const msg = e instanceof Error ? e.message : 'Failed to update status';
			addToast(msg, 'error');
			log('ValidationTasksPage', 'EXPLORE', 'Failed to toggle status', { taskId: task.id }, msg);
		}
	}

	// ── Pagination ─────────────────────────────────────────────
	function goToPage(/** @type {number} */ p) {
		if (p < 1 || p > totalPages) return;
		currentPage = p;
		loadTasks();
	}

	// ── Helpers ─────────────────────────────────────────────────
	/**
	 * @param {string | null | undefined} scheduleInput
	 * @returns {string}
	 */
	function formatSchedule(scheduleInput) {
		if (!scheduleInput) return $t.validation?.manual || 'Manual';
		return scheduleInput;
	}

	/**
	 * @param {string | number | Date | null | undefined} ts
	 * @returns {string}
	 */
	function formatTimestamp(ts) {
		if (!ts) return '—';
		try {
			return new Date(ts).toLocaleString();
		} catch {
			return String(ts);
		}
	}

	/**
	 * @param {{ pass?: number, warn?: number, fail?: number } | null | undefined} summary
	 * @returns {string}
	 */
	function formatLastRunSummary(summary) {
		if (!summary) return '—';
		const parts = [];
		if (summary.pass) parts.push(`${summary.pass} PASS`);
		if (summary.warn) parts.push(`${summary.warn} WARN`);
		if (summary.fail) parts.push(`${summary.fail} FAIL`);
		return parts.join(' • ') || '—';
	}

	/**
	 * @param {{ pass?: number, warn?: number, fail?: number } | null | undefined} summary
	 * @returns {string}
	 */
	function getSummaryBadgeClass(summary) {
		if (!summary) return 'bg-gray-100 text-gray-500';
		if (summary.fail && summary.fail > 0) return 'bg-red-100 text-red-700';
		if (summary.warn && summary.warn > 0) return 'bg-amber-100 text-amber-700';
		if (summary.pass && summary.pass > 0) return 'bg-green-100 text-green-700';
		return 'bg-gray-100 text-gray-500';
	}

	/**
	 * @param {any} task
	 * @returns {string}
	 */
	function getEnvLabel(task) {
		return task.environment_name || task.environment_id || '—';
	}

	/**
	 * @param {number} p
	 * @returns {string}
	 */
	function pageBtnClass(p) {
		const base = 'px-3 py-1.5 text-sm rounded-lg border transition-colors';
		if (p === currentPage) return `${base} bg-blue-50 border-blue-300 text-blue-700`;
		return `${base} border-gray-200 text-gray-600 hover:bg-gray-50`;
	}
</script>

<div class="max-w-7xl mx-auto px-4 py-6">
	<!-- Header -->
	<div class="flex items-center justify-between mb-6">
		<h1 class="text-2xl font-bold text-gray-900">
			{$t.validation?.title || 'Validation Tasks'}
		</h1>
		<button
			onclick={navToNew}
			class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium text-sm"
		>
			<svg class="w-5 h-5 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
				<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
			</svg>
			{$t.validation?.new_task || '+ New Task'}
		</button>
	</div>

	<!-- Search bar -->
	<div class="mb-4">
		<div class="relative max-w-sm">
			<svg class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
				<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
			</svg>
			<input
				type="text"
				placeholder={$t.common?.search || 'Search tasks...'}
				value={searchQuery}
				oninput={(e) => handleSearchInput(/** @type {HTMLInputElement} */(e.target).value)}
				class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none"
				aria-label={$t.common?.search || 'Search tasks'}
			/>
		</div>
	</div>

	<!-- Error state -->
	{#if error && !isLoading}
		<div class="bg-red-50 border border-red-200 rounded-lg p-4 mb-6 flex items-center justify-between" role="alert">
			<div class="flex items-center gap-2 text-red-700">
				<svg class="w-5 h-5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
					<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
				</svg>
				<span class="text-sm">{error}</span>
			</div>
			<button
				onclick={loadTasks}
				class="px-3 py-1.5 text-sm bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
			>
				{$t.validation?.retry || 'Retry'}
			</button>
		</div>
	{/if}

	<!-- Loading skeleton -->
	{#if isLoading}
		<div class="bg-white border border-gray-200 rounded-lg overflow-hidden">
			<table class="min-w-full divide-y divide-gray-200">
				<thead class="bg-gray-50">
					<tr>
						<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.validation?.task_name || 'Task Name'}</th>
						<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.validation?.environment || 'Environment'}</th>
						<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.validation?.schedule || 'Schedule'}</th>
						<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.validation?.last_run || 'Last Run'}</th>
						<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.validation?.status || 'Status'}</th>
						<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.validation?.actions || 'Actions'}</th>
					</tr>
				</thead>
				<tbody class="bg-white divide-y divide-gray-200">
					{#each Array(5) as _, i (i)}
						<tr class="animate-pulse">
							<td class="px-6 py-4"><div class="h-4 w-40 bg-gray-200 rounded"></div></td>
							<td class="px-6 py-4"><div class="h-4 w-24 bg-gray-200 rounded"></div></td>
							<td class="px-6 py-4"><div class="h-4 w-20 bg-gray-200 rounded"></div></td>
							<td class="px-6 py-4"><div class="h-4 w-32 bg-gray-200 rounded"></div></td>
							<td class="px-6 py-4"><div class="h-5 w-14 bg-gray-200 rounded-full"></div></td>
							<td class="px-6 py-4"><div class="h-4 w-24 bg-gray-200 rounded ml-auto"></div></td>
						</tr>
					{/each}
				</tbody>
			</table>
		</div>

	<!-- Empty state -->
	{:else if !error && tasks.length === 0}
		<div class="bg-gray-50 border border-dashed border-gray-300 rounded-lg p-12 text-center">
			<svg class="w-16 h-16 mx-auto text-gray-300 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
				<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" 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>
			<p class="text-gray-500 text-sm mb-1">{$t.validation?.no_tasks || 'No validation tasks yet'}</p>
			<p class="text-gray-400 text-sm mb-4">{$t.validation?.create_first || 'Create your first task'}</p>
			<button
				onclick={navToNew}
				class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm font-medium"
			>
				{$t.validation?.new_task || '+ New Task'}
			</button>
		</div>

	<!-- Loaded state: table -->
	{:else}
		<div class="bg-white border border-gray-200 rounded-lg overflow-hidden shadow-sm">
			<div class="overflow-x-auto">
				<table class="min-w-full divide-y divide-gray-200">
					<thead class="bg-gray-50">
						<tr>
							<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.validation?.task_name || 'Task Name'}</th>
							<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.validation?.environment || 'Environment'}</th>
							<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.validation?.schedule || 'Schedule'}</th>
							<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.validation?.last_run || 'Last Run'}</th>
							<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.validation?.status || 'Status'}</th>
							<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">{$t.validation?.actions || 'Actions'}</th>
						</tr>
					</thead>
					<tbody class="bg-white divide-y divide-gray-200">
						{#each tasks as task (task.id)}
							<tr class="hover:bg-gray-50 transition-colors">
								<!-- Task Name -->
								<td class="px-6 py-4 whitespace-nowrap">
									<button
										onclick={() => navToDetail(task.id)}
										class="text-sm font-medium text-blue-600 hover:text-blue-800 hover:underline text-left"
									>
										{task.name || '—'}
									</button>
								</td>

								<!-- Environment -->
								<td class="px-6 py-4 whitespace-nowrap">
									<span class="text-sm text-gray-700">{getEnvLabel(task)}</span>
								</td>

								<!-- Schedule -->
								<td class="px-6 py-4 whitespace-nowrap">
									{#if task.schedule}
										<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-50 text-blue-700">
											{formatSchedule(task.schedule_description || task.schedule)}
										</span>
									{:else}
										<span class="text-sm text-gray-400">{$t.validation?.manual || 'Manual'}</span>
									{/if}
								</td>

								<!-- Last Run -->
								<td class="px-6 py-4 whitespace-nowrap">
									{#if task.last_run_at || task.last_run_summary}
										<div class="flex flex-col gap-0.5">
											{#if task.last_run_at}
												<span class="text-xs text-gray-500">{formatTimestamp(task.last_run_at)}</span>
											{/if}
											{#if task.last_run_summary}
												<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium {getSummaryBadgeClass(task.last_run_summary)}">
													{formatLastRunSummary(task.last_run_summary)}
												</span>
											{/if}
										</div>
									{:else}
										<span class="text-sm text-gray-400">—</span>
									{/if}
								</td>

								<!-- Status Toggle -->
								<td class="px-6 py-4 whitespace-nowrap">
									<button
										onclick={() => handleToggleStatus(task)}
										class="relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
										class:bg-blue-600={task.is_active !== false}
										class:bg-gray-300={task.is_active === false}
										role="switch"
										aria-checked={task.is_active !== false}
										aria-label={$t.validation?.active || 'Active'}
									>
										<span
											class="inline-block h-4 w-4 transform rounded-full bg-white transition-transform"
											class:translate-x-6={task.is_active !== false}
											class:translate-x-1={task.is_active === false}
										></span>
									</button>
								</td>

								<!-- Actions -->
								<td class="px-6 py-4 whitespace-nowrap text-right">
									<div class="flex items-center justify-end gap-1">
										<!-- Run Now -->
										<button
											onclick={() => handleRunNow(task.id)}
											disabled={runningTasks[task.id]}
											class="p-2 text-gray-400 hover:text-blue-600 rounded-lg hover:bg-blue-50 transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
											title={$t.validation?.run_now || 'Run Now'}
										>
											{#if runningTasks[task.id]}
												<svg class="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
													<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
													<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
												</svg>
											{:else}
												<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
													<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
													<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
												</svg>
											{/if}
										</button>

										<!-- Edit -->
										<button
											onclick={() => navToEdit(task.id)}
											class="p-2 text-gray-400 hover:text-blue-600 rounded-lg hover:bg-blue-50 transition-colors"
											title={$t.validation?.edit || 'Edit'}
										>
											<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
												<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
											</svg>
										</button>

										<!-- Delete -->
										{#if deleteConfirmId === task.id}
											<div class="flex items-center gap-1">
												<button
													onclick={() => handleDelete(task.id)}
													class="px-2 py-1 text-xs bg-red-600 text-white rounded hover:bg-red-700 transition-colors"
												>
													{$t.validation?.confirm_delete || 'Delete'}
												</button>
												<button
													onclick={() => { deleteConfirmId = null; }}
													class="px-2 py-1 text-xs bg-gray-200 text-gray-700 rounded hover:bg-gray-300 transition-colors"
												>
													{$t.common?.cancel || 'Cancel'}
												</button>
											</div>
										{:else}
											<button
												onclick={() => { deleteConfirmId = task.id; }}
												class="p-2 text-gray-400 hover:text-red-600 rounded-lg hover:bg-red-50 transition-colors"
												title={$t.validation?.delete || 'Delete'}
											>
												<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
													<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
												</svg>
											</button>
										{/if}
									</div>
								</td>
							</tr>
						{/each}
					</tbody>
				</table>
			</div>
		</div>

		<!-- Pagination -->
		{#if totalPages > 1}
			<div class="flex items-center justify-between mt-4">
				<p class="text-sm text-gray-500">
					{($t.validation?.showing || 'Showing {count} of {total}')
						.replace('{count}', String(tasks.length))
						.replace('{total}', String(total))}
				</p>
				<nav class="flex items-center gap-1" aria-label="Pagination">
					<button
						onclick={() => goToPage(currentPage - 1)}
						disabled={currentPage <= 1}
						class="px-3 py-1.5 text-sm border border-gray-200 rounded-lg disabled:opacity-40 disabled:cursor-not-allowed hover:bg-gray-50 text-gray-600 transition-colors"
					>
						{$t.validation?.previous || 'Previous'}
					</button>
					{#each Array.from({ length: Math.min(totalPages, 7) }, (_, i) => {
						// Show window around current page
						if (totalPages <= 7) return i + 1;
						const half = 3;
						const start = Math.max(1, currentPage - half);
						const end = Math.min(totalPages, start + 6);
						const adjustedStart = Math.max(1, end - 6);
						return adjustedStart + i;
					}) as p (p)}
						<button
							onclick={() => goToPage(p)}
							class={pageBtnClass(p)}
						>
							{p}
						</button>
					{/each}
					<button
						onclick={() => goToPage(currentPage + 1)}
						disabled={currentPage >= totalPages}
						class="px-3 py-1.5 text-sm border border-gray-200 rounded-lg disabled:opacity-40 disabled:cursor-not-allowed hover:bg-gray-50 text-gray-600 transition-colors"
					>
						{$t.validation?.next || 'Next'}
					</button>
				</nav>
			</div>
		{/if}
	{/if}
</div>
<!-- #endregion ValidationTasksPage -->
