<script lang="ts">
	import { onMount } from 'svelte';
	import { IconPlus, IconRefresh } from '$lib/components/icons';
	import ForgeHero from '$lib/components/ForgeHero.svelte';
	import { workloadsCache } from '$lib/stores/caches';
	import { t } from '$lib/i18n';

	// Cache-backed (stale-while-revalidate): the value persists across
	// navigation, so revisiting this tab renders the table immediately instead
	// of flashing the cold skeleton. The skeleton only shows on the very first
	// visit of the session.
	const workloads = $derived($workloadsCache.value);
	const loading = $derived($workloadsCache.loading);
	const error = $derived($workloadsCache.error);
	let filter = $state<'all' | string>('all');

	// Plugin-native rows are those with a source_kind. trigger_kind is no
	// longer on the workload row (triggers are first-class bindings now), so a
	// manual/binding-trigger app legitimately has an empty trigger_kind and
	// must NOT be filtered out. Legacy pre-cutover project/stack/site rows
	// carry an empty source_kind and are excluded — they have no UI home.
	const pluginRows = $derived(workloads.filter((w) => w.source_kind !== ''));
	const filtered = $derived(
		filter === 'all' ? pluginRows : pluginRows.filter((w) => w.source_kind === filter)
	);
	const sourceKinds = $derived(
		Array.from(new Set(pluginRows.map((w) => w.source_kind))).sort()
	);
	const countBy = $derived((kind: string) =>
		pluginRows.filter((w) => w.source_kind === kind).length
	);

	const load = () => workloadsCache.refresh();

	function sourceBadge(kind: string): string {
		switch (kind) {
			case 'image':
				return 'badge-image';
			case 'compose':
				return 'badge-compose';
			case 'static':
				return 'badge-static';
			default:
				return 'badge-other';
		}
	}

	onMount(load);
</script>

<svelte:head>
	<title>Apps · Tinyforge</title>
</svelte:head>

