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

	// Cache-backed (stale-while-revalidate) so revisiting this tab renders the
	// list immediately instead of flashing the cold skeleton. Apps are loaded
	// alongside secrets (non-fatal) to resolve app-scoped row names. See caches.ts.
	const secrets = $derived<SharedSecret[]>($sharedSecretsCache.value.secrets);
	const apps = $derived($sharedSecretsCache.value.apps);
	const loading = $derived($sharedSecretsCache.loading);
	const error = $derived($sharedSecretsCache.error);
	let filter = $state<'all' | 'global' | 'app'>('all');

	const globals = $derived(secrets.filter((s) => s.scope === 'global'));
	const appScoped = $derived(secrets.filter((s) => s.scope === 'app'));
	const enabledCount = $derived(secrets.filter((s) => s.enabled).length);

	// app id → name lookup so app-scoped rows render the human label
	// instead of the raw uuid. A missing app falls back to a truncated
	// id (the app may have been deleted out from under the secret).
	const appNames = $derived.by(() => {
		const m = new Map<string, string>();
		for (const a of apps) m.set(a.id, a.name);
		return m;
	});

	const filtered = $derived.by(() => {
		switch (filter) {
			case 'global':
				return globals;
			case 'app':
				return appScoped;
			default:
				return secrets;
		}
	});

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

	function scopeLabel(s: SharedSecret): string {
		if (s.scope === 'app') {
			const label = appNames.get(s.app_id) || s.app_id.slice(0, 8);
			return $t('sharedsecrets.scope.app', { name: label });
		}
		return $t('sharedsecrets.scope.global');
	}

	function scopeClass(s: SharedSecret): string {
		return s.scope === 'app' ? 'scope-app' : 'scope-global';
	}

	onMount(load);
</script>

