<!-- #region TranslationRunGlobalIndicator [C:3] [TYPE Component] [SEMANTICS translate, progress, global, indicator] -->
<!-- @ingroup Translate -->
<!-- @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 -->
<!-- @INVARIANT storeState MUST use $effect+subscribe pattern, NOT fromStore+$derived.
  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. -->
<!-- @INVARIANT dismissTimer MUST be plain let, NOT $state.
  The auto-dismiss $effect reads dismissTimer (if check) and writes it (setTimeout).
  A $state variable creates reactive tracking on both read and write — the effect
  re-runs on every write, clearing the timer it just set, creating an infinite loop.
  Plain let breaks the reactive tracking on both sides. -->
<!-- @REJECTED $state(dismissTimer) for auto-dismiss timers — the $effect at line 73
  reads it in `if (dismissTimer)` and writes it via `dismissTimer = setTimeout(...)`.
  $state triggers reactive tracking on read AND write → effect re-runs → clears timer
  → sets new timer → re-runs → infinite loop (effect_update_depth_exceeded).
  Confirmed: error floods with 2311 messages, page freezes at 100% progress. -->
<!-- @REJECTED fromStore + $derived(runState.current.xxx) for store subscription —
  creates render_effect instances via createSubscriber on every $derived re-evaluation.
  Over time these accumulate and trigger an infinite Svelte reactive flush loop.
  @RATIONALE $effect(() => store.subscribe(s => state = s)) creates exactly ONE
  subscription per component lifecycle — no accumulating render_effects. -->
<script lang="ts">
	import { translationRunStore } from '$lib/stores/translationRun.svelte.js';
	import { page } from '$app/state';
	import { goto } from '$app/navigation';
	import { ROUTES } from '$lib/routes';
	import { getT } from '$lib/i18n/index.svelte.js';
	import { onDestroy } from 'svelte';
	import { cancelRun } from '$lib/api/translate.js';
	import { addToast } from '$lib/toasts.svelte.js';
	import { Icon } from '$lib/ui';

	// 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 });
  // @RATIONALE Svelte 5 store detection fails for `$t` in deeply nested templates.
  //             Use getT() + $derived to keep reactivity to locale changes.
  const _t = $derived(getT());
	$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
	/** @type {ReturnType<typeof setTimeout> | null} */
	let dismissTimer = 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 getT()?.translate?.run?.insert_phase || 'Inserting...';
		if (uxState === 'running') return getT()?.translate?.run?.translate_phase || 'Translating...';
		if (uxState === 'completed') return getT()?.translate?.run?.completed || 'Completed';
		if (uxState === 'partial') return getT()?.translate?.run?.completed_with_errors || 'Completed with errors';
		if (uxState === 'failed') return getT()?.translate?.run?.translation_failed || 'Translation failed';
		if (uxState === 'cancelled') return getT()?.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 cacheHits = $derived(storeState?.cacheHits || 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(ROUTES.translate.detail(jobId));
		}
	}

	async function handleCancel(e) {
		e.stopPropagation();
		const runId = storeState?.runId;
		if (!runId || isCancelling) return;
		isCancelling = true;
		try {
			await cancelRun(runId);
			addToast(getT()?.translate?.run?.run_cancelled || 'Run cancelled', 'info');
		} catch (err) {
			addToast(err?.message || getT()?.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-surface-card border-b border-border 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-primary-ring"></div>
							<span class="text-sm font-semibold text-text">{label}</span>
						</div>
						<div class="flex items-center gap-2">
							<button
								onclick={handleClick}
								class="text-xs text-primary hover:text-primary underline"
							>
								{_t.common?.open || 'Open'}
							</button>
							<button
								onclick={handleCancel}
								disabled={isCancelling}
								class="px-2 py-1 text-xs border border-destructive-ring text-destructive rounded hover:bg-destructive-light 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-surface-muted 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-5 gap-2 text-xs">
						<div class="bg-surface-muted rounded px-2 py-1 text-center">
							<span class="text-text-muted block">{(_t.translate?.run?.total || 'Total')}</span>
							<span class="font-bold text-text">{totalRecords}</span>
						</div>
						<div class="bg-success-light rounded px-2 py-1 text-center">
							<span class="text-success block">{(_t.translate?.run?.success || 'OK')}</span>
							<span class="font-bold text-success">{successfulRecords}</span>
						</div>
						<div class="bg-destructive-light rounded px-2 py-1 text-center">
							<span class="text-destructive block">{(_t.translate?.run?.failed || 'Fail')}</span>
							<span class="font-bold text-destructive">{failedRecords}</span>
						</div>
						<div class="bg-warning-light rounded px-2 py-1 text-center">
							<span class="text-warning block">{(_t.translate?.run?.skipped || 'Skip')}</span>
							<span class="font-bold text-warning">{skippedRecords}</span>
						</div>
						<div class="bg-info-light rounded px-2 py-1 text-center">
							<span class="text-info block">Cache</span>
							<span class="font-bold text-info">{cacheHits}</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-success={uxState === 'completed' || uxState === 'partial'}
				class:bg-destructive={uxState === 'failed'}
				class:bg-surface-muted={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'}
						<Icon name="check" size={16} />
					{:else if uxState === 'partial' || uxState === 'failed'}
						<Icon name="warning" size={16} />
					{:else}
						<Icon name="close" size={16} />
					{/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 -->
