<!-- #region TranslationRunGlobalIndicator [C:3] [TYPE Component] [SEMANTICS translate, progress, global, indicator] -->
<!-- @BRIEF Persistent rich progress panel for active translation runs, rendered in root layout. -->
<!-- @RELATION BINDS_TO -> [EXT:frontend:translationRunStore] -->
<!-- @UX_STATE hidden -> No active or recently completed run -->
<!-- @UX_STATE running -> Rich panel with stats grid + progress bar + cancel button -->
<!-- @UX_STATE completed -> Compact green banner with auto-dismiss after 5s -->
<!-- @UX_STATE failed -> Compact red banner with auto-dismiss after 8s -->
<!-- @UX_STATE cancelled -> Compact gray banner with auto-dismiss after 8s -->
<!-- @UX_FEEDBACK Rich stats during active run; compact auto-dismiss for terminal states -->
<script lang="ts">
	import { translationRunStore, stopTranslationRun } from '$lib/stores/translationRun.svelte.js';
	import { page } from '$app/state';
	import { goto } from '$app/navigation';
	import { t } from '$lib/i18n/index.svelte.js';
	import { onDestroy } from 'svelte';
	import { cancelRun } from '$lib/api/translate.js';
	import { addToast } from '$lib/toasts.svelte.js';

	// Subscribe to store via $effect + subscribe (NOT fromStore + $derived).
	// @REJECTED fromStore + multiple $derived(runState.current.xxx) creates render_effect
	// instances via createSubscriber on every $derived re-evaluation. Over time these
	// accumulate and trigger an infinite Svelte reactive flush loop after ~300 polls.
	// @RATIONALE $effect(() => store.subscribe(s => state = s)) creates exactly ONE
	// subscription per component lifecycle — no accumulating render_effects.
	let storeState = $state({ uxState: 'idle', totalRecords: 0, successfulRecords: 0, failedRecords: 0, skippedRecords: 0, progressPct: 0, runId: null, jobId: null });
	$effect(() => {
		const unsub = translationRunStore.subscribe(s => { storeState = s; });
		return () => unsub();
	});

	// Hide on the translate page itself to avoid duplication
	let isOnTranslatePage = $derived(
		page.url.pathname.startsWith('/translate/') && page.url.pathname !== '/translate'
	);

	// Terminal state auto-dismiss timers
	let dismissTimer = $state(null);
	let dismissed = $state(false);
	let isCancelling = $state(false);

	let uxState = $derived(storeState?.uxState || 'idle');

	let show = $derived.by(() => {
		if (dismissed) return false;
		if (isOnTranslatePage) return false;
		if (uxState === 'running' || uxState === 'inserting') return true;
		if (uxState === 'completed' || uxState === 'partial') return true;
		if (uxState === 'failed' || uxState === 'cancelled') return true;
		return false;
	});

	let isActive = $derived(uxState === 'running' || uxState === 'inserting');

	let label = $derived.by(() => {
		if (uxState === 'inserting') return $t.translate?.run?.insert_phase || 'Inserting...';
		if (uxState === 'running') return $t.translate?.run?.translate_phase || 'Translating...';
		if (uxState === 'completed') return $t.translate?.run?.completed || 'Completed';
		if (uxState === 'partial') return $t.translate?.run?.completed_with_errors || 'Completed with errors';
		if (uxState === 'failed') return $t.translate?.run?.translation_failed || 'Translation failed';
		if (uxState === 'cancelled') return $t.translate?.run?.cancelled || 'Cancelled';
		return '';
	});

	let totalRecords = $derived(storeState?.totalRecords || 0);
	let successfulRecords = $derived(storeState?.successfulRecords || 0);
	let failedRecords = $derived(storeState?.failedRecords || 0);
	let skippedRecords = $derived(storeState?.skippedRecords || 0);
	let progressPct = $derived(storeState?.progressPct || 0);

	// Auto-dismiss terminal states after a few seconds
	$effect(() => {
		if (uxState === 'completed' || uxState === 'partial') {
			dismissed = false;
			if (dismissTimer) clearTimeout(dismissTimer);
			dismissTimer = setTimeout(() => { dismissed = true; }, 5000);
		} else if (uxState === 'failed' || uxState === 'cancelled') {
			dismissed = false;
			if (dismissTimer) clearTimeout(dismissTimer);
			dismissTimer = setTimeout(() => { dismissed = true; }, 8000);
		} else if (uxState === 'idle') {
			dismissed = false;
		}
	});

	onDestroy(() => {
		if (dismissTimer) clearTimeout(dismissTimer);
	});

	function handleClick() {
		const jobId = storeState?.jobId;
		if (jobId) {
			goto(`/translate/${jobId}`);
		}
	}

	async function handleCancel(e) {
		e.stopPropagation();
		const runId = storeState?.runId;
		if (!runId || isCancelling) return;
		isCancelling = true;
		try {
			await cancelRun(runId);
			addToast($t.translate?.run?.run_cancelled || 'Run cancelled', 'info');
		} catch (err) {
			addToast(err?.message || $t.translate?.run?.cancel_failed || 'Cancel failed', 'error');
		} finally {
			isCancelling = false;
		}
	}
