<script lang="ts">
	import { onMount } from 'svelte';
	import type { LogScanRule } from '$lib/api';
	import { logScanCache } 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. See caches.ts.
	// Scanner stats are loaded alongside the rule list (non-fatal) so the
	// operator sees drop counters + compile errors next to the rules causing
	// them. Named `scanStats` to avoid colliding with the `{#snippet stats()}`
	// slot below that feeds the hero.
	const rules = $derived<LogScanRule[]>($logScanCache.value.rules);
	const scanStats = $derived($logScanCache.value.stats);
	const loading = $derived($logScanCache.loading);
	const error = $derived($logScanCache.error);
	let filter = $state<'all' | 'global' | 'workload' | 'override'>('all');

	const globals = $derived(rules.filter((r) => r.workload_id === '' && r.overrides_id === 0));
	const workloadOnly = $derived(
		rules.filter((r) => r.workload_id !== '' && r.overrides_id === 0)
	);
	const overrides = $derived(rules.filter((r) => r.overrides_id !== 0));
	const enabledCount = $derived(rules.filter((r) => r.enabled).length);

	const filtered = $derived.by(() => {
		switch (filter) {
			case 'global':
				return globals;
			case 'workload':
				return workloadOnly;
			case 'override':
				return overrides;
			default:
				return rules;
		}
	});

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

	function scopeLabel(r: LogScanRule): string {
		if (r.overrides_id !== 0) {
			return $t('logscan.scope.overrideShort', { id: String(r.overrides_id) });
		}
		if (r.workload_id !== '') {
			return $t('logscan.scope.workload', { id: r.workload_id.slice(0, 8) });
		}
		return $t('logscan.scope.global');
	}

	function scopeClass(r: LogScanRule): string {
		if (r.overrides_id !== 0) return 'scope-override';
		if (r.workload_id !== '') return 'scope-workload';
		return 'scope-global';
	}

	onMount(load);
