<script lang="ts">
	import { t } from '$lib/i18n';
	import MdiIcon from '$lib/components/MdiIcon.svelte';
	import Button from '$lib/components/Button.svelte';
	import Hint from '$lib/components/Hint.svelte';

	type Tone = 'mint' | 'sky' | 'citrus' | 'coral';

	interface CacheBucketStats {
		count: number;
		total_size_bytes: number;
		oldest: string | null;
		newest: string | null;
	}
	interface CacheStats {
		url: CacheBucketStats;
		asset: CacheBucketStats;
	}

	interface Props {
		stats: CacheStats | null;
		clearing: boolean;
		maxEntries: number;
		onRefresh: () => void;
		onClear: () => void;
	}

	let { stats, clearing, maxEntries, onRefresh, onClear }: Props = $props();

	function formatBytes(bytes: number): string {
		if (!bytes) return '0 B';
		const units = ['B', 'KB', 'MB', 'GB'];
		let i = 0;
		let v = bytes;
		while (v >= 1024 && i < units.length - 1) { v /= 1024; i++; }
		return `${v.toFixed(v < 10 && i > 0 ? 1 : 0)} ${units[i]}`;
	}

	function parseDate(iso: string | null): Date | null {
		if (!iso) return null;
		const d = new Date(iso.endsWith('Z') || /[+-]\d{2}:?\d{2}$/.test(iso) ? iso : iso + 'Z');
		return isNaN(d.getTime()) ? null : d;
	}

	function relativeTime(iso: string | null): string {
		const date = parseDate(iso);
		if (!date) return '';
		const diffSec = Math.max(0, (Date.now() - date.getTime()) / 1000);
		if (diffSec < 60) return t('dashboard.justNow');
		const min = Math.floor(diffSec / 60);
		if (min < 60) return t('dashboard.minutesAgo').replace('{n}', String(min));
		const hr = Math.floor(min / 60);
		if (hr < 24) return t('dashboard.hoursAgo').replace('{n}', String(hr));
		const day = Math.floor(hr / 24);
		return t('dashboard.daysAgo').replace('{n}', String(day));
	}

	function ageTone(iso: string | null): Tone {
		const date = parseDate(iso);
		if (!date) return 'mint';
		const hours = (Date.now() - date.getTime()) / 3_600_000;
		if (hours < 48) return 'mint';
		if (hours < 24 * 7) return 'sky';
		if (hours < 24 * 30) return 'citrus';
		return 'coral';
	}

	interface BucketRow {
		key: 'url' | 'asset';
		labelKey: string;
		icon: string;
		data: CacheBucketStats | null;
	}

	const buckets = $derived<BucketRow[]>([
		{ key: 'url', labelKey: 'settings.cacheStatsUrl', icon: 'mdiLinkVariant', data: stats?.url ?? null },
		{ key: 'asset', labelKey: 'settings.cacheStatsAsset', icon: 'mdiImageMultipleOutline', data: stats?.asset ?? null },
	]);

	const totalCount = $derived(
		(stats?.url.count ?? 0) + (stats?.asset.count ?? 0),
	);
	const totalBytes = $derived(
		(stats?.url.total_size_bytes ?? 0) + (stats?.asset.total_size_bytes ?? 0),
	);
	const fillPct = $derived.by(() => {
		const max = Math.max(1, maxEntries);
		const each = totalCount / 2; // two buckets share the cap conceptually; use whichever is fuller
		const top = Math.max(stats?.url.count ?? 0, stats?.asset.count ?? 0);
		void each; // explicit ack we considered both
		return Math.min(100, Math.round((top / max) * 100));
	});
</script>

