<script lang="ts">
	import { onMount, onDestroy, untrack } from 'svelte';
	import { page } from '$app/stores';
	import * as Select from '$lib/components/ui/select';
	import MultiSelectFilter from '$lib/components/MultiSelectFilter.svelte';
	import { Button } from '$lib/components/ui/button';
	import { DatePicker } from '$lib/components/ui/date-picker';
	import { Input } from '$lib/components/ui/input';
	import { Badge } from '$lib/components/ui/badge';
	import * as Dialog from '$lib/components/ui/dialog';
	import {
		RefreshCw,
		Calendar,
		Box,
		X,
		Eye,
		Server,
		Play,
		Square,
		RotateCcw,
		Pause,
		CirclePlay,
		Trash2,
		Plus,
		Skull,
		Zap,
		AlertTriangle,
		Pencil,
		Activity,
		Loader2,
		FileX,
		Heart,
		Search
	} from 'lucide-svelte';
	import PageHeader from '$lib/components/PageHeader.svelte';
	import { currentEnvironment, environments as environmentsStore } from '$lib/stores/environment';
	import { getIconComponent } from '$lib/utils/icons';
	import { canAccess } from '$lib/stores/auth';
	import ConfirmPopover from '$lib/components/ConfirmPopover.svelte';
	import { toast } from 'svelte-sonner';
	import { formatDateTime } from '$lib/stores/settings';
	import { NoEnvironment } from '$lib/components/ui/empty-state';
	import { DataGrid } from '$lib/components/data-grid';

	interface ContainerEvent {
		id: number;
		environmentId: number | null;
		environmentName: string | null;
		environmentIcon: string | null;
		containerId: string | null;
		containerName: string | null;
		image: string | null;
		action: string;
		actorAttributes: Record<string, string> | null;
		timestamp: string;
		createdAt: string;
	}

	interface Environment {
		id: number;
		name: string;
		icon: string;
		labels?: string[];
	}

	// Constants
	const FETCH_BATCH_SIZE = 100;

	// State
	let events = $state<ContainerEvent[]>([]);
	let total = $state(0);
	let loading = $state(false);
	let loadingMore = $state(false);
	let containers = $state<string[]>([]);
	let environments = $state<Environment[]>([]);
	let envId = $state<number | null>(null);
	let hasMore = $state(true);
	let initialized = $state(false);
	let dataFetched = $state(false);
	let showClearConfirm = $state(false);
	let clearingActivity = $state(false);

	// Visible range for virtual scroll
	let visibleStart = $state(1);
	let visibleEnd = $state(0);

	// localStorage key for filters
	const STORAGE_KEY = 'dockhand_activity_filters';

	// Filters
	let filterContainerName = $state('');
	let filterActions = $state<string[]>([]);
	let filterEnvironmentId = $state<number | null>(null);
	let filterLabels = $state<string[]>([]);
	let filterFromDate = $state('');
	let filterToDate = $state('');

	// Load filters from localStorage
	function loadFiltersFromStorage() {
		if (typeof window === 'undefined') return;
		try {
			const stored = localStorage.getItem(STORAGE_KEY);
			if (stored) {
				const parsed = JSON.parse(stored);
				filterContainerName = parsed.containerName || '';
				filterActions = parsed.actions || [];
				filterEnvironmentId = parsed.environmentId || null;
				filterLabels = parsed.labels || [];
				filterFromDate = parsed.fromDate || '';
				filterToDate = parsed.toDate || '';
			}
		} catch (e) {
			console.error('Failed to load activity filters from localStorage:', e);
		}
	}

	// Save filters to localStorage
	function saveFiltersToStorage() {
		if (typeof window === 'undefined') return;
		try {
			localStorage.setItem(STORAGE_KEY, JSON.stringify({
				containerName: filterContainerName,
				actions: filterActions,
				environmentId: filterEnvironmentId,
				labels: filterLabels,
				fromDate: filterFromDate,
				toDate: filterToDate
			}));
		} catch (e) {
			console.error('Failed to save activity filters to localStorage:', e);
		}
	}

	// Detail dialog
	let showDetailDialog = $state(false);
	let selectedEvent = $state<ContainerEvent | null>(null);

	// SSE connection
	let sseConnected = $state(false);
	let eventSource: EventSource | null = null;

	const actionOptions = [
		{ value: 'create', label: 'Create', icon: Plus, color: 'text-emerald-500' },
		{ value: 'start', label: 'Start', icon: Play, color: 'text-emerald-500' },
		{ value: 'stop', label: 'Stop', icon: Square, color: 'text-amber-500' },
		{ value: 'die', label: 'Die', icon: Skull, color: 'text-red-500' },
		{ value: 'kill', label: 'Kill', icon: Zap, color: 'text-red-500' },
		{ value: 'restart', label: 'Restart', icon: RotateCcw, color: 'text-sky-500' },
		{ value: 'pause', label: 'Pause', icon: Pause, color: 'text-amber-500' },
		{ value: 'unpause', label: 'Unpause', icon: CirclePlay, color: 'text-emerald-500' },
		{ value: 'destroy', label: 'Destroy', icon: Trash2, color: 'text-red-500' },
		{ value: 'rename', label: 'Rename', icon: Pencil, color: 'text-muted-foreground' },
		{ value: 'update', label: 'Update', icon: Pencil, color: 'text-sky-500' },
		{ value: 'oom', label: 'Out of memory', icon: AlertTriangle, color: 'text-red-500' },
		{ value: 'health_status', label: 'Health status', icon: Heart, color: 'text-amber-500' }
	];

	// Date filter preset
	let selectedDatePreset = $state<string>('');

	// Check if any filters are active
	const hasActiveFilters = $derived(
		filterContainerName || filterActions.length > 0 || filterEnvironmentId !== null || selectedDatePreset
	);

	const datePresets = [
		{ value: 'today', label: 'Today' },
		{ value: 'yesterday', label: 'Yesterday' },
		{ value: 'last7days', label: 'Last 7 days' },
		{ value: 'last30days', label: 'Last 30 days' },
		{ value: 'thisMonth', label: 'This month' },
		{ value: 'lastMonth', label: 'Last month' }
	];

	function formatDateForInput(date: Date): string {
		const year = date.getFullYear();
		const month = String(date.getMonth() + 1).padStart(2, '0');
		const day = String(date.getDate()).padStart(2, '0');
		return `${year}-${month}-${day}`;
	}

	function applyDatePreset(preset: string): { from: string; to: string } {
		const today = new Date();
		today.setHours(0, 0, 0, 0);

		let from = '';
		let to = '';

		switch (preset) {
			case 'today':
				from = formatDateForInput(today);
				to = formatDateForInput(today);
				break;
			case 'yesterday': {
				const yesterday = new Date(today);
				yesterday.setDate(yesterday.getDate() - 1);
				from = formatDateForInput(yesterday);
				to = formatDateForInput(yesterday);
				break;
			}
			case 'last7days': {
				const weekAgo = new Date(today);
				weekAgo.setDate(weekAgo.getDate() - 6);
				from = formatDateForInput(weekAgo);
				to = formatDateForInput(today);
				break;
			}
			case 'last30days': {
				const monthAgo = new Date(today);
				monthAgo.setDate(monthAgo.getDate() - 29);
				from = formatDateForInput(monthAgo);
				to = formatDateForInput(today);
				break;
			}
			case 'thisMonth': {
				const firstOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
				from = formatDateForInput(firstOfMonth);
				to = formatDateForInput(today);
				break;
			}
			case 'lastMonth': {
				const firstOfLastMonth = new Date(today.getFullYear(), today.getMonth() - 1, 1);
				const lastOfLastMonth = new Date(today.getFullYear(), today.getMonth(), 0);
				from = formatDateForInput(firstOfLastMonth);
				to = formatDateForInput(lastOfLastMonth);
				break;
			}
		}

		filterFromDate = from;
		filterToDate = to;

		return { from, to };
	}

	async function clearActivity() {
		clearingActivity = true;
		try {
			const res = await fetch('/api/activity', {
				method: 'DELETE'
			});
			if (!res.ok) {
				const data = await res.json();
				throw new Error(data.error || 'Failed to clear activity');
			}
			toast.success('Activity log cleared');
			// Reset and reload
			events = [];
			total = 0;
			hasMore = true;
			fetchEvents(false);
		} catch (error: any) {
			toast.error(error.message);
		} finally {
			clearingActivity = false;
			showClearConfirm = false;
		}
	}

	// Subscribe to environment
	$effect(() => {
		const env = $currentEnvironment;
		envId = env?.id ?? null;
	});

	let fetchController: AbortController | null = null;

	async function fetchEvents(append = false, silent = false) {
		if (append && loadingMore) return;

		if (!append && fetchController) {
			fetchController.abort();
		}

		if (append) {
			loadingMore = true;
		} else if (!silent) {
			loading = true;
			hasMore = true;
		}

		fetchController = new AbortController();

		try {
			const params = new URLSearchParams();

			if (filterContainerName) params.set('containerName', filterContainerName);
			if (filterActions.length > 0) params.set('actions', filterActions.join(','));
			if (filterEnvironmentId !== null) params.set('environmentId', String(filterEnvironmentId));
			if (filterLabels.length > 0) params.set('labels', filterLabels.join(','));
			if (filterFromDate) params.set('fromDate', filterFromDate);
			if (filterToDate) params.set('toDate', filterToDate + 'T23:59:59');
			params.set('limit', String(FETCH_BATCH_SIZE));
			params.set('offset', String(append ? events.length : 0));

			const response = await fetch(`/api/activity?${params.toString()}`, {
				signal: fetchController.signal
			});
			if (!response.ok) {
				throw new Error('Failed to fetch events');
			}
			const data = await response.json();

			if (append) {
				events = [...events, ...data.events];
			} else {
				events = data.events;
			}
			total = data.total;
			hasMore = events.length < total;
			dataFetched = true;

			loading = false;
			loadingMore = false;
			fetchController = null;
		} catch (error: any) {
			if (error?.name === 'AbortError') {
				return;
			}
			console.error('Failed to fetch events:', error);
			if (!append && !silent) {
				events = [];
				total = 0;
			}
			loading = false;
			loadingMore = false;
			fetchController = null;
			hasMore = false;
		}
	}

	async function fetchContainers() {
		try {
			const params = new URLSearchParams();
			if (filterEnvironmentId !== null) {
				params.set('environmentId', String(filterEnvironmentId));
			}
			const response = await fetch(`/api/activity/containers?${params.toString()}`);
			if (response.ok) {
				containers = await response.json();
			}
		} catch (error) {
			console.error('Failed to fetch containers:', error);
		}
	}

	async function fetchEnvironments() {
		try {
			const response = await fetch('/api/environments');
			if (response.ok) {
				environments = await response.json();
			}
		} catch (error) {
			console.error('Failed to fetch environments:', error);
		}
	}

	function clearFilters() {
		filterContainerName = '';
		filterActions = [];
		filterEnvironmentId = null;
		filterLabels = [];
		filterFromDate = '';
		filterToDate = '';
		selectedDatePreset = '';
		if (typeof window !== 'undefined') {
			localStorage.removeItem(STORAGE_KEY);
		}
	}

	// Track if initial load is done
	let initialLoadDone = $state(false);

	// Auto-fetch when filters change
	$effect(() => {
		const _cn = filterContainerName;
		const _a = filterActions;
		const _fd = filterFromDate;
		const _td = filterToDate;
		const _ei = filterEnvironmentId;
		const _l = filterLabels;

		const isReady = untrack(() => initialLoadDone);

		if (isReady) {
			saveFiltersToStorage();
			fetchEvents(false);
		}
	});

	// Called by DataGrid when user scrolls near the bottom
	function loadMoreEvents() {
		if (hasMore && !loadingMore && !loading) {
			fetchEvents(true);
		}
	}

	// Called by DataGrid when visible range changes
	function handleVisibleRangeChange(start: number, end: number, _total: number) {
		visibleStart = start;
		visibleEnd = end;
	}

	function showDetails(event: ContainerEvent) {
		selectedEvent = event;
		showDetailDialog = true;
	}

	function formatTimestamp(ts: string): string {
		return formatDateTime(ts, true);
	}

	function getActionIcon(action: string) {
		switch (action) {
			case 'create': return Plus;
			case 'start': return Play;
			case 'stop': return Square;
			case 'die': return Skull;
			case 'kill': return Zap;
			case 'restart': return RotateCcw;
			case 'pause': return Pause;
			case 'unpause': return CirclePlay;
			case 'destroy': return Trash2;
			case 'rename': return Pencil;
			case 'update': return Pencil;
			case 'oom': return AlertTriangle;
			case 'health_status': return Heart;
			default: return Activity;
		}
	}

	function getActionColor(action: string): string {
		switch (action) {
			case 'create':
			case 'start':
			case 'unpause':
				return 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400';
			case 'stop':
			case 'die':
			case 'kill':
			case 'destroy':
			case 'oom':
				return 'bg-rose-100 text-rose-700 dark:bg-rose-900/30 dark:text-rose-400';
			case 'restart':
			case 'pause':
			case 'update':
			case 'rename':
				return 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400';
			case 'health_status':
				return 'bg-sky-100 text-sky-700 dark:bg-sky-900/30 dark:text-sky-400';
			default:
				return 'bg-slate-100 text-slate-700 dark:bg-slate-800 dark:text-slate-400';
		}
	}

	// SSE connection
	let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
	let wasConnected = false;
	let reconnectAttempts = 0;
	const MAX_RECONNECT_ATTEMPTS = 10;
	const BASE_RECONNECT_DELAY = 3000;

	function connectSSE() {
		if (eventSource) {
			eventSource.close();
		}

		if (reconnectTimer) {
			clearTimeout(reconnectTimer);
			reconnectTimer = null;
		}

		eventSource = new EventSource('/api/activity/events');

		eventSource.addEventListener('connected', () => {
			const wasDisconnected = wasConnected && !sseConnected;
			sseConnected = true;
			wasConnected = true;
			reconnectAttempts = 0; // Reset backoff on successful connection

			// If we were previously connected and reconnected, fetch any missed events
			if (wasDisconnected) {
				fetchEvents(false, true); // silent fetch to catch up on missed events
			}
		});

		eventSource.addEventListener('activity', (e) => {
			try {
				const newEvent = JSON.parse(e.data);

				// Check if event matches current filters
				if (filterContainerName && !newEvent.containerName?.includes(filterContainerName)) return;
				if (filterActions.length > 0 && !filterActions.includes(newEvent.action)) return;
				if (filterEnvironmentId !== null && newEvent.environmentId !== filterEnvironmentId) return;

				// Check date filters
				if (filterFromDate) {
					const eventDate = new Date(newEvent.timestamp).toISOString().split('T')[0];
					if (eventDate < filterFromDate) return;
				}
				if (filterToDate) {
					const eventDate = new Date(newEvent.timestamp).toISOString().split('T')[0];
					if (eventDate > filterToDate) return;
				}

				// Add to beginning of events (prepend new events)
				if (!events.some(event => event.id === newEvent.id)) {
					events = [newEvent, ...events];
					total = total + 1;

					// Add container to list if not already there
					if (newEvent.containerName && !containers.includes(newEvent.containerName)) {
						containers = [...containers, newEvent.containerName].sort();
					}
				}
			} catch {
				// Ignore parse errors
			}
		});

		eventSource.addEventListener('heartbeat', () => {
			sseConnected = true;
		});

		eventSource.onerror = () => {
			sseConnected = false;
			// Exponential backoff reconnection
			if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
				const delay = Math.min(BASE_RECONNECT_DELAY * Math.pow(2, reconnectAttempts), 60000);
				reconnectAttempts++;
				reconnectTimer = setTimeout(() => {
					if (eventSource?.readyState === EventSource.CLOSED) {
						connectSSE();
					}
				}, delay);
			}
		};
	}

	function disconnectSSE() {
		if (reconnectTimer) {
			clearTimeout(reconnectTimer);
			reconnectTimer = null;
		}
		if (eventSource) {
			eventSource.close();
			eventSource = null;
			sseConnected = false;
		}
	}

	// Handle tab visibility changes (e.g., user switches back from another tab)
	function handleVisibilityChange() {
		if (document.visibilityState === 'visible') {
			// Tab became visible - check and restore connection

			// Clear any pending reconnection timer
			if (reconnectTimer) {
				clearTimeout(reconnectTimer);
				reconnectTimer = null;
			}

			// Reset reconnection counter for fresh attempts
			reconnectAttempts = 0;

			// Reconnect SSE if it's closed or in error state
			if (!eventSource || eventSource.readyState !== EventSource.OPEN) {
				connectSSE();
			}
		}
	}

	onMount(() => {
		// Listen for tab visibility changes to reconnect when user returns
		document.addEventListener('visibilitychange', handleVisibilityChange);
		// Chrome 77+ Page Lifecycle API - fires when frozen tab is resumed
		document.addEventListener('resume', handleVisibilityChange);

		loadFiltersFromStorage();

		// Check for URL query param (env) - takes priority over localStorage
		const urlEnvParam = $page.url.searchParams.get('env');
		if (urlEnvParam) {
			const envIdFromUrl = parseInt(urlEnvParam);
			if (!isNaN(envIdFromUrl)) {
				filterEnvironmentId = envIdFromUrl;
			}
		}

		// Initialize in order - set initialized=true AFTER data is fetched
		fetchEnvironments().then(() => {
			// Validate filterEnvironmentId - reset if it doesn't exist
			if (filterEnvironmentId !== null) {
				const envExists = environments.some(e => e.id === filterEnvironmentId);
				if (!envExists) {
					filterEnvironmentId = null;
					saveFiltersToStorage();
				}
			}
			return fetchEvents();
		}).then(() => {
			initialized = true;
			return fetchContainers();
		}).then(() => {
			connectSSE();
			initialLoadDone = true;
		});

		return () => {
			disconnectSSE();
		};
	});

	onDestroy(() => {
		document.removeEventListener('visibilitychange', handleVisibilityChange);
		document.removeEventListener('resume', handleVisibilityChange);
		disconnectSSE();
	});
