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

	interface BackupFile {
		filename: string;
		size: number;
		created_at?: string | null;
	}

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

	interface Props {
		files: BackupFile[];
		loading: boolean;
		creating: boolean;
		onCreate: () => void;
		onRefresh: () => void;
		onDownload: (filename: string) => void;
		onDelete: (filename: string) => void;
	}

	let { files, loading, creating, onCreate, onRefresh, onDownload, onDelete }: Props = $props();

	function formatBytes(bytes: number): string {
		if (!bytes) return '0 B';
		if (bytes < 1024) return `${bytes} B`;
		if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
		return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
	}

	function parseDate(iso: string | null | undefined): 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 | undefined): 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 absoluteTime(iso: string | null | undefined): string {
		const date = parseDate(iso);
		return date ? date.toLocaleString() : '—';
	}

	function ageTone(iso: string | null | undefined): Tone {
		const date = parseDate(iso);
		if (!date) return 'coral';
		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';
	}

	const totalSize = $derived(files.reduce((sum, f) => sum + (f.size || 0), 0));
</script>

<section class="ledger glass">
	<header class="ledger-head">
		<div>
			<div class="ledger-eyebrow">
				<MdiIcon name="mdiArchiveOutline" size={12} />
				<span>{t('backup.savedFiles')}</span>
			</div>
			{#if files.length > 0}
				<div class="ledger-summary">
					<span class="ledger-count font-mono">{files.length}</span>
					<span class="ledger-count-label">{t('backup.countLabel')}</span>
					<span class="ledger-sep">·</span>
					<span class="ledger-total">{t('backup.totalSize').replace('{size}', formatBytes(totalSize))}</span>
				</div>
			{/if}
		</div>
		<div class="ledger-actions">
			<Button size="sm" variant="secondary" onclick={onCreate} disabled={creating}>
				{#if creating}
					<MdiIcon name="mdiLoading" size={14} />
				{:else}
					<MdiIcon name="mdiPlus" size={14} />
				{/if}
				{creating ? t('common.loading') : t('backup.createManual')}
			</Button>
			<button class="icon-btn" type="button" onclick={onRefresh} disabled={loading}
				aria-label={t('common.refresh', 'Refresh')} title={t('common.refresh', 'Refresh')}>
				<span class:spinning={loading}><MdiIcon name="mdiRefresh" size={16} /></span>
			</button>
		</div>
	</header>

	{#if files.length === 0}
		<div class="ledger-empty">
			<MdiIcon name="mdiCloudOffOutline" size={28} />
			<p>{t('backup.noFiles')}</p>
		</div>
	{:else}
		<ol class="ledger-list">
			{#each files as file (file.filename)}
				{@const tone = ageTone(file.created_at)}
				<li class="row" data-tone={tone}>
					<span class="row-edge" aria-hidden="true"></span>
					<span class="row-dot" aria-hidden="true"></span>
					<div class="row-time">
						<span class="row-rel">{relativeTime(file.created_at) || '—'}</span>
						<span class="row-abs" title={absoluteTime(file.created_at)}>
							{absoluteTime(file.created_at)}
						</span>
					</div>
					<div class="row-name">
						<span class="row-filename" title={file.filename}>{file.filename}</span>
					</div>
					<span class="row-size font-mono">{formatBytes(file.size)}</span>
					<div class="row-actions">
						<button class="icon-btn" type="button"
							onclick={() => onDownload(file.filename)}
							aria-label={t('backup.download')}
							title={t('backup.download')}>
							<MdiIcon name="mdiDownload" size={14} />
						</button>
						<button class="icon-btn icon-btn-danger" type="button"
							onclick={() => onDelete(file.filename)}
							aria-label={t('common.delete')}
							title={t('common.delete')}>
							<MdiIcon name="mdiTrashCanOutline" size={14} />
						</button>
					</div>
				</li>
			{/each}
		</ol>
	{/if}
</section>

<style>
	.ledger {
		padding: 1.4rem 1.5rem 1.25rem;
		display: flex;
		flex-direction: column;
		gap: 0.95rem;
	}
	.ledger-head {
		position: relative;
		z-index: 1;
		display: flex;
		align-items: flex-end;
		justify-content: space-between;
		gap: 1rem;
		flex-wrap: wrap;
	}
	.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.3rem;
	}
	.ledger-summary {
		display: flex;
		align-items: baseline;
		gap: 0.45rem;
		line-height: 1;
	}
	.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-total {
		font-size: 0.75rem;
		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);
	}
	.icon-btn:disabled { opacity: 0.5; cursor: default; }
	.icon-btn-danger:hover:not(:disabled) {
		color: var(--color-error-fg);
		border-color: color-mix(in srgb, var(--color-error-fg) 35%, var(--color-border));
		background: color-mix(in srgb, var(--color-error-fg) 8%, var(--color-glass-strong));
	}
	.spinning {
		display: inline-flex;
		animation: ledger-spin 1.1s linear infinite;
	}
	@keyframes ledger-spin {
		from { transform: rotate(0deg); }
		to { transform: rotate(360deg); }
	}

	.ledger-empty {
		position: relative;
		z-index: 1;
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: 0.5rem;
		padding: 1.6rem 1rem;
		color: var(--color-muted-foreground);
		text-align: center;
	}
	.ledger-empty p { margin: 0; font-size: 0.8rem; }

	.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 auto 1fr auto auto;
		align-items: center;
		gap: 0.7rem;
		padding: 0.55rem 0.75rem 0.55rem 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-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-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); }
	.row[data-tone="citrus"] .row-dot { background: var(--color-citrus); }
	.row[data-tone="coral"] .row-dot  { background: var(--color-coral); }

	.row-time {
		display: flex;
		flex-direction: column;
		gap: 0.05rem;
		min-width: 6.5rem;
	}
	.row-rel {
		font-size: 0.78rem;
		color: var(--color-foreground);
		font-weight: 500;
		letter-spacing: -0.005em;
	}
	.row-abs {
		font-family: var(--font-mono);
		font-size: 0.62rem;
		color: var(--color-muted-foreground);
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
		max-width: 14rem;
	}
	.row-name {
		min-width: 0;
	}
	.row-filename {
		display: block;
		font-family: var(--font-mono);
		font-size: 0.72rem;
		color: var(--color-muted-foreground);
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}
	.row:hover .row-filename { color: var(--color-foreground); }

	.row-size {
		font-size: 0.7rem;
		color: var(--color-muted-foreground);
		text-align: right;
		white-space: nowrap;
	}
	.row-actions {
		display: flex;
		gap: 0.15rem;
		opacity: 0;
		transition: opacity 0.18s;
	}
	.row:hover .row-actions,
	.row:focus-within .row-actions { opacity: 1; }
	@media (max-width: 640px) {
		.row { grid-template-columns: auto 1fr auto; row-gap: 0.25rem; }
		.row-time { grid-column: 2; min-width: 0; }
		.row-name { grid-column: 1 / -1; }
		.row-size { grid-column: 3; grid-row: 1; }
		.row-actions { grid-column: 1 / -1; opacity: 1; justify-content: flex-end; }
	}

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