<section class="ledger glass">
	<header class="ledger-head">
		<div class="ledger-summary">
			<div class="ledger-eyebrow">
				<MdiIcon name="mdiDatabaseClockOutline" size={12} />
				<span>{t('settings.cacheStats')}</span>
			</div>
			<div class="ledger-numbers">
				<span class="ledger-count font-mono">{totalCount.toLocaleString()}</span>
				<span class="ledger-count-label">{t('settings.cacheStatsEntries')}</span>
				{#if totalBytes > 0}
					<span class="ledger-sep">·</span>
					<span class="ledger-bytes font-mono">{formatBytes(totalBytes)}</span>
					<Hint text={t('settings.cacheStatsHint')} />
				{/if}
			</div>
		</div>
		<div class="ledger-actions">
			<button
				type="button"
				class="icon-btn"
				onclick={onRefresh}
				aria-label={t('common.refresh', 'Refresh')}
				title={t('common.refresh', 'Refresh')}
			>
				<MdiIcon name="mdiRefresh" size={16} />
			</button>
		</div>
	</header>

	<!-- Capacity meter (peak bucket vs configured cap) -->
	{#if maxEntries > 0}
		<div class="meter" aria-label={t('settings.cacheCapacity')}>
			<div class="meter-track">
				<div class="meter-fill" style="width: {fillPct}%"></div>
			</div>
			<span class="meter-text font-mono">
				{fillPct}% · {t('settings.cacheCapacityCap').replace('{n}', maxEntries.toLocaleString())}
			</span>
		</div>
	{/if}

	<!-- Bucket rows -->
	<ol class="ledger-list">
		{#each buckets as bucket (bucket.key)}
			{@const data = bucket.data}
			{@const empty = !data || data.count === 0}
			{@const tone = empty ? 'mint' : ageTone(data?.oldest ?? null)}
			<li class="row" data-tone={tone} class:row-empty={empty}>
				<span class="row-edge" aria-hidden="true"></span>
				<span class="row-icon" aria-hidden="true">
					<MdiIcon name={bucket.icon} size={16} />
				</span>
				<div class="row-text">
					<span class="row-name">{t(bucket.labelKey)}</span>
					{#if empty}
						<span class="row-meta">{t('settings.cacheStatsEmpty')}</span>
					{:else if data}
						<span class="row-meta">
							<span>
								<span class="font-mono">{data.count.toLocaleString()}</span>
								{t('settings.cacheStatsEntries')}
							</span>
							{#if data.total_size_bytes > 0}
								<span class="row-sep">·</span>
								<span class="font-mono">{formatBytes(data.total_size_bytes)}</span>
							{/if}
							{#if data.oldest}
								<span class="row-sep">·</span>
								<span>{t('settings.cacheStatsOldest')} {relativeTime(data.oldest)}</span>
							{/if}
						</span>
					{/if}
				</div>
				<span class="row-dot" aria-hidden="true"></span>
			</li>
		{/each}
	</ol>

	<footer class="ledger-foot">
		<Button size="sm" variant="secondary" onclick={onClear} disabled={clearing || totalCount === 0}>
			{#if clearing}
				<MdiIcon name="mdiLoading" size={14} />
			{:else}
				<MdiIcon name="mdiDeleteSweep" size={14} />
			{/if}
			{clearing ? t('common.loading') : t('settings.clearCache')}
		</Button>
		<span class="foot-hint">{t('settings.clearCacheHint')}</span>
	</footer>
</section>

<style>
	.ledger {
		padding: 1.4rem 1.5rem 1.25rem;
		display: flex;
		flex-direction: column;
		gap: 1rem;
		min-height: 100%;
	}
	.ledger-head {
		position: relative;
		z-index: 1;
		display: flex;
		align-items: flex-end;
		justify-content: space-between;
		gap: 1rem;
		flex-wrap: wrap;
	}
	.ledger-summary { min-width: 0; }
	.ledger-eyebrow {
		display: inline-flex;
		align-items: center;
		gap: 0.35rem;
		font-family: var(--font-mono);
		font-size: 0.6rem;
		text-transform: uppercase;
		letter-spacing: 0.18em;
		color: var(--color-muted-foreground);
		margin-bottom: 0.4rem;
	}
	.ledger-numbers {
		display: flex;
		align-items: baseline;
		gap: 0.45rem;
		line-height: 1;
		flex-wrap: wrap;
	}
	.ledger-count {
		font-size: 1.7rem;
		font-weight: 500;
		letter-spacing: -0.025em;
		color: var(--color-foreground);
		font-variant-numeric: tabular-nums;
	}
	.ledger-count-label {
		font-size: 0.62rem;
		text-transform: uppercase;
		letter-spacing: 0.16em;
		color: var(--color-muted-foreground);
	}
	.ledger-sep { color: var(--color-muted-foreground); opacity: 0.5; }
	.ledger-bytes {
		font-size: 0.78rem;
		color: var(--color-muted-foreground);
	}
	.ledger-actions {
		display: flex;
		align-items: center;
		gap: 0.4rem;
	}

	.icon-btn {
		width: 30px; height: 30px;
		display: inline-flex;
		align-items: center;
		justify-content: center;
		border-radius: 8px;
		background: transparent;
		border: 1px solid transparent;
		color: var(--color-muted-foreground);
		cursor: pointer;
		transition: background 0.15s, color 0.15s, border-color 0.15s;
	}
	.icon-btn:hover:not(:disabled) {
		background: var(--color-glass-strong);
		color: var(--color-foreground);
		border-color: var(--color-border);
	}

	/* --- Capacity meter --- */
	.meter {
		position: relative;
		z-index: 1;
		display: flex;
		align-items: center;
		gap: 0.65rem;
	}
	.meter-track {
		flex: 1;
		height: 6px;
		border-radius: 999px;
		background: var(--color-glass-strong);
		border: 1px solid var(--color-border);
		overflow: hidden;
		position: relative;
	}
	.meter-fill {
		height: 100%;
		background: linear-gradient(90deg, var(--color-mint), var(--color-sky));
		border-radius: inherit;
		transition: width 0.4s cubic-bezier(.2,.7,.2,1);
		box-shadow: 0 0 8px color-mix(in srgb, var(--color-sky) 40%, transparent);
	}
	.meter-text {
		font-size: 0.62rem;
		color: var(--color-muted-foreground);
		letter-spacing: 0.04em;
		white-space: nowrap;
	}

	/* --- Bucket rows --- */
	.ledger-list {
		position: relative;
		z-index: 1;
		list-style: none;
		padding: 0;
		margin: 0;
		display: flex;
		flex-direction: column;
		gap: 0.4rem;
	}
	.row {
		position: relative;
		display: grid;
		grid-template-columns: auto 1fr auto;
		align-items: center;
		gap: 0.85rem;
		padding: 0.7rem 0.95rem 0.7rem 1.1rem;
		border-radius: 14px;
		border: 1px solid var(--color-border);
		background: var(--color-glass-strong);
		transition: transform 0.18s, border-color 0.18s, background 0.18s;
		overflow: hidden;
	}
	.row:hover {
		transform: translateY(-1px);
		border-color: var(--color-rule-strong);
		background: var(--color-glass-elev);
	}
	.row.row-empty { opacity: 0.78; }

	.row-edge {
		position: absolute;
		left: 0; top: 0; bottom: 0;
		width: 3px;
		opacity: 0.85;
	}
	.row[data-tone="mint"] .row-edge   { background: var(--color-mint); }
	.row[data-tone="sky"] .row-edge    { background: var(--color-sky); }
	.row[data-tone="citrus"] .row-edge { background: var(--color-citrus); }
	.row[data-tone="coral"] .row-edge  { background: var(--color-coral); }

	.row-icon {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		width: 30px; height: 30px;
		border-radius: 9px;
		background: var(--color-glass);
		color: var(--color-foreground);
	}
	.row[data-tone="mint"] .row-icon   { color: var(--color-mint); }
	.row[data-tone="sky"] .row-icon    { color: var(--color-sky); }
	.row[data-tone="citrus"] .row-icon { color: var(--color-citrus); }
	.row[data-tone="coral"] .row-icon  { color: var(--color-coral); }

	.row-text {
		display: flex;
		flex-direction: column;
		gap: 0.15rem;
		min-width: 0;
	}
	.row-name {
		font-size: 0.85rem;
		font-weight: 500;
		color: var(--color-foreground);
		letter-spacing: -0.005em;
	}
	.row-meta {
		font-size: 0.7rem;
		color: var(--color-muted-foreground);
		display: inline-flex;
		flex-wrap: wrap;
		gap: 0.35rem;
	}
	.row-sep { opacity: 0.45; }

	.row-dot {
		width: 8px; height: 8px;
		border-radius: 50%;
		flex-shrink: 0;
	}
	.row[data-tone="mint"] .row-dot   { background: var(--color-mint); box-shadow: 0 0 8px color-mix(in srgb, var(--color-mint) 50%, transparent); }
	.row[data-tone="sky"] .row-dot    { background: var(--color-sky); box-shadow: 0 0 8px color-mix(in srgb, var(--color-sky) 50%, transparent); }
	.row[data-tone="citrus"] .row-dot { background: var(--color-citrus); box-shadow: 0 0 8px color-mix(in srgb, var(--color-citrus) 50%, transparent); }
	.row[data-tone="coral"] .row-dot  { background: var(--color-coral); box-shadow: 0 0 8px color-mix(in srgb, var(--color-coral) 50%, transparent); }

	/* --- Footer --- */
	.ledger-foot {
		position: relative;
		z-index: 1;
		display: flex;
		align-items: center;
		gap: 0.85rem;
		flex-wrap: wrap;
		padding-top: 0.4rem;
		margin-top: auto;
	}
	.foot-hint {
		font-size: 0.7rem;
		color: var(--color-muted-foreground);
		flex: 1;
		min-width: 12rem;
		line-height: 1.4;
	}

	@media (prefers-reduced-motion: reduce) {
		.row, .meter-fill { transition: none !important; }
		.row:hover { transform: none !important; }
	}
</style>
