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

	// Known kinds drive the kind-aware form switch in /new and the
	// filter chips here. Future kinds are tolerated: an unknown kind
	// renders with a generic label + grey badge instead of dropping
	// the row.
	const KNOWN_KINDS = ['registry', 'git', 'manual', 'schedule', 'webhook', 'logscan'] as const;
	type KnownKind = (typeof KNOWN_KINDS)[number];

	// Cache-backed (stale-while-revalidate) so revisiting this tab renders the
	// list immediately instead of flashing the cold skeleton. See caches.ts.
	const triggers = $derived<RedeployTrigger[]>($triggersCache.value);
	const loading = $derived($triggersCache.loading);
	const error = $derived($triggersCache.error);
	let kindFilter = $state<'all' | KnownKind | string>('all');

	const filtered = $derived(
		kindFilter === 'all' ? triggers : triggers.filter((t) => t.kind === kindFilter)
	);

	const withWebhook = $derived(triggers.filter((t) => t.webhook_enabled).length);
	const totalBindings = $derived(
		triggers.reduce((sum, t) => sum + (t.binding_count ?? 0), 0)
	);

	// Group triggers by kind for the hero stat rail. Caps to first
	// three kinds + a roll-up so the rail stays single-line on
	// narrow screens; the chip filter row exposes the full breakdown.
	const byKind = $derived.by(() => {
		const acc: Record<string, number> = {};
		for (const t of triggers) acc[t.kind] = (acc[t.kind] ?? 0) + 1;
		return acc;
	});

	const presentKinds = $derived(Object.keys(byKind));

	function kindLabel(k: string): string {
		const key = `redeployTriggers.kind.${k}`;
		const label = $t(key);
		return label === key ? k : label;
	}

	function kindShort(k: string): string {
		const key = `redeployTriggers.kindShort.${k}`;
		const label = $t(key);
		return label === key ? k.slice(0, 3).toUpperCase() : label;
	}

	function kindClass(k: string): string {
		// CSS-only kind colour. Falls through to the neutral
		// `kind-other` style for unknown kinds so the row still
		// renders cleanly.
		return KNOWN_KINDS.includes(k as KnownKind) ? `kind-${k}` : 'kind-other';
	}

	function fmtCreated(iso: string): string {
		try {
			return new Date(iso).toLocaleDateString(undefined, {
				year: 'numeric',
				month: 'short',
				day: '2-digit'
			});
		} catch {
			return iso;
		}
	}

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

	onMount(load);
</script>

<svelte:head>
	<title>{$t('redeployTriggers.title')} · Tinyforge</title>
</svelte:head>