<div class="forge">
	{#snippet appsToolbar()}
		<button class="forge-btn-icon" onclick={load} aria-label={$t('apps.list.refresh')}>
			<IconRefresh size={16} />
		</button>
		<a href="/apps/new" class="forge-btn">
			<IconPlus size={14} />
			<span>{$t('apps.list.newApp')}</span>
		</a>
	{/snippet}

	{#snippet appsStats()}
		<div>
			<dt>{$t('apps.list.statTotal')}</dt>
			<dd>{loading ? '—' : String(pluginRows.length).padStart(2, '0')}</dd>
		</div>
		<div>
			<dt>{$t('apps.list.statImage')}</dt>
			<dd>{loading ? '—' : String(countBy('image')).padStart(2, '0')}</dd>
		</div>
		<div>
			<dt>{$t('apps.list.statCompose')}</dt>
			<dd>{loading ? '—' : String(countBy('compose')).padStart(2, '0')}</dd>
		</div>
		<div>
			<dt>{$t('apps.list.statStatic')}</dt>
			<dd class="accent">{loading ? '—' : String(countBy('static')).padStart(2, '0')}</dd>
		</div>
	{/snippet}

	{#snippet appsLede()}
		{$t('apps.list.ledePrefix')} <em>{$t('apps.list.ledeKindImage')}</em>, <em>{$t('apps.list.ledeKindCompose')}</em>{$t('apps.list.ledeMiddle')}
		<em>{$t('apps.list.ledeKindStatic')}</em>{$t('apps.list.ledeSuffix')}
	{/snippet}

	<ForgeHero
		eyebrowSuffix={$t('apps.list.eyebrowSuffix')}
		title={$t('apps.list.title')}
		size="lg"
		toolbar={appsToolbar}
		lede_html={appsLede}
		stats={appsStats}
	/>

	{#if error}
		<div class="alert"><span class="alert-tag">{$t('apps.list.alertTag')}</span><span>{error}</span></div>
	{/if}

	{#if !loading && pluginRows.length > 0}
		<div class="filter-row" role="tablist" aria-label={$t('apps.list.filterAriaLabel')}>
			<button
				class="chip"
				class:active={filter === 'all'}
				role="tab"
				aria-selected={filter === 'all'}
				onclick={() => (filter = 'all')}
			>
				<span class="chip-label">{$t('apps.list.filterAll')}</span>
				<span class="chip-count">{String(pluginRows.length).padStart(2, '0')}</span>
			</button>
			{#each sourceKinds as kind}
				{@const count = countBy(kind)}
				<button
					class="chip src-{kind}"
					class:active={filter === kind}
					role="tab"
					aria-selected={filter === kind}
					onclick={() => (filter = kind)}
				>
					<span class="chip-dot" aria-hidden="true"></span>
					<span class="chip-label">{kind.toUpperCase()}</span>
					<span class="chip-count">{String(count).padStart(2, '0')}</span>
				</button>
			{/each}
		</div>
	{/if}

	{#if loading}
		<div class="skeleton-rows" aria-busy="true">
			{#each Array(4) as _, i}
				<div class="skeleton-row" style:--i={i}></div>
			{/each}
		</div>
	{:else if filtered.length === 0}
		<div class="empty">
			<div class="empty-mark"><span></span><span></span><span></span></div>
			<h2>{$t('apps.list.emptyTitle')}</h2>
			<p>{$t('apps.list.emptyBody')}</p>
			<a href="/apps/new" class="btn-primary">
				<IconPlus size={14} /><span>{$t('apps.list.emptyCta')}</span>
			</a>
		</div>
	{:else}
		<div class="table-wrap">
			<table class="forge-table">
				<thead>
					<tr>
						<th>{$t('apps.list.colName')}</th>
						<th>{$t('apps.list.colSource')}</th>
						<th>{$t('apps.list.colTrigger')}</th>
						<th>{$t('apps.list.colCreated')}</th>
						<th class="t-right">{$t('apps.list.colActions')}</th>
					</tr>
				</thead>
				<tbody>
					{#each filtered as w, i (w.id)}
						<tr>
							<td>
								<a class="row-link" href={`/apps/${w.id}`}>
									<span class="row-ref">{String(i + 1).padStart(2, '0')}</span>
									<span class="row-name">{w.name}</span>
								</a>
							</td>
							<td>
								<span class="badge {sourceBadge(w.source_kind)}">
									<span class="badge-dot" aria-hidden="true"></span>{w.source_kind}
								</span>
								{#if w.gitops_enabled && (w.source_kind === 'dockerfile' || w.source_kind === 'static')}
									<span class="badge badge-gitops" title={$t('apps.list.gitopsBadgeTitle')}>
										<span class="badge-dot" aria-hidden="true"></span>{$t('apps.list.gitopsBadge')}
									</span>
								{/if}
							</td>
							<td>
								<span class="badge badge-trigger">{w.trigger_kind}</span>
							</td>
							<td class="muted mono">{w.created_at}</td>
							<td class="actions-cell">
								<a class="row-action" href={`/apps/${w.id}`}>
									{$t('apps.list.rowOpen')} <span class="arrow" aria-hidden="true">→</span>
								</a>
							</td>
						</tr>
					{/each}
				</tbody>
			</table>
		</div>
	{/if}
</div>

<style>
	.forge {
		--accent: var(--forge-accent);
		--accent-soft: var(--forge-accent-soft);
		--glow: var(--forge-glow);
		display: flex;
		flex-direction: column;
		gap: 1.25rem;
		max-width: 1240px;
		margin: 0 auto;
	}

	/* ── Alert ─────────────────────────────────────── */
	.alert {
		display: flex;
		gap: 0.7rem;
		align-items: center;
		padding: 0.7rem 0.9rem;
		background: var(--color-danger-light);
		color: var(--color-danger-dark);
		border: 1px solid var(--color-danger);
		border-left-width: 4px;
		border-radius: var(--radius-lg);
		font-size: 0.875rem;
	}
	.alert-tag {
		font-family: var(--forge-mono);
		font-weight: 700;
		font-size: 0.65rem;
		letter-spacing: 0.16em;
		padding: 0.15rem 0.4rem;
		background: var(--color-danger);
		color: #fff;
		border-radius: var(--radius-sm);
	}
	:global([data-theme='dark']) .alert {
		background: color-mix(in srgb, var(--color-danger) 14%, transparent);
		color: #fca5a5;
	}

	/* ── Filter chips ──────────────────────────────── */
	.filter-row {
		display: flex;
		gap: 0.4rem;
		flex-wrap: wrap;
	}
	.chip {
		display: inline-flex;
		align-items: center;
		gap: 0.45rem;
		padding: 0.35rem 0.75rem;
		border: 1px solid var(--border-primary);
		background: var(--surface-card);
		border-radius: var(--radius-full);
		font-family: var(--forge-mono);
		font-size: 0.66rem;
		font-weight: 600;
		letter-spacing: 0.12em;
		color: var(--text-secondary);
		cursor: pointer;
		transition: border-color 150ms ease, background 150ms ease, color 150ms ease,
			transform 150ms ease;
	}
	.chip:hover {
		background: var(--surface-card-hover);
		color: var(--text-primary);
		transform: translateY(-1px);
	}
	.chip:focus-visible {
		outline: 2px solid var(--border-focus);
		outline-offset: 2px;
	}
	.chip.active {
		background: var(--text-primary);
		color: var(--surface-card);
		border-color: var(--text-primary);
	}
	.chip.active .chip-count,
	.chip.active .chip-dot {
		color: var(--surface-card);
	}
	.chip-dot {
		width: 6px;
		height: 6px;
		border-radius: 50%;
		background: currentColor;
		opacity: 0.7;
	}
	.chip.src-image .chip-dot {
		color: var(--badge-image-color);
	}
	.chip.src-compose .chip-dot {
		color: var(--badge-compose-color);
	}
	.chip.src-static .chip-dot {
		color: var(--badge-static-color);
	}
	.chip-count {
		font-variant-numeric: tabular-nums;
		font-size: 0.62rem;
		opacity: 0.7;
	}

	/* ── Skeleton ──────────────────────────────────── */
	.skeleton-rows {
		display: flex;
		flex-direction: column;
		gap: 0.55rem;
	}
	.skeleton-row {
		height: 52px;
		border: 1px solid var(--border-primary);
		border-radius: var(--radius-lg);
		background: linear-gradient(
			110deg,
			var(--surface-card) 20%,
			var(--surface-card-hover) 50%,
			var(--surface-card) 80%
		);
		background-size: 200% 100%;
		animation: shimmer 1.6s linear infinite;
		animation-delay: calc(var(--i) * 120ms);
	}
	@keyframes shimmer {
		0% {
			background-position: 200% 0;
		}
		100% {
			background-position: -200% 0;
		}
	}

	/* ── Empty ─────────────────────────────────────── */
	.empty {
		text-align: center;
		padding: 4rem 2rem;
		border: 1px dashed var(--border-primary);
		border-radius: var(--radius-2xl);
		background: var(--surface-card);
	}
	.empty-mark {
		display: inline-flex;
		gap: 4px;
		margin-bottom: 1.5rem;
	}
	.empty-mark span {
		width: 10px;
		height: 10px;
		border-radius: 50%;
		background: var(--border-input);
	}
	.empty-mark span:nth-child(2) {
		background: var(--accent);
		animation: ember 2.4s ease-in-out infinite;
	}
	@keyframes ember {
		0%,
		100% {
			box-shadow: 0 0 0 3px var(--accent-soft);
		}
		50% {
			box-shadow: 0 0 0 6px color-mix(in srgb, var(--color-brand-500) 18%, transparent);
		}
	}
	.empty h2 {
		font-family: var(--font-family-sans);
		font-weight: 700;
		font-size: 1.5rem;
		margin: 0 0 0.5rem;
		letter-spacing: -0.01em;
	}
	.empty p {
		color: var(--text-secondary);
		margin: 0 auto 1.5rem;
		font-size: 0.95rem;
		max-width: 48ch;
	}
	.btn-primary {
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
		padding: 0.6rem 1rem;
		background: var(--text-primary);
		color: var(--surface-card);
		border: 0;
		border-radius: var(--radius-lg);
		font-family: var(--forge-mono);
		font-size: 0.72rem;
		font-weight: 600;
		letter-spacing: 0.1em;
		text-transform: uppercase;
		text-decoration: none;
		cursor: pointer;
		transition: transform 150ms ease, box-shadow 150ms ease;
		box-shadow: 0 0 0 0 var(--glow);
	}
	.btn-primary:hover {
		transform: translateY(-1px);
		box-shadow: 0 0 0 4px var(--glow);
	}

	/* ── Table ─────────────────────────────────────── */
	.table-wrap {
		border: 1px solid var(--border-primary);
		border-radius: var(--radius-xl);
		background: var(--surface-card);
		overflow: hidden;
	}
	.t-right {
		text-align: right;
	}
	.row-link {
		display: inline-flex;
		align-items: baseline;
		gap: 0.6rem;
		color: var(--text-primary);
		text-decoration: none;
		transition: color 120ms ease;
	}
	.row-link:hover {
		color: var(--accent);
	}
	.row-link:focus-visible {
		outline: 2px solid var(--border-focus);
		outline-offset: 2px;
		border-radius: var(--radius-sm);
	}
	.row-ref {
		font-family: var(--forge-mono);
		font-size: 0.68rem;
		letter-spacing: 0.1em;
		color: var(--text-tertiary);
	}
	.row-name {
		font-weight: 600;
	}
	.row-action {
		font-family: var(--forge-mono);
		font-size: 0.68rem;
		font-weight: 600;
		letter-spacing: 0.1em;
		text-transform: uppercase;
		color: var(--accent);
		text-decoration: none;
	}
	.row-action:hover {
		color: var(--color-brand-700);
	}
	.row-action:focus-visible {
		outline: 2px solid var(--border-focus);
		outline-offset: 2px;
		border-radius: var(--radius-sm);
	}
	.row-action .arrow {
		display: inline-block;
		transition: transform 150ms ease;
	}
	.row-action:hover .arrow {
		transform: translateX(3px);
	}

	/* ── Source badges (themed via tokens) ─────────── */
	/* Light-theme defaults; dark overrides below pick up automatically. */
	.forge {
		--badge-image-color: var(--color-info);
		--badge-image-text: var(--color-info-dark);
		--badge-compose-color: var(--color-brand-500);
		--badge-compose-text: var(--color-brand-700);
		--badge-static-color: var(--color-success);
		--badge-static-text: var(--color-success-dark);
	}
	:global([data-theme='dark']) .forge {
		--badge-image-text: #93c5fd;
		--badge-compose-text: #c4b5fd;
		--badge-static-text: #6ee7b7;
	}

	.badge {
		display: inline-flex;
		align-items: center;
		gap: 0.35rem;
		padding: 0.18rem 0.55rem;
		border-radius: var(--radius-full);
		font-family: var(--forge-mono);
		font-size: 0.62rem;
		font-weight: 600;
		letter-spacing: 0.1em;
		text-transform: uppercase;
		border: 1px solid var(--border-primary);
	}
	.badge-dot {
		width: 6px;
		height: 6px;
		border-radius: 50%;
		background: currentColor;
	}
	.badge-image {
		background: color-mix(in srgb, var(--badge-image-color) 10%, transparent);
		color: var(--badge-image-text);
		border-color: color-mix(in srgb, var(--badge-image-color) 35%, transparent);
	}
	.badge-compose {
		background: color-mix(in srgb, var(--badge-compose-color) 10%, transparent);
		color: var(--badge-compose-text);
		border-color: color-mix(in srgb, var(--badge-compose-color) 35%, transparent);
	}
	.badge-static {
		background: color-mix(in srgb, var(--badge-static-color) 10%, transparent);
		color: var(--badge-static-text);
		border-color: color-mix(in srgb, var(--badge-static-color) 35%, transparent);
	}
	.badge-other {
		background: var(--surface-card-hover);
		color: var(--text-secondary);
	}
	.badge-trigger {
		background: var(--surface-card-hover);
		color: var(--text-secondary);
	}
	/* GitOps-managed chip — ember-tinted, sits beside the source badge. */
	.badge-gitops {
		margin-left: 0.35rem;
		background: var(--forge-accent-soft);
		color: var(--color-brand-700);
		border-color: color-mix(in srgb, var(--color-brand-500) 35%, transparent);
	}
	:global([data-theme='dark']) .badge-gitops {
		color: var(--color-brand-300);
	}

	.muted {
		color: var(--text-tertiary);
	}
	.mono {
		font-family: var(--forge-mono);
		font-size: 0.78rem;
	}
	.actions-cell {
		text-align: right;
	}
</style>
