<script lang="ts">
	import { base } from '$app/paths';
	import { page } from '$app/state';
	import { api, ApiError, type App, type FileMeta } from '$lib/api';
	import ConfirmModal from '$lib/ConfirmModal.svelte';

	let slug = $derived(page.params.slug ?? '');
	let app = $state<App | null>(null);
	let collection = $state('');
	let activeCollection = $state('');
	let files = $state<FileMeta[]>([]);
	let nextCursor = $state<string | null>(null);
	let loading = $state(false);
	let error = $state<string | null>(null);
	let fileToRemove = $state<FileMeta | null>(null);
	let removing = $state(false);

	async function loadApp() {
		try {
			app = await api.apps.get(slug);
		} catch (e) {
			error = e instanceof ApiError ? e.message : String(e);
		}
	}

	$effect(() => {
		void slug;
		void loadApp();
	});

	async function loadFiles(cursor?: string) {
		const c = collection.trim();
		if (!c) {
			error = 'Enter a collection name to list its files.';
			return;
		}
		loading = true;
		error = null;
		try {
			const res = await api.files.list(slug, c, { cursor, limit: 100 });
			if (cursor) {
				files = [...files, ...res.files];
			} else {
				files = res.files;
				activeCollection = c;
			}
			nextCursor = res.next_cursor;
		} catch (e) {
			error = e instanceof ApiError ? e.message : String(e);
		} finally {
			loading = false;
		}
	}

	async function confirmRemove() {
		if (!fileToRemove) return;
		removing = true;
		try {
			await api.files.remove(slug, fileToRemove.collection, fileToRemove.id);
			files = files.filter((f) => f.id !== fileToRemove!.id);
			fileToRemove = null;
		} catch (e) {
			error = e instanceof ApiError ? e.message : String(e);
		} finally {
			removing = false;
		}
	}

	function fmtTime(iso: string): string {
		return new Date(iso).toLocaleString();
	}

	function fmtSize(bytes: number): string {
		if (bytes < 1024) return `${bytes} B`;
		if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
		return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
	}
</script>

<svelte:head>
	<title>Files · {slug} · PiCloud</title>
</svelte:head>

<div class="container">
	<header>
		<div>
			<a href="{base}/apps/{slug}" class="back">&larr; back to {app?.name ?? slug}</a>
			<h1>Files</h1>
			<p class="subtitle">
				Browse and delete stored blobs by collection. Uploads happen from scripts via
				<code>files::collection(c).create(…)</code>.
			</p>
		</div>
	</header>

	<form
		class="collection-form"
		onsubmit={(e) => {
			e.preventDefault();
			void loadFiles();
		}}
	>
		<label>
			<span>Collection</span>
			<input bind:value={collection} placeholder="avatars" required />
		</label>
		<button type="submit" disabled={loading || !collection.trim()}>
			{loading ? 'Loading…' : 'List files'}
		</button>
	</form>

	{#if error}
		<div class="error">{error}</div>
	{/if}

	{#if activeCollection}
		{#if files.length === 0 && !loading}
			<p class="muted">No files in collection <code>{activeCollection}</code>.</p>
		{:else}
			<table>
				<thead>
					<tr>
						<th>Name</th>
						<th>Content type</th>
						<th>Size</th>
						<th>Created</th>
						<th>ID</th>
						<th></th>
					</tr>
				</thead>
				<tbody>
					{#each files as f (f.id)}
						<tr>
							<td>{f.name}</td>
							<td><code>{f.content_type}</code></td>
							<td>{fmtSize(f.size)}</td>
							<td>{fmtTime(f.created_at)}</td>
							<td class="mono small">{f.id}</td>
							<td>
								<button type="button" class="danger" onclick={() => (fileToRemove = f)}>
									Delete
								</button>
							</td>
						</tr>
					{/each}
				</tbody>
			</table>
			{#if nextCursor}
				<button type="button" class="secondary" onclick={() => loadFiles(nextCursor ?? undefined)}>
					Load more
				</button>
			{/if}
		{/if}
	{/if}
</div>

{#if fileToRemove}
	<ConfirmModal
		title="Delete file"
		variant="danger"
		confirmLabel="Delete file"
		onConfirm={confirmRemove}
		onCancel={() => (fileToRemove = null)}
	>
		<p>
			Delete <strong>{fileToRemove.name}</strong> ({fmtSize(fileToRemove.size)}) from collection
			<code>{fileToRemove.collection}</code>? This removes both the metadata row and the bytes on
			disk and cannot be undone.
		</p>
		{#if removing}<p class="muted">Deleting…</p>{/if}
	</ConfirmModal>
{/if}

<style>
	.container {
		max-width: 60rem;
		margin: 0 auto;
		padding: 1.5rem;
	}
	header {
		margin-bottom: 1rem;
	}
	.back {
		font-size: 0.85rem;
	}
	.subtitle {
		color: var(--muted, #666);
		font-size: 0.9rem;
	}
	.collection-form {
		display: flex;
		align-items: flex-end;
		gap: 0.75rem;
		margin-bottom: 1rem;
	}
	.collection-form label {
		display: flex;
		flex-direction: column;
		gap: 0.25rem;
		font-size: 0.85rem;
	}
	table {
		width: 100%;
		border-collapse: collapse;
		font-size: 0.9rem;
	}
	th,
	td {
		text-align: left;
		padding: 0.4rem 0.6rem;
		border-bottom: 1px solid var(--border, #e2e2e2);
	}
	.mono {
		font-family: monospace;
	}
	.small {
		font-size: 0.78rem;
	}
	.muted {
		color: var(--muted, #666);
	}
	.error {
		color: #b00020;
		margin: 0.5rem 0;
	}
	button.danger {
		color: #b00020;
	}
</style>