<div class="forge" aria-busy={loading}>
	{#snippet toolbar()}
		<button
			class="forge-btn-icon"
			onclick={load}
			aria-label={$t('observability.refresh')}
			disabled={loading}
		>
			<IconRefresh size={16} />
		</button>
		<a href="/triggers/new" class="forge-btn">
			<IconPlus size={14} />
			<span>{$t('redeployTriggers.toolbar.newButton')}</span>
		</a>
	{/snippet}

	{#snippet stats()}
		<div>
			<dt>{$t('redeployTriggers.stat.total')}</dt>
			<dd>{loading ? '—' : String(triggers.length).padStart(2, '0')}</dd>
		</div>
		<div>
			<dt>{$t('redeployTriggers.stat.withWebhook')}</dt>
			<dd class="accent">{loading ? '—' : String(withWebhook).padStart(2, '0')}</dd>
		</div>
		<div>
			<dt>{$t('redeployTriggers.stat.boundWorkloads')}</dt>
			<dd>{loading ? '—' : String(totalBindings).padStart(2, '0')}</dd>
		</div>
	{/snippet}

	{#snippet lede()}
		{$t('redeployTriggers.lede')}
	{/snippet}

	<ForgeHero
		eyebrowSuffix={$t('redeployTriggers.section').toUpperCase()}
		title={$t('redeployTriggers.title')}
		size="lg"
		toolbar={toolbar}
		lede_html={lede}
		stats={stats}
	/>

	{#if error}
		<div class="alert" role="alert">
			<span class="alert-tag">ERR</span><span>{error}</span>
		</div>
	{/if}

	{#if !loading && triggers.length > 0}
		<!-- Kind filter chips. ALL is always present; per-kind chips are
		     rendered only for kinds present in the result set so the
		     row stays scannable when the operator only uses two kinds. -->
		<div class="filter-row" role="group" aria-label={$t('redeployTriggers.filter.ariaLabel')}>
			<button
				type="button"
				class="chip"
				class:active={kindFilter === 'all'}
				aria-pressed={kindFilter === 'all'}
				onclick={() => (kindFilter = 'all')}
			>
				<span class="chip-label">{$t('redeployTriggers.filter.all')}</span>
				<span class="chip-count">{String(triggers.length).padStart(2, '0')}</span>
			</button>
			{#each presentKinds as k}
				<button
					type="button"
					class="chip"
					class:active={kindFilter === k}
					aria-pressed={kindFilter === k}
					onclick={() => (kindFilter = k)}
				>
					<span class="chip-label">{kindLabel(k)}</span>
					<span class="chip-count">{String(byKind[k]).padStart(2, '0')}</span>
				</button>
			{/each}
		</div>
	{/if}

	{#if loading}
		<div class="skeleton-rows" aria-busy="true" aria-live="polite" aria-label={$t('observability.loading')}>
			{#each Array(3) as _, i}
				<div class="skeleton-row" style:--i={i}></div>
			{/each}
		</div>
	{:else if triggers.length === 0}
		<div class="empty">
			<div class="empty-mark" aria-hidden="true">
				<span></span><span></span><span></span>
			</div>
			<h2>{$t('redeployTriggers.empty.heading')}</h2>
			<p>{$t('redeployTriggers.empty.body')}</p>
			<a href="/triggers/new" class="forge-btn">
				<IconPlus size={14} /><span>{$t('redeployTriggers.empty.cta')}</span>
			</a>
		</div>
	{:else}
		<div class="table-wrap">
			<table class="forge-table">
				<thead>
					<tr>
						<th>{$t('redeployTriggers.list.name')}</th>
						<th>{$t('redeployTriggers.list.kind')}</th>
						<th>{$t('redeployTriggers.list.bindings')}</th>
						<th>{$t('redeployTriggers.list.webhook')}</th>
						<th class="hide-md">{$t('redeployTriggers.list.created')}</th>
						<th class="t-right">{$t('redeployTriggers.list.open')}</th>
					</tr>
				</thead>
				<tbody>
					{#each filtered as trig, i (trig.id)}
						<tr>
							<td>
								<a class="row-link" href={`/triggers/${trig.id}`}>
									<span class="row-ref">{String(i + 1).padStart(2, '0')}</span>
									<span class="row-name">{trig.name}</span>
								</a>
							</td>
							<td>
								<span class="badge kind {kindClass(trig.kind)}">
									<span class="kind-tag">{kindShort(trig.kind)}</span>
									<span class="kind-name">{kindLabel(trig.kind)}</span>
								</span>
							</td>
							<td>
								{#if trig.binding_count > 0}
									<span class="bindings-pill" title={String(trig.binding_count)}>
										<span class="bp-num">{trig.binding_count}</span>
										<span class="bp-bar" aria-hidden="true">
											{#each Array(Math.min(trig.binding_count, 6)) as _}
												<span></span>
											{/each}
										</span>
									</span>
								{:else}
									<span class="muted mono small">{$t('redeployTriggers.list.noBindings')}</span>
								{/if}
							</td>
							<td>
								<span class="status" class:on={trig.webhook_enabled} class:off={!trig.webhook_enabled}>
									<span class="status-dot" aria-hidden="true"></span>
									{trig.webhook_enabled
										? $t('redeployTriggers.list.webhookOn')
										: $t('redeployTriggers.list.webhookOff')}
								</span>
							</td>
							<td class="muted mono small hide-md">{fmtCreated(trig.created_at)}</td>
							<td class="actions-cell">
								<a class="row-action" href={`/triggers/${trig.id}`}>
									{$t('observability.open')} <span class="arrow" aria-hidden="true">→</span>
								</a>
							</td>
						</tr>
					{/each}
				</tbody>
			</table>
		</div>
	{/if}
</div>

<style>
	.forge {
		display: flex;
		flex-direction: column;
		gap: 1.25rem;
		max-width: 1100px;
		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: var(--surface-card);
		border-radius: var(--radius-sm);
	}
	:global([data-theme='dark']) .alert {
		background: color-mix(in srgb, var(--color-danger) 14%, transparent);
		color: color-mix(in srgb, var(--color-danger) 60%, var(--text-primary));
	}

	/* ── Filter chips ──────────────────────────────── */
	.filter-row {
		display: flex;
		flex-wrap: wrap;
		gap: 0.4rem;
	}
	.chip {
		display: inline-flex;
		align-items: center;
		gap: 0.4rem;
		padding: 0.35rem 0.75rem;
		background: var(--surface-card);
		border: 1px solid var(--border-primary);
		border-radius: var(--radius-full);
		cursor: pointer;
		color: var(--text-secondary);
		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-label {
		font-family: var(--forge-mono);
		font-size: 0.62rem;
		font-weight: 600;
		letter-spacing: 0.12em;
		text-transform: uppercase;
	}
	.chip-count {
		font-family: var(--forge-mono);
		font-size: 0.6rem;
		opacity: 0.7;
		font-variant-numeric: tabular-nums;
	}

	/* ── 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(--forge-accent);
		animation: ember 2.4s ease-in-out infinite;
	}
	@keyframes ember {
		0%,
		100% {
			box-shadow: 0 0 0 3px var(--forge-accent-soft);
		}
		50% {
			box-shadow: 0 0 0 6px color-mix(in srgb, var(--color-brand-500) 18%, transparent);
		}
	}
	.empty h2 {
		font-weight: 700;
		font-size: 1.5rem;
		margin: 0 0 0.5rem;
		letter-spacing: -0.01em;
		color: var(--text-primary);
	}
	.empty p {
		color: var(--text-secondary);
		margin: 0 auto 1.5rem;
		font-size: 0.95rem;
		max-width: 52ch;
		line-height: 1.5;
	}

	/* ── Table ─────────────────────────────────────── */
	.table-wrap {
		border: 1px solid var(--border-primary);
		border-radius: var(--radius-xl);
		background: var(--surface-card);
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
	}
	.table-wrap :global(.forge-table) {
		min-width: 720px;
	}
	.t-right {
		text-align: right;
	}
	.actions-cell {
		text-align: right;
	}
	@media (max-width: 820px) {
		.hide-md {
			display: none;
		}
	}

	/* ── Row link / action ─────────────────────────── */
	.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(--forge-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(--forge-accent);
		text-decoration: none;
	}
	.row-action:hover {
		color: var(--color-brand-500);
	}
	.arrow {
		display: inline-block;
		transition: transform 150ms ease;
	}
	.row-action:hover .arrow {
		transform: translateX(3px);
	}

	/* ── Kind badge ─────────────────────────────────
	   Two-segment pill: a tight monospace tag (REG, GIT…)
	   followed by the human-readable kind name. The tag
	   carries the colour so the eye can pick out the kind
	   even when the operator filters all rows down to two
	   kinds and the names line up.
	*/
	.badge.kind {
		display: inline-flex;
		align-items: stretch;
		overflow: hidden;
		border-radius: var(--radius-full);
		border: 1px solid var(--border-primary);
		font-family: var(--forge-mono);
		font-size: 0.62rem;
		font-weight: 600;
		letter-spacing: 0.1em;
		text-transform: uppercase;
		white-space: nowrap;
		background: var(--surface-card-hover);
		color: var(--text-secondary);
	}
	.kind-tag {
		display: inline-flex;
		align-items: center;
		padding: 0.18rem 0.5rem;
		font-weight: 700;
		letter-spacing: 0.16em;
		color: var(--surface-card);
		background: var(--text-primary);
	}
	.kind-name {
		display: inline-flex;
		align-items: center;
		padding: 0.18rem 0.55rem 0.18rem 0.5rem;
	}

	/* Per-kind colour. The pattern matches the rest of the app:
	   coloured tag + soft-tinted body that reads in both themes. */
	.badge.kind.kind-registry .kind-tag {
		background: var(--color-brand-600);
	}
	.badge.kind.kind-registry {
		background: color-mix(in srgb, var(--color-brand-500) 10%, transparent);
		border-color: color-mix(in srgb, var(--color-brand-500) 30%, transparent);
		color: var(--color-brand-600);
	}
	.badge.kind.kind-git .kind-tag {
		background: #6b46c1;
	}
	.badge.kind.kind-git {
		background: color-mix(in srgb, #8b5cf6 12%, transparent);
		border-color: color-mix(in srgb, #8b5cf6 32%, transparent);
		color: #6b46c1;
	}
	:global([data-theme='dark']) .badge.kind.kind-git {
		color: #c4b5fd;
	}
	.badge.kind.kind-manual .kind-tag {
		background: var(--text-secondary);
	}
	.badge.kind.kind-schedule .kind-tag {
		background: var(--color-warning, #f59e0b);
	}
	.badge.kind.kind-schedule {
		background: color-mix(in srgb, var(--color-warning, #f59e0b) 14%, transparent);
		border-color: color-mix(in srgb, var(--color-warning, #f59e0b) 35%, transparent);
		color: var(--color-warning-dark, #b45309);
	}
	.badge.kind.kind-webhook .kind-tag {
		background: var(--forge-accent);
	}
	.badge.kind.kind-webhook {
		background: var(--forge-accent-soft);
		border-color: color-mix(in srgb, var(--forge-accent) 35%, transparent);
		color: var(--forge-accent);
	}
	.badge.kind.kind-logscan .kind-tag {
		background: #0891b2;
	}
	.badge.kind.kind-logscan {
		background: color-mix(in srgb, #06b6d4 12%, transparent);
		border-color: color-mix(in srgb, #06b6d4 32%, transparent);
		color: #0e7490;
	}
	:global([data-theme='dark']) .badge.kind.kind-logscan {
		color: #67e8f9;
	}

	/* ── Bindings pill ──────────────────────────────
	   Number + miniature segmented bar that visually
	   communicates fan-out without taking a whole column.
	*/
	.bindings-pill {
		display: inline-flex;
		align-items: center;
		gap: 0.45rem;
		padding: 0.18rem 0.55rem;
		background: var(--surface-card-hover);
		border: 1px solid var(--border-primary);
		border-radius: var(--radius-full);
	}
	.bp-num {
		font-family: var(--forge-mono);
		font-size: 0.7rem;
		font-weight: 700;
		color: var(--text-primary);
		font-variant-numeric: tabular-nums;
	}
	.bp-bar {
		display: inline-flex;
		gap: 2px;
	}
	.bp-bar span {
		width: 4px;
		height: 10px;
		background: var(--forge-accent);
		border-radius: 1px;
		opacity: 0.85;
	}
	.bp-bar span:nth-child(2) { opacity: 0.7; }
	.bp-bar span:nth-child(3) { opacity: 0.6; }
	.bp-bar span:nth-child(4) { opacity: 0.5; }
	.bp-bar span:nth-child(5) { opacity: 0.4; }
	.bp-bar span:nth-child(6) { opacity: 0.3; }

	.small {
		font-size: 0.72rem;
	}

	/* ── Status (webhook on/off) ──────────────────── */
	.status {
		display: inline-flex;
		align-items: center;
		gap: 0.4rem;
		font-family: var(--forge-mono);
		font-size: 0.62rem;
		letter-spacing: 0.1em;
		font-weight: 600;
		text-transform: uppercase;
		white-space: nowrap;
	}
	.status-dot {
		width: 7px;
		height: 7px;
		border-radius: 50%;
	}
	.status.on {
		color: var(--color-success-dark);
	}
	.status.on .status-dot {
		background: var(--color-success);
		box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-success) 20%, transparent);
	}
	.status.off {
		color: var(--text-tertiary);
	}
	.status.off .status-dot {
		background: var(--text-tertiary);
		opacity: 0.5;
	}

	.muted {
		color: var(--text-tertiary);
	}
	.mono {
		font-family: var(--forge-mono);
	}
</style>