<svelte:head>
	<title>{$t('sharedsecrets.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="/shared-secrets/new" class="forge-btn">
			<IconPlus size={14} />
			<span>{$t('sharedsecrets.toolbar.newButton')}</span>
		</a>
	{/snippet}

	{#snippet stats()}
		<div>
			<dt>{$t('sharedsecrets.stat.total')}</dt>
			<dd>{loading ? '—' : String(secrets.length).padStart(2, '0')}</dd>
		</div>
		<div>
			<dt>{$t('sharedsecrets.stat.global')}</dt>
			<dd>{loading ? '—' : String(globals.length).padStart(2, '0')}</dd>
		</div>
		<div>
			<dt>{$t('sharedsecrets.stat.app')}</dt>
			<dd>{loading ? '—' : String(appScoped.length).padStart(2, '0')}</dd>
		</div>
		<div>
			<dt>{$t('sharedsecrets.stat.enabled')}</dt>
			<dd class="accent">{loading ? '—' : String(enabledCount).padStart(2, '0')}</dd>
		</div>
	{/snippet}

	{#snippet lede()}
		{$t('sharedsecrets.lede', { enabled: String(enabledCount), total: String(secrets.length) })}
	{/snippet}

	<ForgeHero
		eyebrowSuffix={$t('sharedsecrets.eyebrow').toUpperCase()}
		title={$t('sharedsecrets.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 && secrets.length > 0}
		<div class="filter-row" role="group" aria-label={$t('sharedsecrets.list.scope')}>
			{#each [['all', $t('sharedsecrets.filter.all'), secrets.length], ['global', $t('sharedsecrets.filter.global'), globals.length], ['app', $t('sharedsecrets.filter.app'), appScoped.length]] as [key, label, count]}
				<button
					type="button"
					class="chip"
					class:active={filter === key}
					aria-pressed={filter === key}
					onclick={() => (filter = key as typeof filter)}
				>
					<span class="chip-label">{label}</span>
					<span class="chip-count">{String(count).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(4) as _, i}
				<div class="skeleton-row" style:--i={i}></div>
			{/each}
		</div>
	{:else if secrets.length === 0}
		<div class="empty">
			<div class="empty-mark" aria-hidden="true">
				<span></span><span></span><span></span>
			</div>
			<h2>{$t('sharedsecrets.empty.heading')}</h2>
			<p>{$t('sharedsecrets.empty.body')}</p>
			<a href="/shared-secrets/new" class="forge-btn">
				<IconPlus size={14} /><span>{$t('sharedsecrets.empty.cta')}</span>
			</a>
		</div>
	{:else}
		<div class="table-wrap">
			<table class="forge-table">
				<thead>
					<tr>
						<th>{$t('sharedsecrets.list.name')}</th>
						<th>{$t('sharedsecrets.list.scope')}</th>
						<th>{$t('sharedsecrets.list.value')}</th>
						<th>{$t('sharedsecrets.list.encrypted')}</th>
						<th>{$t('sharedsecrets.list.status')}</th>
						<th class="t-right">{$t('sharedsecrets.list.open')}</th>
					</tr>
				</thead>
				<tbody>
					{#each filtered as s, i (s.id)}
						<tr>
							<td>
								<a class="row-link" href={`/shared-secrets/${s.id}`}>
									<span class="row-ref">{String(i + 1).padStart(2, '0')}</span>
									<span class="row-name mono">{s.name}</span>
								</a>
							</td>
							<td>
								<span class="badge {scopeClass(s)}">{scopeLabel(s)}</span>
							</td>
							<td>
								{#if s.has_value}
									<span class="value-state set">{$t('sharedsecrets.list.valueSet')}</span>
								{:else}
									<span class="value-state none">{$t('sharedsecrets.list.valueNone')}</span>
								{/if}
							</td>
							<td>
								{#if s.encrypted}
									<span class="enc-pill on">{$t('sharedsecrets.list.encOn')}</span>
								{:else}
									<span class="enc-pill off">{$t('sharedsecrets.list.encOff')}</span>
								{/if}
							</td>
							<td>
								<span class="status" class:on={s.enabled} class:off={!s.enabled}>
									<span class="status-dot" aria-hidden="true"></span>
									{s.enabled ? $t('sharedsecrets.status.enabled') : $t('sharedsecrets.status.disabled')}
								</span>
							</td>
							<td class="actions-cell">
								<a class="row-action" href={`/shared-secrets/${s.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: 1200px;
		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;
	}
	.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;
	}

	/* ── 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);
	}
	.row-action:focus-visible {
		outline: 2px solid var(--border-focus);
		outline-offset: 2px;
		border-radius: var(--radius-sm);
	}
	.arrow {
		display: inline-block;
		transition: transform 150ms ease;
	}
	.row-action:hover .arrow {
		transform: translateX(3px);
	}
	.actions-cell {
		text-align: right;
	}

	/* ── Badges ────────────────────────────────────── */
	.badge {
		display: inline-flex;
		align-items: center;
		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);
		white-space: nowrap;
	}
	.badge.scope-global {
		background: var(--surface-card-hover);
		color: var(--text-secondary);
	}
	.badge.scope-app {
		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);
	}

	/* ── Value state ───────────────────────────────── */
	.value-state {
		display: inline-flex;
		align-items: center;
		font-family: var(--forge-mono);
		font-size: 0.62rem;
		font-weight: 700;
		letter-spacing: 0.14em;
		text-transform: uppercase;
	}
	.value-state.set {
		color: var(--color-success-dark);
	}
	.value-state.none {
		color: var(--text-tertiary);
	}

	/* ── Encrypted pill ────────────────────────────── */
	.enc-pill {
		display: inline-flex;
		align-items: center;
		padding: 0.15rem 0.5rem;
		border-radius: var(--radius-full);
		border: 1px solid var(--border-primary);
		font-family: var(--forge-mono);
		font-size: 0.62rem;
		font-weight: 700;
		letter-spacing: 0.14em;
		text-transform: uppercase;
		white-space: nowrap;
	}
	.enc-pill.on {
		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);
	}
	.enc-pill.off {
		background: var(--surface-card-hover);
		color: var(--text-tertiary);
	}

	/* ── Status ────────────────────────────────────── */
	.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;
	}

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