<script lang="ts">
	import type { Project, Instance, StaleContainer, StaticSite } from '$lib/types';
	import * as api from '$lib/api';
	import ProjectCard from '$lib/components/ProjectCard.svelte';
	import SkeletonCard from '$lib/components/SkeletonCard.svelte';
	import EmptyState from '$lib/components/EmptyState.svelte';
	import SystemHealthCard from '$lib/components/SystemHealthCard.svelte';
	import SystemDaemonsCard from '$lib/components/SystemDaemonsCard.svelte';
	import SystemResourcesCard from '$lib/components/SystemResourcesCard.svelte';
	import CollapsibleSection from '$lib/components/CollapsibleSection.svelte';
	import ForgeHero from '$lib/components/ForgeHero.svelte';
	import { IconDeploy, IconAlert } from '$lib/components/icons';
	import { t } from '$lib/i18n';
	import { fmt } from '$lib/format/datetime';

	let projects = $state<Project[]>([]);
	let instancesByProject = $state<Record<string, Instance[]>>({});
	let staleContainers = $state<StaleContainer[]>([]);
	let unusedImagesMB = $state(0);
	let unusedImagesCount = $state(0);
	let unusedImagesExceeded = $state(false);
	let sites = $state<StaticSite[]>([]);
	let loading = $state(true);
	let error = $state('');
	let loadController: AbortController | null = null;

	async function loadDashboard() {
		loadController?.abort();
		const controller = new AbortController();
		loadController = controller;
		const signal = controller.signal;

		loading = true;
		error = '';
		try {
			projects = await api.listProjects(signal);

			// Fetch project details sequentially to avoid exhausting
			// browser connection pool (HTTP/1.1 allows only 6 per host).
			const results: { projectId: string; instances: Instance[] }[] = [];
			for (const p of projects) {
				try {
					const detail = await api.getProject(p.id, signal);
					const stages = detail.stages ?? [];
					const stageInstances: Instance[][] = [];
					for (const s of stages) {
						stageInstances.push(await api.listInstances(p.id, s.id, signal));
					}
					results.push({ projectId: p.id, instances: stageInstances.flat() });
				} catch (e) {
					if (e instanceof DOMException && e.name === 'AbortError') throw e;
					results.push({ projectId: p.id, instances: [] });
				}
			}

			const mapped: Record<string, Instance[]> = {};
			for (const r of results) {
				mapped[r.projectId] = r.instances;
			}
			instancesByProject = mapped;

			staleContainers = await api.fetchStaleContainers(signal).catch(() => [] as StaleContainer[]);

			sites = await api.listStaticSites(signal).catch(() => [] as StaticSite[]);

			try {
				const imgStats = await api.getUnusedImageStats(signal);
				unusedImagesMB = imgStats.total_size_mb;
				unusedImagesCount = imgStats.count;
				unusedImagesExceeded = imgStats.exceeded;
			} catch { /* non-critical */ }
		} catch (e) {
			if (e instanceof DOMException && e.name === 'AbortError') return;
			error = e instanceof Error ? e.message : $t('dashboard.loadFailed');
		} finally {
			loading = false;
		}
	}

	$effect(() => {
		loadDashboard();
		return () => { loadController?.abort(); };
	});

	const totalProjects = $derived(projects.length);
	const totalRunning = $derived(
		Object.values(instancesByProject)
			.flat()
			.filter((i) => i.status === 'running').length
	);
	const totalFailed = $derived(
		Object.values(instancesByProject)
			.flat()
			.filter((i) => i.status === 'failed').length
	);
	const totalStale = $derived(staleContainers.length);
	const totalSites = $derived(sites.length);
	const deployedSites = $derived(sites.filter((s) => s.status === 'deployed').length);
	const failedSitesCount = $derived(sites.filter((s) => s.status === 'failed').length);

	function siteStatusBadge(status: string): { text: string; cls: string } {
		switch (status) {
			case 'deployed':
				return { text: 'Deployed', cls: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400' };
			case 'syncing':
				return { text: 'Syncing', cls: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400' };
			case 'failed':
				return { text: 'Failed', cls: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400' };
			case 'stopped':
				return { text: 'Stopped', cls: 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400' };
			default:
				return { text: 'Idle', cls: 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400' };
		}
	}
</script>

<svelte:head>
	<title>{$t('dashboard.title')} - {$t('app.name')}</title>
</svelte:head>

<div class="space-y-6 dashboard">
	<!-- Hero -->
	{#snippet heroToolbar()}
		<a href="/deploy" class="forge-btn">
			<IconDeploy size={14} />
			<span>{$t('dashboard.quickDeploy')}</span>
		</a>
	{/snippet}
	<ForgeHero
		eyebrow="THE FORGE"
		eyebrowSuffix="DASHBOARD"
		title={$t('dashboard.title')}
		accent="."
		size="lg"
		toolbar={heroToolbar}
	/>

	<!-- Stats grid -->
	<div class="forge-stat-grid">
		<div class="forge-stat">
			<span class="forge-stat-label">{$t('dashboard.totalProjects')}</span>
			<span class="forge-stat-value">{String(totalProjects).padStart(2, '0')}</span>
			<span class="forge-stat-sub">active</span>
		</div>
		<div class="forge-stat">
			<span class="forge-stat-label">{$t('dashboard.runningInstances')}</span>
			<span class="forge-stat-value accent">{String(totalRunning).padStart(2, '0')}</span>
			<span class="forge-stat-sub">instances</span>
		</div>
		<div class="forge-stat">
			<span class="forge-stat-label">{$t('dashboard.failedInstances')}</span>
			<span class="forge-stat-value" class:fail={totalFailed > 0}>{String(totalFailed).padStart(2, '0')}</span>
			<span class="forge-stat-sub">need attention</span>
		</div>
		<a href="/containers/stale" class="forge-stat stat-link">
			<span class="forge-stat-label">{$t('dashboard.staleContainers')}</span>
			<span class="forge-stat-value" class:warn={totalStale > 0}>{String(totalStale).padStart(2, '0')}</span>
			<span class="forge-stat-sub">stale →</span>
		</a>
		<a href="/sites" class="forge-stat stat-link">
			<span class="forge-stat-label">{$t('dashboard.totalSites')}</span>
			<span class="forge-stat-value">{String(totalSites).padStart(2, '0')}</span>
			<span class="forge-stat-sub">
				{#if deployedSites > 0}<span class="tag ok">{deployedSites} up</span>{/if}
				{#if failedSitesCount > 0}<span class="tag bad">{failedSitesCount} fail</span>{/if}
				{#if deployedSites === 0 && failedSitesCount === 0}static sites →{/if}
			</span>
		</a>
	</div>

	<!-- Unused images warning -->
	{#if unusedImagesExceeded}
		<a href="/settings" class="flex items-center gap-3 rounded-xl border border-amber-300 bg-amber-50 dark:border-amber-700 dark:bg-amber-950/30 p-4 transition-colors hover:bg-amber-100 dark:hover:bg-amber-950/50">
			<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-amber-100 dark:bg-amber-900/50 text-amber-600">
				<IconAlert size={20} />
			</div>
			<div class="flex-1">
				<p class="text-sm font-medium text-amber-800 dark:text-amber-300">{$t('dashboard.unusedImagesWarning')}</p>
				<p class="text-xs text-amber-700 dark:text-amber-400">{unusedImagesCount} {$t('dashboard.unusedImages')} &middot; {unusedImagesMB >= 1024 ? (unusedImagesMB / 1024).toFixed(1) + ' GB' : unusedImagesMB + ' MB'}</p>
			</div>
			<span class="text-xs font-medium text-amber-600 dark:text-amber-400">{$t('settings.pruneImages')} &rarr;</span>
		</a>
	{/if}

	<!-- System health summary -->
	<CollapsibleSection id="system-health" title={$t('dashboard.systemHealth')}>
		<SystemHealthCard />
	</CollapsibleSection>

	<!-- Detailed daemon panel: Docker engine + NPM/Traefik proxy -->
	<CollapsibleSection id="system-daemons" title={$t('dashboard.daemons')} defaultOpen={false}>
		<SystemDaemonsCard />
	</CollapsibleSection>

	<!-- Host CPU/memory/disk + top consumers -->
	<CollapsibleSection
		id="system-resources"
		title={$t('dashboard.systemResources')}
		subtitle={$t('dashboard.systemResourcesSubtitle')}
	>
		<SystemResourcesCard />
	</CollapsibleSection>

	<!-- Static sites summary -->
	{#if !loading}
		{#snippet sitesActions()}
			{#if sites.length > 0}
				<a href="/sites" class="text-xs font-medium text-[var(--color-brand-600)] hover:underline">
					{$t('dashboard.viewAllSites')} →
				</a>
			{/if}
		{/snippet}
		<CollapsibleSection
			id="dashboard-sites"
			title={$t('dashboard.staticSites')}
			badge={sites.length > 0 ? String(sites.length) : ''}
			actions={sitesActions}
		>
			{#if sites.length === 0}
				<EmptyState
					title={$t('dashboard.noSites')}
					description={$t('dashboard.addFirstSite')}
					actionLabel={$t('sites.title')}
					actionHref="/sites"
					icon="projects"
				/>
			{:else}
				<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
					{#each sites as site (site.id)}
						{@const badge = siteStatusBadge(site.status)}
						<a href="/sites/{site.id}" class="flex flex-col gap-2 rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] p-4 shadow-[var(--shadow-sm)] transition-colors hover:bg-[var(--surface-card-hover)]">
							<div class="flex items-center justify-between gap-2">
								<span class="truncate font-medium text-[var(--text-primary)]">{site.name}</span>
								<span class="inline-flex shrink-0 items-center rounded-full px-2 py-0.5 text-xs font-medium {badge.cls}">{badge.text}</span>
							</div>
							<div class="flex items-center gap-3 text-xs text-[var(--text-secondary)]">
								<span class="truncate">{site.repo_owner}/{site.repo_name}</span>
								{#if site.domain}
									<span class="truncate text-[var(--color-brand-600)]">{site.domain}</span>
								{/if}
							</div>
							{#if site.last_sync_at}
								<p class="text-xs text-[var(--text-tertiary)]">{$t('sites.lastSync')}: {$fmt.dateTime(site.last_sync_at)}</p>
							{/if}
						</a>
					{/each}
				</div>
			{/if}
		</CollapsibleSection>
	{/if}

	<!-- Project cards -->
	<CollapsibleSection
		id="dashboard-projects"
		title={$t('dashboard.projects')}
		badge={!loading && projects.length > 0 ? String(projects.length) : ''}
	>
		{#if loading}
			<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
				{#each Array(3) as _}
					<SkeletonCard />
				{/each}
			</div>
		{:else if error}
			<div class="rounded-xl border border-[var(--color-danger-light)] bg-[var(--color-danger-light)] p-4">
				<p class="text-sm text-[var(--color-danger)]">{error}</p>
				<button
					type="button"
					class="mt-2 text-sm font-medium text-[var(--color-danger)] underline hover:no-underline"
					onclick={loadDashboard}
				>
					{$t('dashboard.retry')}
				</button>
			</div>
		{:else if projects.length === 0}
			<EmptyState
				title={$t('empty.noProjects')}
				description={$t('empty.noProjectsDesc')}
				actionLabel={$t('empty.createProject')}
				actionHref="/projects"
				icon="projects"
			/>
		{:else}
			<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
				{#each projects as project (project.id)}
					<ProjectCard {project} instances={instancesByProject[project.id] ?? []} />
				{/each}
			</div>
		{/if}
	</CollapsibleSection>
</div>

<style>
	.dashboard { position: relative; }

	.stat-link {
		text-decoration: none;
		transition: background 150ms ease;
	}
	.stat-link:hover { background: var(--surface-card-hover); }
	.stat-link .forge-stat-sub .tag {
		display: inline-block;
		padding: 0.05rem 0.4rem;
		margin-right: 0.25rem;
		border-radius: var(--radius-sm);
		font-family: var(--forge-mono);
		font-size: 0.62rem;
		font-weight: 600;
	}
	.stat-link .tag.ok { background: var(--color-success-light); color: var(--color-success-dark); }
	.stat-link .tag.bad { background: var(--color-danger-light); color: var(--color-danger-dark); }
	:global([data-theme='dark']) .stat-link .tag.ok { background: color-mix(in srgb, var(--color-success) 16%, transparent); color: #86efac; }
	:global([data-theme='dark']) .stat-link .tag.bad { background: color-mix(in srgb, var(--color-danger) 16%, transparent); color: #fca5a5; }

	.section { margin-top: 0.5rem; }
</style>