</script>

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

	{#snippet stats()}
		<div>
			<dt>{$t('logscan.stat.total')}</dt>
			<dd>{loading ? '—' : String(rules.length).padStart(2, '0')}</dd>
		</div>
		<div>
			<dt>{$t('logscan.stat.global')}</dt>
			<dd>{loading ? '—' : String(globals.length).padStart(2, '0')}</dd>
		</div>
		<div>
			<dt>{$t('logscan.stat.workload')}</dt>
			<dd>{loading ? '—' : String(workloadOnly.length).padStart(2, '0')}</dd>
		</div>
		<div>
			<dt>{$t('logscan.stat.overrides')}</dt>
			<dd class="accent">{loading ? '—' : String(overrides.length).padStart(2, '0')}</dd>
		</div>
	{/snippet}

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

	<ForgeHero
		eyebrowSuffix={$t('observability.section').toUpperCase()}
		title={$t('logscan.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 && rules.length > 0}
		<div class="filter-row" role="group" aria-label={$t('logscan.list.scope')}>
			{#each [['all', $t('logscan.filter.all'), rules.length], ['global', $t('logscan.filter.global'), globals.length], ['workload', $t('logscan.filter.workload'), workloadOnly.length], ['override', $t('logscan.filter.overrides'), overrides.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 scanStats}
		<section class="stats-panel" aria-labelledby="stats-heading">
			<header class="stats-head">
				<h2 class="stats-title" id="stats-heading">
					{$t('logscan.stats.heading')}<span class="title-accent">.</span>
				</h2>
				<span class="stats-sub">{$t('logscan.stats.headingSub')}</span>
			</header>
			<dl class="stats-grid">
				<div class="stat-cell">
					<dt>{$t('logscan.stat.activeTails')}</dt>
					<dd>{String(scanStats.active_tails).padStart(2, '0')}</dd>
				</div>
				<div
					class="stat-cell"
					class:warn={scanStats.engine.dropped_by_bucket > 0}
				>
					<dt>{$t('logscan.stat.droppedBucket')}</dt>
					<dd>{scanStats.engine.dropped_by_bucket.toLocaleString()}</dd>
				</div>
				<div class="stat-cell">
					<dt>{$t('logscan.stat.droppedCooldown')}</dt>
					<dd>{scanStats.engine.dropped_by_cooldown.toLocaleString()}</dd>
				</div>
				<div
					class="stat-cell"
					class:bad={scanStats.last_compile_errors.length > 0}
				>
					<dt>{$t('logscan.stat.compileErrors')}</dt>
					<dd>{String(scanStats.last_compile_errors.length).padStart(2, '0')}</dd>
				</div>
			</dl>
			{#if scanStats.last_compile_errors.length > 0}
				<div class="compile-errors" role="alert">
					<span class="ce-heading">{$t('logscan.stats.compileErrorsHeading')}</span>
					<ul>
						{#each scanStats.last_compile_errors as msg}
							<li class="mono">{msg}</li>
						{/each}
					</ul>
				</div>
			{:else}
				<p class="hint stats-foot">{$t('logscan.stats.noCompileErrors')}</p>
			{/if}
		</section>
	{/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 rules.length === 0}
		<div class="empty">
			<div class="empty-mark" aria-hidden="true">
				<span></span><span></span><span></span>
			</div>
			<h2>{$t('logscan.empty.heading')}</h2>
			<p>{$t('logscan.empty.body')}</p>
			<a href="/log-scan-rules/new" class="forge-btn">
				<IconPlus size={14} /><span>{$t('logscan.empty.cta')}</span>
			</a>
		</div>
	{:else}
		<div class="table-wrap">
			<table class="forge-table">
				<thead>
					<tr>
						<th>{$t('logscan.list.name')}</th>
						<th>{$t('logscan.list.pattern')}</th>
						<th>{$t('logscan.list.scope')}</th>
						<th>{$t('logscan.list.severity')}</th>
						<th class="hide-md">{$t('logscan.list.streams')}</th>
						<th>{$t('logscan.list.status')}</th>
						<th class="t-right">{$t('logscan.list.open')}</th>
					</tr>
				</thead>
				<tbody>
					{#each filtered as r, i (r.id)}
						<tr>
							<td>
								<a class="row-link" href={`/log-scan-rules/${r.id}`}>
									<span class="row-ref">{String(i + 1).padStart(2, '0')}</span>
									<span class="row-name">{r.name}</span>
								</a>
							</td>
							<td class="muted mono small pattern">/{r.pattern}/</td>
							<td>
								<span class="badge {scopeClass(r)}">{scopeLabel(r)}</span>
							</td>
							<td>
								<span class="severity sev-{r.severity}">{r.severity}</span>
							</td>
							<td class="mono small muted hide-md">{r.streams}</td>
							<td>
								<span class="status" class:on={r.enabled} class:off={!r.enabled}>
									<span class="status-dot" aria-hidden="true"></span>
									{r.enabled ? $t('logscan.status.enabled') : $t('logscan.status.disabled')}
								</span>
							</td>
							<td class="actions-cell">
								<a class="row-action" href={`/log-scan-rules/${r.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;
	}
	.pattern {
		max-width: 360px;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}
	@media (max-width: 900px) {
		.pattern {
			max-width: 200px;
		}
		.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);
	}
	.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-workload {
		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.scope-override {
		background: color-mix(in srgb, var(--forge-accent) 12%, transparent);
		border-color: color-mix(in srgb, var(--forge-accent) 35%, transparent);
		color: var(--forge-accent);
	}

	/* ── Severity ──────────────────────────────────── */
	.severity {
		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;
	}
	.sev-info {
		background: color-mix(in srgb, var(--color-info, var(--text-tertiary)) 10%, transparent);
		border-color: color-mix(in srgb, var(--color-info, var(--text-tertiary)) 30%, transparent);
		color: var(--text-secondary);
	}
	.sev-warn {
		background: color-mix(in srgb, var(--color-warning, #f59e0b) 16%, transparent);
		border-color: color-mix(in srgb, var(--color-warning, #f59e0b) 35%, transparent);
		color: var(--color-warning-dark, #b45309);
	}
	.sev-error {
		background: var(--color-danger-light);
		border-color: color-mix(in srgb, var(--color-danger) 35%, transparent);
		color: var(--color-danger-dark);
	}
	:global([data-theme='dark']) .sev-error {
		background: color-mix(in srgb, var(--color-danger) 14%, transparent);
		color: color-mix(in srgb, var(--color-danger) 60%, var(--text-primary));
	}

	.small {
		font-size: 0.72rem;
	}

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

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

	/* ── Stats panel ────────────────────────────────────────
	   Drops a small four-cell counter row + compile-error list
	   between the hero/filter chips and the rules table.
	   Cells highlight when their counter is non-zero so the
	   operator notices a noisy regex without having to read
	   the number itself. */
	.stats-panel {
		display: flex;
		flex-direction: column;
		gap: 0.8rem;
		padding: 1rem 1.1rem;
		background: var(--surface-card);
		border: 1px solid var(--border-primary);
		border-radius: var(--radius-lg);
	}
	.stats-head {
		display: flex;
		flex-direction: column;
		gap: 0.2rem;
	}
	.stats-title {
		margin: 0;
		font-size: 0.95rem;
	}
	.title-accent {
		color: var(--forge-accent);
	}
	.stats-sub {
		font-family: var(--forge-mono);
		font-size: 0.7rem;
		color: var(--text-tertiary);
	}
	.stats-grid {
		display: grid;
		grid-template-columns: repeat(4, minmax(0, 1fr));
		gap: 0.55rem;
		margin: 0;
	}
	@media (max-width: 640px) {
		.stats-grid {
			grid-template-columns: repeat(2, minmax(0, 1fr));
		}
	}
	.stat-cell {
		display: flex;
		flex-direction: column;
		gap: 0.2rem;
		padding: 0.55rem 0.7rem;
		background: var(--surface-card-hover);
		border: 1px solid var(--border-primary);
		border-radius: var(--radius-md);
	}
	.stat-cell.warn {
		background: color-mix(in srgb, var(--color-warning, #f59e0b) 12%, transparent);
		border-color: color-mix(in srgb, var(--color-warning, #f59e0b) 40%, var(--border-primary));
	}
	.stat-cell.bad {
		background: color-mix(in srgb, var(--color-danger) 12%, transparent);
		border-color: color-mix(in srgb, var(--color-danger) 40%, var(--border-primary));
	}
	.stat-cell dt {
		font-family: var(--forge-mono);
		font-size: 0.6rem;
		font-weight: 700;
		letter-spacing: 0.14em;
		color: var(--text-secondary);
		margin: 0;
	}
	.stat-cell dd {
		font-family: var(--forge-mono);
		font-size: 1.2rem;
		font-weight: 700;
		color: var(--text-primary);
		margin: 0;
	}
	.compile-errors {
		padding: 0.55rem 0.75rem;
		background: var(--color-danger-light);
		color: var(--color-danger-dark);
		border: 1px solid var(--color-danger);
		border-radius: var(--radius-md);
	}
	.compile-errors .ce-heading {
		display: block;
		font-family: var(--forge-mono);
		font-size: 0.65rem;
		font-weight: 700;
		letter-spacing: 0.14em;
		text-transform: uppercase;
		margin-bottom: 0.4rem;
	}
	.compile-errors ul {
		margin: 0;
		padding-left: 1.1rem;
		font-size: 0.8rem;
		line-height: 1.5;
	}
	.stats-foot {
		margin: 0;
		font-size: 0.78rem;
		color: var(--text-tertiary);
	}
</style>