</script>

<svelte:head>
	<title>Activity - Dockhand</title>
</svelte:head>

<div class="flex-1 min-h-0 flex flex-col gap-3 overflow-hidden">
	<!-- Header with inline filters -->
	<div class="shrink-0 flex flex-wrap justify-between items-center gap-3">
		<PageHeader icon={Activity} title="Activity" count={visibleEnd > 0 ? `${visibleStart}-${visibleEnd}` : undefined} total={total > 0 ? total : undefined} countClass="min-w-32" />
		<div class="flex flex-wrap items-center gap-2">
			<!-- Container name search -->
			<div class="relative">
				<Search class="absolute left-2 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-muted-foreground" />
				<Input
					type="text"
					placeholder="Container..."
					bind:value={filterContainerName}
					onkeydown={(e) => e.key === 'Escape' && (filterContainerName = '')}
					class="pl-8 h-8 w-36 text-sm"
				/>
			</div>

			<!-- Action filter -->
			<MultiSelectFilter
				bind:value={filterActions}
				options={actionOptions}
				placeholder="Action"
				pluralLabel="actions"
				width="w-36"
				defaultIcon={Activity}
			/>

			<!-- Environment filter -->
			{#if environments.length > 0}
				{@const selectedEnv = environments.find(e => e.id === filterEnvironmentId)}
				{@const SelectedEnvIcon = selectedEnv ? getIconComponent(selectedEnv.icon || 'globe') : Server}
				<Select.Root
					type="single"
					value={filterEnvironmentId !== null ? String(filterEnvironmentId) : undefined}
					onValueChange={(v) => filterEnvironmentId = v ? parseInt(v) : null}
				>
					<Select.Trigger size="sm" class="w-44 text-sm">
						<SelectedEnvIcon class="w-3.5 h-3.5 mr-1.5 text-muted-foreground shrink-0" />
						<span class="truncate">
							{#if filterEnvironmentId === null}
								Environment
							{:else}
								{selectedEnv?.name || 'Environment'}
							{/if}
						</span>
					</Select.Trigger>
					<Select.Content>
						<Select.Item value="">
							<Server class="w-4 h-4 mr-2 text-muted-foreground" />
							All environments
						</Select.Item>
						{#each environments as env}
							{@const EnvIcon = getIconComponent(env.icon || 'globe')}
							<Select.Item value={String(env.id)}>
								<EnvIcon class="w-4 h-4 mr-2 text-muted-foreground" />
								{env.name}
							</Select.Item>
						{/each}
					</Select.Content>
				</Select.Root>
			{/if}

			<!-- Date range filter -->
			<Select.Root
				type="single"
				value={selectedDatePreset}
				onValueChange={(v) => {
					selectedDatePreset = v || '';
					if (v !== 'custom') {
						applyDatePreset(v || '');
					}
				}}
			>
				<Select.Trigger size="sm" class="w-32 text-sm">
					<Calendar class="w-3.5 h-3.5 mr-1.5 text-muted-foreground shrink-0" />
					<span class="truncate">
						{#if selectedDatePreset === 'custom'}
							Custom
						{:else if selectedDatePreset}
							{datePresets.find(d => d.value === selectedDatePreset)?.label || 'All time'}
						{:else}
							All time
						{/if}
					</span>
				</Select.Trigger>
				<Select.Content>
					<Select.Item value="">All time</Select.Item>
					{#each datePresets as preset}
						<Select.Item value={preset.value}>{preset.label}</Select.Item>
					{/each}
					<Select.Item value="custom">Custom range...</Select.Item>
				</Select.Content>
			</Select.Root>

			<!-- Custom date inputs -->
			{#if selectedDatePreset === 'custom'}
				<DatePicker bind:value={filterFromDate} placeholder="From" class="h-8 w-28" />
				<DatePicker bind:value={filterToDate} placeholder="To" class="h-8 w-28" />
			{/if}

			<!-- Clear filters -->
			<Button
				variant="outline"
				size="sm"
				class="h-8 px-2"
				onclick={clearFilters}
				disabled={!hasActiveFilters}
				title="Clear all filters"
			>
				<X class="w-3.5 h-3.5" />
			</Button>

			<Button variant="outline" size="sm" onclick={() => { hasMore = true; fetchEvents(false); }} disabled={loading}>
				<RefreshCw class="w-3.5 h-3.5 {loading ? 'animate-spin' : ''}" />
			</Button>

			{#if $canAccess('activity', 'delete')}
				<ConfirmPopover
					bind:open={showClearConfirm}
					action="Clear"
					itemType="activity log"
					title="Clear all"
					onConfirm={clearActivity}
					confirmText="Clear"
					variant="destructive"
					disabled={clearingActivity}
					onOpenChange={(open) => showClearConfirm = open}
				>
					{#snippet children({ open })}
						<Button variant="outline" size="sm" disabled={clearingActivity || total === 0}>
							<Trash2 class="w-3.5 h-3.5" />
						</Button>
					{/snippet}
				</ConfirmPopover>
			{/if}
		</div>
	</div>

	<!-- DataGrid with Virtual Scrolling -->
	{#if $environmentsStore.length === 0}
		<NoEnvironment />
	{:else}
		<DataGrid
			data={events}
			keyField="id"
			gridId="activity"
			virtualScroll
			hasMore={hasMore}
			onLoadMore={loadMoreEvents}
			onVisibleRangeChange={handleVisibleRangeChange}
			loading={loading || !initialized}
			onRowClick={(event) => showDetails(event)}
			class="border-none"
			wrapperClass="border rounded-lg"
		>
			{#snippet cell(column, event, rowState)}
				{#if column.id === 'timestamp'}
					<span class="font-mono text-xs whitespace-nowrap">{formatTimestamp(event.timestamp)}</span>
				{:else if column.id === 'environment'}
					{#if event.environmentName}
						{@const EventEnvIcon = getIconComponent(event.environmentIcon || 'globe')}
						<div class="flex items-center gap-1 text-xs">
							<EventEnvIcon class="w-3 h-3 text-muted-foreground shrink-0" />
							<span class="truncate">{event.environmentName}</span>
						</div>
					{:else}
						<span class="text-muted-foreground text-xs">-</span>
					{/if}
				{:else if column.id === 'action'}
					<div class="flex justify-center">
						<Badge class="{getActionColor(event.action)} py-0.5 px-1" title={event.action.charAt(0).toUpperCase() + event.action.slice(1)}>
							<svelte:component this={getActionIcon(event.action)} class="w-3 h-3" />
						</Badge>
					</div>
				{:else if column.id === 'container'}
					<div class="flex items-center gap-1 truncate text-xs">
						<Box class="w-3 h-3 text-muted-foreground shrink-0" />
						<span class="truncate" title={event.containerName || event.containerId || 'Unknown'}>
							{event.containerName || (event.containerId ? event.containerId.slice(0, 12) : 'Unknown')}
						</span>
					</div>
				{:else if column.id === 'image'}
					<span class="text-xs text-muted-foreground truncate" title={event.image || '-'}>
						{event.image || '-'}
					</span>
				{:else if column.id === 'exitCode'}
					{#if event.actorAttributes?.exitCode !== undefined}
						{@const exitCode = parseInt(event.actorAttributes.exitCode)}
						<span class="font-mono text-xs text-center block {exitCode === 0 ? 'text-green-600' : 'text-red-500'}">
							{exitCode}
						</span>
					{:else}
						<span class="text-muted-foreground text-xs text-center block">-</span>
					{/if}
				{:else if column.id === 'actions'}
					<div class="flex items-center justify-end">
						<Button variant="ghost" size="icon" class="h-6 w-6" onclick={(e) => { e.stopPropagation(); showDetails(event); }}>
							<Eye class="w-3.5 h-3.5" />
						</Button>
					</div>
				{/if}
			{/snippet}

			{#snippet emptyState()}
				<div class="flex flex-col items-center justify-center py-16 text-muted-foreground">
					<FileX class="w-10 h-10 mb-3 opacity-40" />
					<p>No container events found</p>
					<p class="text-xs mt-1">Events will appear here as containers start, stop, etc.</p>
				</div>
			{/snippet}

			{#snippet loadingState()}
				<div class="flex items-center justify-center py-16 text-muted-foreground">
					<RefreshCw class="w-5 h-5 animate-spin mr-2" />
					Loading...
				</div>
			{/snippet}
		</DataGrid>

		<!-- Loading more indicator -->
		{#if loadingMore}
			<div class="flex items-center justify-center py-2 text-muted-foreground border-t">
				<Loader2 class="w-4 h-4 animate-spin mr-2" />
				Loading more...
			</div>
		{/if}

		<!-- End of results -->
		{#if !hasMore && events.length > 0}
			<div class="text-center py-2 text-sm text-muted-foreground border-t">
				End of results ({total.toLocaleString()} events)
			</div>
		{/if}
	{/if}
</div>

<!-- Detail Dialog -->
<Dialog.Root bind:open={showDetailDialog}>
	<Dialog.Content class="max-w-2xl">
		<Dialog.Header>
			<Dialog.Title>Event details</Dialog.Title>
		</Dialog.Header>
		{#if selectedEvent}
			<div class="space-y-4">
				<div class="grid grid-cols-2 gap-4">
					<div>
						<label class="text-sm font-medium text-muted-foreground">Timestamp</label>
						<p class="font-mono text-sm">{formatTimestamp(selectedEvent.timestamp)}</p>
					</div>
					<div>
						<label class="text-sm font-medium text-muted-foreground">Action</label>
						<p>
							<Badge class="{getActionColor(selectedEvent.action)} gap-1">
								<svelte:component this={getActionIcon(selectedEvent.action)} class="w-3 h-3" />
								{selectedEvent.action}
							</Badge>
						</p>
					</div>
					<div>
						<label class="text-sm font-medium text-muted-foreground">Container name</label>
						<p class="flex items-center gap-1">
							<Box class="w-4 h-4 text-muted-foreground" />
							{selectedEvent.containerName || '-'}
						</p>
					</div>
					<div>
						<label class="text-sm font-medium text-muted-foreground">Container ID</label>
						<p class="font-mono text-sm break-all">{selectedEvent.containerId}</p>
					</div>
					{#if selectedEvent.image}
						<div class="col-span-2">
							<label class="text-sm font-medium text-muted-foreground">Image</label>
							<p class="font-mono text-sm break-all">{selectedEvent.image}</p>
						</div>
					{/if}
					{#if selectedEvent.environmentName}
						<div>
							<label class="text-sm font-medium text-muted-foreground">Environment</label>
							<p>{selectedEvent.environmentName}</p>
						</div>
					{/if}
				</div>

				{#if selectedEvent.actorAttributes && Object.keys(selectedEvent.actorAttributes).length > 0}
					<div>
						<label class="text-sm font-medium text-muted-foreground">Attributes</label>
						<div class="mt-1 border rounded-md overflow-hidden max-h-[200px] overflow-y-auto">
							<table class="w-full text-xs">
								<tbody>
									{#each Object.entries(selectedEvent.actorAttributes) as [key, value], i}
										<tr class="{i % 2 === 0 ? 'bg-muted/50' : 'bg-background'}">
											<td class="px-3 py-1.5 font-mono font-medium text-muted-foreground whitespace-nowrap align-top w-1/3">{key}</td>
											<td class="px-3 py-1.5 font-mono break-all">{value}</td>
										</tr>
									{/each}
								</tbody>
							</table>
						</div>
					</div>
				{/if}
			</div>
		{/if}
		<Dialog.Footer>
			<Button variant="outline" onclick={() => showDetailDialog = false}>Close</Button>
		</Dialog.Footer>
	</Dialog.Content>
</Dialog.Root>
