<script lang="ts">
	import { onMount } from 'svelte';
	import { slide } from 'svelte/transition';
	import { api, parseDate } from '$lib/api';
	import { t } from '$lib/i18n';
	import { providersCache } from '$lib/stores/caches.svelte';
	import PageHeader from '$lib/components/PageHeader.svelte';
	import Card from '$lib/components/Card.svelte';
	import Loading from '$lib/components/Loading.svelte';
	import MdiIcon from '$lib/components/MdiIcon.svelte';
	import EventChart from '$lib/components/EventChart.svelte';
	import IconGridSelect from '$lib/components/IconGridSelect.svelte';
	import EntitySelect from '$lib/components/EntitySelect.svelte';
	import ConfirmModal from '$lib/components/ConfirmModal.svelte';
	import { snackSuccess, snackError } from '$lib/stores/snackbar.svelte';
	import { eventTypeFilterItems, sortFilterItems, providerDefaultIcon } from '$lib/grid-items';
	import { globalProviderFilter } from '$lib/stores/provider-filter.svelte';
	import { getDescriptor } from '$lib/providers';

	import type { DashboardStatus } from '$lib/types';

	const CHART_KEY = 'dashboard_chart_visible';
	let chartVisible = $state(typeof localStorage !== 'undefined' ? localStorage.getItem(CHART_KEY) !== 'false' : true);
	function toggleChart() {
		chartVisible = !chartVisible;
		if (typeof localStorage !== 'undefined') localStorage.setItem(CHART_KEY, String(chartVisible));
	}

	let status = $state<DashboardStatus | null>(null);
	let providers = $derived(providersCache.items);
	const providerFilterItems = $derived([
		{ value: '', label: t('dashboard.allProviders'), icon: 'mdiFilterOff' },
		...providers.map(p => ({ value: p.id, label: p.name, icon: providerDefaultIcon(p), desc: p.type })),
	]);
	let chartDays = $state<{ date: string; [eventType: string]: string | number }[]>([]);
	let loaded = $state(false);
	let error = $state('');

	let displayProviders = $state(0);
	let displayActive = $state(0);
	let displayTotal = $state(0);
	let displayTargets = $state(0);

	// Event filters
	let filterEventType = $state('');
	let filterProviderId = $state('');
	let effectiveProviderId = $derived(globalProviderFilter.id ? String(globalProviderFilter.id) : filterProviderId);
	let filterSearch = $state('');
	let filterSort = $state('newest');

	const EVENTS_PER_PAGE_KEY = 'dashboard_events_per_page';
	function loadEventsPerPage(): number {
		if (typeof localStorage === 'undefined') return 10;
		const stored = localStorage.getItem(EVENTS_PER_PAGE_KEY);
		return stored ? parseInt(stored, 10) || 10 : 10;
	}

	let eventsLimit = $state(loadEventsPerPage());
	let eventsOffset = $state(0);
	let eventsLoading = $state(false);
	let confirmClearEvents = $state(false);

	async function clearEvents() {
		try {
			const res = await api<{ deleted: number }>('/status/events', { method: 'DELETE' });
			snackSuccess(t('snack.eventsCleared').replace('{count}', String(res.deleted)));
			eventsOffset = 0;
			await loadEvents();
			await loadChart();
		} catch (err: any) {
			snackError(err.message || t('common.error'));
		} finally {
			confirmClearEvents = false;
		}
	}

	let currentPage = $derived(Math.floor(eventsOffset / eventsLimit) + 1);
	let totalPages = $derived(status ? Math.ceil((status.total_events || 0) / eventsLimit) : 0);

	function animateCount(from: number, to: number, setter: (v: number) => void, duration = 600) {
		if (to === 0) { setter(0); return; }
		const start = performance.now();
		function frame(now: number) {
			const elapsed = now - start;
			const progress = Math.min(elapsed / duration, 1);
			const eased = 1 - Math.pow(1 - progress, 3);
			setter(Math.round(from + (to - from) * eased));
			if (progress < 1) requestAnimationFrame(frame);
		}
		requestAnimationFrame(frame);
	}

	/** Build filter query string (shared by events list + chart). */
	function buildFilterParams(): URLSearchParams {
		const params = new URLSearchParams();
		if (filterEventType) params.set('event_type', filterEventType);
		if (effectiveProviderId) params.set('provider_id', effectiveProviderId);
		if (filterSearch) params.set('search', filterSearch);
		return params;
	}

	async function loadEvents() {
		eventsLoading = true;
		try {
			const params = buildFilterParams();
			params.set('sort', filterSort);
			params.set('limit', String(eventsLimit));
			params.set('offset', String(eventsOffset));
			const qs = params.toString();
			status = await api<DashboardStatus>(`/status${qs ? '?' + qs : ''}`);
		} catch (err: any) {
			error = err.message || t('common.error');
		} finally {
			eventsLoading = false;
		}
	}

	async function loadChart() {
		try {
			const params = buildFilterParams();
			const qs = params.toString();
			const chartRes = await api<{ days: { date: string; [k: string]: string | number }[] }>(`/status/chart${qs ? '?' + qs : ''}`);
			chartDays = chartRes.days || [];
		} catch (e) { console.warn('Failed to load chart data:', e); }
	}

	// Auto-apply when filter values change (via IconGridSelect bind:value)
	let _prevFilterKey = '';
	$effect(() => {
		const key = `${filterEventType}|${effectiveProviderId}|${filterSort}`;
		if (loaded && key !== _prevFilterKey && _prevFilterKey !== '') {
			applyFilters();
		}
		_prevFilterKey = key;
	});

	function applyFilters() {
		eventsOffset = 0;
		loadEvents();
		loadChart();
	}

	function goToPage(page: number) {
		eventsOffset = (page - 1) * eventsLimit;
		loadEvents();
	}

	let searchTimeout: ReturnType<typeof setTimeout>;
	function onSearchInput() {
		clearTimeout(searchTimeout);
		searchTimeout = setTimeout(applyFilters, 300);
	}

	onMount(() => {
		loadInitial();
		return () => {
			clearTimeout(searchTimeout);
		};
	});

	async function loadInitial() {
		try {
			const [statusRes, , chartRes] = await Promise.all([
				api<DashboardStatus>(`/status?limit=${eventsLimit}`),
				providersCache.fetch(),
				api<{ days: { date: string; [k: string]: string | number }[] }>('/status/chart'),
			]);
			status = statusRes;
			chartDays = chartRes.days || [];
			setTimeout(() => {
				if (!status) return;
				animateCount(0, status.providers, (v) => displayProviders = v);
				animateCount(0, status.trackers.active, (v) => displayActive = v);
				animateCount(0, status.trackers.total, (v) => displayTotal = v);
				animateCount(0, status.targets, (v) => displayTargets = v);
				if (status.command_trackers !== undefined) {
					animateCount(0, status.command_trackers, (v) => displayCommandTrackers = v);
				}
			}, 200);
		} catch (err: any) {
			error = err.message || t('common.error');
		} finally {
			loaded = true;
		}
	}

	let displayCommandTrackers = $state(0);

	const filteredProviderCount = $derived(globalProviderFilter.providerType
		? providers.filter(p => p.type === globalProviderFilter.providerType).length
		: displayProviders);

	const providerCard = $derived.by(() => {
		const gp = globalProviderFilter.provider;
		if (gp) {
			const desc = getDescriptor(gp.type);
			return { icon: providerDefaultIcon(gp), label: '', literalLabel: desc?.defaultName ?? gp.type, value: 0, literalValue: gp.name, color: '#0d9488' };
		}
		return { icon: 'mdiServer', label: 'dashboard.providers', value: filteredProviderCount, color: '#0d9488' };
	});

	interface StatCard { icon: string; label: string; literalLabel?: string; value: number; literalValue?: string; suffix?: string; color: string }
	const statCards = $derived<StatCard[]>(status ? [
		providerCard,
		{ icon: 'mdiRadar', label: 'dashboard.activeTrackers', value: displayActive, suffix: ` / ${displayTotal}`, color: '#6366f1' },
		{ icon: 'mdiTarget', label: 'dashboard.targets', value: displayTargets, color: '#f59e0b' },
		...(status.command_trackers !== undefined ? [{ icon: 'mdiConsoleLine', label: 'nav.commandTrackers', value: displayCommandTrackers, color: '#8b5cf6' }] : []),
	] : []);

	function timeAgo(dateStr: string): string {
		const diff = Date.now() - parseDate(dateStr).getTime();
		const mins = Math.floor(diff / 60000);
		if (mins < 1) return t('dashboard.justNow');
		if (mins < 60) return t('dashboard.minutesAgo').replace('{n}', String(mins));
		const hours = Math.floor(mins / 60);
		if (hours < 24) return t('dashboard.hoursAgo').replace('{n}', String(hours));
		return t('dashboard.daysAgo').replace('{n}', String(Math.floor(hours / 24)));
	}

	const eventLabels: Record<string, string> = {
		assets_added: 'dashboard.assetsAdded',
		assets_removed: 'dashboard.assetsRemoved',
		collection_renamed: 'dashboard.collectionRenamed',
		collection_deleted: 'dashboard.collectionDeleted',
		sharing_changed: 'dashboard.sharingChanged',
		action_success: 'dashboard.actionSuccess',
		action_partial: 'dashboard.actionPartial',
		action_failed: 'dashboard.actionFailed',
	};

	const eventIcons: Record<string, string> = {
		assets_added: 'mdiImagePlus', assets_removed: 'mdiImageMinus',
		collection_renamed: 'mdiRename', collection_deleted: 'mdiDeleteAlert', sharing_changed: 'mdiShareVariant',
		action_success: 'mdiPlayCircle', action_partial: 'mdiAlertCircle', action_failed: 'mdiCloseCircle',
	};
	const eventColors: Record<string, string> = {
		assets_added: '#059669', assets_removed: '#ef4444',
		collection_renamed: '#6366f1', collection_deleted: '#dc2626', sharing_changed: '#f59e0b',
		action_success: '#0d9488', action_partial: '#f59e0b', action_failed: '#dc2626',
	};