</script>

{#if show}
	<div
		class="fixed top-0 left-0 right-0 z-[100] shadow-md"
		role="status"
		aria-label={label}
	>
		{#if isActive}
			<!-- ═══ RICH ACTIVE PANEL ═══ -->
			<div class="bg-white border-b border-gray-200 px-4 py-3">
				<div class="max-w-5xl mx-auto">
					<!-- Header row: spinner + label + actions -->
					<div class="flex items-center justify-between mb-2">
						<div class="flex items-center gap-2">
							<div class="animate-spin rounded-full h-4 w-4 border-b-2 border-blue-600" />
							<span class="text-sm font-semibold text-gray-900">{label}</span>
						</div>
						<div class="flex items-center gap-2">
							<button
								onclick={handleClick}
								class="text-xs text-primary hover:text-blue-800 underline"
							>
								{$t.common?.open || 'Open'}
							</button>
							<button
								onclick={handleCancel}
								disabled={isCancelling}
								class="px-2 py-1 text-xs border border-red-300 text-red-600 rounded hover:bg-red-50 disabled:opacity-50 transition-colors"
							>
								{isCancelling
									? ($t.translate?.run?.cancelling || 'Cancelling...')
									: ($t.translate?.run?.cancel || 'Cancel')}
							</button>
						</div>
					</div>

					<!-- Progress bar with percentage -->
					<div class="w-full bg-gray-200 rounded-full h-2.5 mb-2">
						<div
							class="bg-primary h-2.5 rounded-full transition-all duration-500"
							style="width: {Math.min(progressPct, 100)}%"
						></div>
					</div>

					<!-- Stats grid -->
					<div class="grid grid-cols-4 gap-2 text-xs">
						<div class="bg-gray-50 rounded px-2 py-1 text-center">
							<span class="text-gray-500 block">{($t.translate?.run?.total || 'Total')}</span>
							<span class="font-bold text-gray-900">{totalRecords}</span>
						</div>
						<div class="bg-green-50 rounded px-2 py-1 text-center">
							<span class="text-green-600 block">{($t.translate?.run?.success || 'OK')}</span>
							<span class="font-bold text-green-700">{successfulRecords}</span>
						</div>
						<div class="bg-red-50 rounded px-2 py-1 text-center">
							<span class="text-red-600 block">{($t.translate?.run?.failed || 'Fail')}</span>
							<span class="font-bold text-red-700">{failedRecords}</span>
						</div>
						<div class="bg-yellow-50 rounded px-2 py-1 text-center">
							<span class="text-yellow-600 block">{($t.translate?.run?.skipped || 'Skip')}</span>
							<span class="font-bold text-yellow-700">{skippedRecords}</span>
						</div>
					</div>
				</div>
			</div>
		{:else}
			<!-- ═══ COMPACT TERMINAL BANNER ═══ -->
			<div
				class="px-4 py-2 text-white text-sm flex items-center justify-between cursor-pointer"
				class:bg-green-600={uxState === 'completed' || uxState === 'partial'}
				class:bg-destructive={uxState === 'failed'}
				class:bg-gray-500={uxState === 'cancelled'}
				onclick={handleClick}
				onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleClick(); } }}
				role="button"
				tabindex="0"
			>
				<div class="flex items-center gap-2">
					{#if uxState === 'completed'}
						<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="M5 13l4 4L19 7" /></svg>
					{:else if uxState === 'partial' || uxState === 'failed'}
						<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="M12 9v2m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></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="M6 18L18 6M6 6l12 12" /></svg>
					{/if}
					<span class="font-medium">{label}</span>
					{#if uxState === 'partial'}
						<span class="opacity-80">{successfulRecords}/{totalRecords}</span>
					{/if}
				</div>
				<span class="opacity-70 hover:opacity-100 transition-opacity">
					&#9654; {$t.common?.open || 'Open'}
				</span>
			</div>
		{/if}
	</div>
{/if}
<!-- #endregion TranslationRunGlobalIndicator -->