</script>

<PageHeader title={t('dashboard.title')} description={t('dashboard.description')} />

{#if !loaded}
	<Loading lines={4} />
{:else if error}
	<Card>
		<div class="flex items-center gap-2" style="color: var(--color-error-fg);">
			<MdiIcon name="mdiAlertCircle" size={20} />
			<p class="text-sm">{error}</p>
		</div>
	</Card>
{:else if status}
	<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-8 stagger-children">
		{#each statCards as card, i}
			<div class="stat-card" style="--accent: {card.color};">
				<div class="stat-card-inner">
					<div class="flex items-center gap-3">
						<div class="stat-icon" style="background: {card.color}15; color: {card.color};">
							<MdiIcon name={card.icon} size={22} />
						</div>
						<div>
							<p class="text-sm" style="color: var(--color-muted-foreground);">{card.literalLabel || t(card.label)}</p>
							<p class="{card.literalValue ? 'stat-value-text' : 'stat-value'} font-mono" style="animation-delay: {i * 80 + 200}ms;">
								{#if card.literalValue}{card.literalValue}{:else}{card.value}{/if}{#if card.suffix}<span class="stat-suffix">{card.suffix}</span>{/if}
							</p>
						</div>
					</div>
				</div>
			</div>
		{/each}
	</div>

	<!-- Events section -->
	<div class="flex items-center justify-between mb-3">
		<h3 class="text-base font-semibold flex items-center gap-2">
			<MdiIcon name="mdiPulse" size={18} />
			{t('dashboard.recentEvents')}
			{#if status.total_events > 0}
				<span class="text-xs font-normal text-[var(--color-muted-foreground)]">({status.total_events})</span>
			{/if}
		</h3>
		{#if status.total_events > 0}
			<button type="button" onclick={() => confirmClearEvents = true}
				class="clear-events-btn flex items-center gap-1.5 px-2.5 py-1 text-xs border border-[var(--color-border)] rounded-md transition-colors"
				title={t('dashboard.clearEvents')}>
				<MdiIcon name="mdiTrashCanOutline" size={14} />
				<span class="hidden sm:inline">{t('dashboard.clearEvents')}</span>
			</button>
		{/if}
	</div>

	<!-- Filters -->
	<div class="flex flex-wrap items-center gap-2 mb-4">
		<div class="flex-1 min-w-[150px] max-w-[260px]">
			<input type="text" bind:value={filterSearch} oninput={onSearchInput}
				placeholder={t('dashboard.searchEvents')}
				class="w-full px-3 py-1.5 border border-[var(--color-border)] rounded-md text-sm bg-[var(--color-background)]" />
		</div>
		<div class="w-40"><IconGridSelect items={eventTypeFilterItems()} bind:value={filterEventType} columns={3} compact /></div>
		{#if !globalProviderFilter.id}<div class="w-40"><IconGridSelect items={providerFilterItems} bind:value={filterProviderId} columns={2} compact /></div>{/if}
		<div class="w-36"><IconGridSelect items={sortFilterItems()} bind:value={filterSort} columns={2} compact /></div>
	</div>

	<!-- Chart -->
	<button type="button" onclick={toggleChart}
		class="flex items-center gap-1.5 text-xs text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)] transition-colors mb-2 cursor-pointer">
		<MdiIcon name={chartVisible ? 'mdiChevronDown' : 'mdiChevronRight'} size={14} />
		<MdiIcon name="mdiChartBar" size={14} />
		{t('dashboard.chart')}
	</button>
	{#if chartVisible}
		<div in:slide={{ duration: 200 }}>
			<EventChart days={chartDays} />
		</div>
	{/if}

	{#snippet paginator()}
		<div class="flex items-center justify-center gap-1">
			{#if totalPages > 1}
				<button onclick={() => goToPage(currentPage - 1)} disabled={currentPage <= 1}
					class="px-2 py-1 text-sm border border-[var(--color-border)] rounded-md hover:bg-[var(--color-muted)] transition-colors disabled:opacity-50 disabled:cursor-default">
					<MdiIcon name="mdiChevronLeft" size={16} />
				</button>
				{#each Array.from({ length: totalPages }, (_, i) => i + 1) as page}
					{#if page === 1 || page === totalPages || (page >= currentPage - 1 && page <= currentPage + 1)}
						<button onclick={() => goToPage(page)}
							class="px-2.5 py-1 text-xs font-mono rounded-md border transition-colors {page === currentPage
								? 'bg-[var(--color-primary)] text-[var(--color-primary-foreground)] border-[var(--color-primary)]'
								: 'border-[var(--color-border)] hover:bg-[var(--color-muted)]'}">
							{page}
						</button>
					{:else if page === currentPage - 2 || page === currentPage + 2}
						<span class="px-1 text-xs text-[var(--color-muted-foreground)]">...</span>
					{/if}
				{/each}
				<button onclick={() => goToPage(currentPage + 1)} disabled={currentPage >= totalPages}
					class="px-2 py-1 text-sm border border-[var(--color-border)] rounded-md hover:bg-[var(--color-muted)] transition-colors disabled:opacity-50 disabled:cursor-default">
					<MdiIcon name="mdiChevronRight" size={16} />
				</button>
			{/if}
			<select value={eventsLimit}
				onchange={(e) => { const v = parseInt((e.target as HTMLSelectElement).value, 10); eventsLimit = v; eventsOffset = 0; if (typeof localStorage !== 'undefined') localStorage.setItem(EVENTS_PER_PAGE_KEY, String(v)); loadEvents(); }}
				class="ml-2 px-2 py-1 text-xs border border-[var(--color-border)] rounded-md bg-[var(--color-background)] text-[var(--color-foreground)]">
				{#each [5, 10, 20, 50] as n}
					<option value={n}>{n}</option>
				{/each}
			</select>
		</div>
	{/snippet}

	{#if eventsLoading}
		<Card><p class="text-sm text-center py-4" style="color: var(--color-muted-foreground);">{t('dashboard.loadingEvents')}</p></Card>
	{:else if status.recent_events.length === 0}
		<Card>
			<div class="flex flex-col items-center py-8 gap-3" style="color: var(--color-muted-foreground);">
				<div style="opacity: 0.4;"><MdiIcon name="mdiCalendarBlank" size={40} /></div>
				<p class="text-sm">{t('dashboard.noEvents')}</p>
			</div>
		</Card>
	{:else}
		<div class="event-timeline stagger-children">
			{#each status.recent_events as event, i}
				<div class="event-item" style="animation-delay: {i * 60}ms;">
					<div class="event-dot" style="background: {eventColors[event.event_type] || 'var(--color-muted-foreground)'}; box-shadow: 0 0 8px {eventColors[event.event_type] || 'var(--color-muted-foreground)'}40;"></div>
					{#if i < status.recent_events.length - 1}<div class="event-line"></div>{/if}
					<div class="event-content">
						<div class="flex items-center justify-between gap-2">
							<div class="flex items-center gap-2 min-w-0 flex-wrap">
								<span style="color: {eventColors[event.event_type] || 'var(--color-muted-foreground)'}; flex-shrink: 0;">
									<MdiIcon name={eventIcons[event.event_type] || 'mdiBell'} size={16} />
								</span>
								<span class="text-sm font-medium truncate">{event.collection_name}</span>
								<span class="event-badge">{t(eventLabels[event.event_type] || event.event_type)}</span>
								{#if event.assets_count > 0}
									<span class="event-badge" style="background: {eventColors[event.event_type]}20; color: {eventColors[event.event_type]};">{event.assets_count} {event.assets_count === 1 ? t('dashboard.asset') : t('dashboard.assets')}</span>
								{/if}
							</div>
							<span class="text-xs whitespace-nowrap font-mono" style="color: var(--color-muted-foreground);">{timeAgo(event.created_at)}</span>
						</div>
						{#if event.provider_name || event.tracker_name}
							<div class="flex items-center gap-2 mt-1 text-xs" style="color: var(--color-muted-foreground);">
								{#if event.provider_name}
									<span class="flex items-center gap-1"><MdiIcon name="mdiServer" size={12} />{event.provider_name}</span>
								{/if}
								{#if event.tracker_name}
									<span class="flex items-center gap-1"><MdiIcon name="mdiRadar" size={12} />{event.tracker_name}</span>
								{/if}
							</div>
						{/if}
					</div>
				</div>
			{/each}
		</div>

		<!-- Bottom paginator -->
		<div class="mt-4">
			{@render paginator()}
		</div>
	{/if}
{/if}

<ConfirmModal open={confirmClearEvents} message={t('dashboard.confirmClearEvents')}
	onconfirm={clearEvents} oncancel={() => confirmClearEvents = false} />

<style>
	.stat-card { position: relative; border-radius: 0.75rem; padding: 1px; background: linear-gradient(135deg, var(--accent), transparent 60%, var(--color-border)); transition: all 0.3s ease; }
	.stat-card:hover { box-shadow: 0 0 24px color-mix(in srgb, var(--accent) 20%, transparent); }
	.stat-card-inner { background: var(--color-card); border-radius: calc(0.75rem - 1px); padding: 1.25rem; }
	.stat-icon { display: flex; align-items: center; justify-content: center; width: 2.75rem; height: 2.75rem; border-radius: 0.75rem; flex-shrink: 0; }
	.stat-value { font-size: 1.75rem; font-weight: 600; line-height: 1.2; animation: countUp 0.5s ease-out both; }
	.stat-value-text { font-size: 1rem; font-weight: 600; line-height: 1.3; animation: countUp 0.5s ease-out both; }
	.stat-suffix { font-size: 1rem; font-weight: 400; color: var(--color-muted-foreground); }
	.event-timeline { display: flex; flex-direction: column; }
	.event-item { display: flex; align-items: flex-start; gap: 0.75rem; position: relative; padding-bottom: 0.5rem; }
	.event-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; margin-top: 6px; z-index: 1; }
	.event-line { position: absolute; left: 4px; top: 18px; bottom: 0; width: 2px; background: var(--color-border); }
	.event-content { flex: 1; min-width: 0; padding: 0.375rem 0.75rem; border-radius: 0.5rem; background: var(--color-card); border: 1px solid var(--color-border); transition: all 0.2s ease; }
	.event-content:hover { border-color: var(--color-primary); box-shadow: 0 0 12px var(--color-glow); }
	.event-badge { display: inline-block; font-size: 0.65rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.03em; padding: 0.15rem 0.5rem; border-radius: 9999px; background: var(--color-muted); color: var(--color-muted-foreground); white-space: nowrap; font-family: var(--font-mono); }
	.clear-events-btn { color: var(--color-muted-foreground); background: transparent; }
	.clear-events-btn:hover { background: color-mix(in srgb, var(--color-error-fg) 10%, transparent); border-color: color-mix(in srgb, var(--color-error-fg) 40%, var(--color-border)); color: var(--color-error-fg); }
</style>
