<script lang="ts">
	import { page } from '$app/stores';
	import type { FileEntry } from '$lib/types';
	import * as api from '$lib/api';
	import { toasts } from '$lib/stores/toast';
	import { t } from '$lib/i18n';
	import { IconLoader, IconChevronRight } from '$lib/components/icons';
	import Breadcrumb from '$lib/components/Breadcrumb.svelte';
	import Skeleton from '$lib/components/Skeleton.svelte';

	const projectId = $derived($page.params.id ?? '');
	const volId = $derived($page.params.volId ?? '');

	let entries = $state<FileEntry[]>([]);
	let currentPath = $state('');
	let loading = $state(true);
	let error = $state('');
	let uploading = $state(false);

	// Query params for instance/stage scoped volumes.
	const stage = $derived($page.url.searchParams.get('stage') ?? '');
	const tag = $derived($page.url.searchParams.get('tag') ?? '');

	const breadcrumbs = $derived(() => {
		if (!currentPath) return [];
		return currentPath.split('/').filter(Boolean);
	});

	function fileIcon(entry: FileEntry): string {
		if (entry.is_dir) return '📁';
		const ext = entry.name.split('.').pop()?.toLowerCase() ?? '';
		const icons: Record<string, string> = {
			jpg: '🖼️', jpeg: '🖼️', png: '🖼️', gif: '🖼️', svg: '🖼️', webp: '🖼️',
			txt: '📄', md: '📄', log: '📄', csv: '📄',
			json: '📋', yaml: '📋', yml: '📋', toml: '📋', xml: '📋',
			js: '📜', ts: '📜', go: '📜', py: '📜', rs: '📜', sh: '📜',
			zip: '📦', tar: '📦', gz: '📦', rar: '📦',
			db: '🗄️', sqlite: '🗄️', sql: '🗄️',
		};
		return icons[ext] ?? '📄';
	}

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

	function formatDate(iso: string): string {
		if (!iso) return '—';
		const d = new Date(iso);
		return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit' });
	}

	async function loadDir(path: string) {
		loading = true;
		error = '';
		try {
			const result = await api.browseVolume(projectId, volId, { path, stage, tag });
			entries = result.entries;
			currentPath = result.path || '';
		} catch (e) {
			error = e instanceof Error ? e.message : $t('volumeBrowser.loadFailed');
		} finally {
			loading = false;
		}
	}

	function navigateTo(path: string) {
		loadDir(path);
	}

	function navigateToBreadcrumb(index: number) {
		const parts = currentPath.split('/').filter(Boolean);
		const path = parts.slice(0, index + 1).join('/');
		navigateTo(path);
	}

	function handleEntryClick(entry: FileEntry) {
		if (entry.is_dir) {
			const newPath = currentPath ? `${currentPath}/${entry.name}` : entry.name;
			navigateTo(newPath);
		} else {
			// Download single file.
			const filePath = currentPath ? `${currentPath}/${entry.name}` : entry.name;
			window.open(api.volumeDownloadUrl(projectId, volId, { path: filePath, stage, tag }), '_blank');
		}
	}

	function downloadCurrent() {
		window.open(api.volumeDownloadUrl(projectId, volId, { path: currentPath, stage, tag }), '_blank');
	}

	let fileInput: HTMLInputElement;

	async function handleUpload() {
		if (!fileInput.files?.length) return;
		uploading = true;
		try {
			const result = await api.uploadToVolume(projectId, volId, fileInput.files, { path: currentPath, stage, tag });
			toasts.success(`${$t('volumeBrowser.uploaded')} ${result.count} ${$t('volumeBrowser.files')}`);
			fileInput.value = '';
			await loadDir(currentPath);
		} catch (e) {
			toasts.error(e instanceof Error ? e.message : $t('volumeBrowser.uploadFailed'));
		} finally {
			uploading = false;
		}
	}

	$effect(() => {
		void projectId;
		void volId;
		loadDir('');
	});
</script>

<svelte:head>
	<title>{$t('volumeBrowser.title')} - {$t('app.name')}</title>
</svelte:head>

<div class="space-y-4">
	<!-- Header -->
	<div>
		<Breadcrumb items={[
			{ label: $t('common.project'), href: `/projects/${projectId}` },
			{ label: $t('volumeEditor.title'), href: `/projects/${projectId}/volumes` }
		]} />
		<div class="mt-1 flex items-center justify-between">
			<h1 class="text-2xl font-bold text-[var(--text-primary)]">{$t('volumeBrowser.title')}</h1>
			<div class="flex items-center gap-2">
				<button
					type="button"
					class="inline-flex items-center gap-1.5 rounded-lg border border-[var(--border-primary)] px-3 py-2 text-xs font-medium text-[var(--text-secondary)] hover:bg-[var(--surface-card-hover)] transition-colors"
					onclick={downloadCurrent}
				>
					📦 {currentPath ? $t('volumeBrowser.downloadFolder') : $t('volumeBrowser.downloadAll')}
				</button>
				<label
					class="inline-flex cursor-pointer items-center gap-1.5 rounded-lg bg-[var(--color-brand-600)] px-3 py-2 text-xs font-medium text-white hover:bg-[var(--color-brand-700)] transition-colors {uploading ? 'opacity-50 pointer-events-none' : ''}"
				>
					{#if uploading}
						<IconLoader size={14} class="animate-spin" />
					{/if}
					{$t('volumeBrowser.upload')}
					<input bind:this={fileInput} type="file" multiple class="hidden" onchange={handleUpload} />
				</label>
			</div>
		</div>
	</div>

	<!-- Breadcrumbs -->
	<nav class="flex items-center gap-1 text-sm">
		<button
			type="button"
			class="rounded px-1.5 py-0.5 text-[var(--text-link)] hover:bg-[var(--surface-card-hover)] transition-colors {currentPath === '' ? 'font-semibold' : ''}"
			onclick={() => navigateTo('')}
		>
			/
		</button>
		{#each breadcrumbs() as segment, i}
			<IconChevronRight size={12} class="text-[var(--text-tertiary)]" />
			<button
				type="button"
				class="rounded px-1.5 py-0.5 text-[var(--text-link)] hover:bg-[var(--surface-card-hover)] transition-colors {i === breadcrumbs().length - 1 ? 'font-semibold text-[var(--text-primary)]' : ''}"
				onclick={() => navigateToBreadcrumb(i)}
			>
				{segment}
			</button>
		{/each}
	</nav>

	{#if loading}
		<Skeleton height="16rem" />
	{:else if error}
		<div class="rounded-xl border border-[var(--color-danger-light)] bg-[var(--color-danger-light)] p-4">
			<p class="text-sm text-[var(--color-danger)]">{error}</p>
			<button type="button" class="mt-2 text-sm font-medium text-[var(--color-danger)] underline hover:no-underline" onclick={() => loadDir(currentPath)}>
				{$t('common.retry')}
			</button>
		</div>
	{:else if entries.length === 0}
		<div class="rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] p-8 text-center">
			<p class="text-sm text-[var(--text-tertiary)]">{$t('volumeBrowser.empty')}</p>
		</div>
	{:else}
		<div class="overflow-hidden rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] shadow-[var(--shadow-sm)]">
			<table class="min-w-full divide-y divide-[var(--border-primary)]">
				<thead class="bg-[var(--surface-card-hover)]">
					<tr>
						<th class="px-4 py-2.5 text-left text-xs font-medium text-[var(--text-tertiary)] uppercase">{$t('volumeBrowser.name')}</th>
						<th class="px-4 py-2.5 text-right text-xs font-medium text-[var(--text-tertiary)] uppercase">{$t('volumeBrowser.size')}</th>
						<th class="px-4 py-2.5 text-right text-xs font-medium text-[var(--text-tertiary)] uppercase">{$t('volumeBrowser.modified')}</th>
					</tr>
				</thead>
				<tbody class="divide-y divide-[var(--border-secondary)]">
					{#if currentPath}
						<tr class="hover:bg-[var(--surface-card-hover)] cursor-pointer transition-colors" onclick={() => {
							const parts = currentPath.split('/').filter(Boolean);
							parts.pop();
							navigateTo(parts.join('/'));
						}}>
							<td class="px-4 py-2 text-sm text-[var(--text-link)]">
								<span class="mr-2">📁</span>..
							</td>
							<td></td>
							<td></td>
						</tr>
					{/if}
					{#each entries.sort((a, b) => {
						if (a.is_dir !== b.is_dir) return a.is_dir ? -1 : 1;
						return a.name.localeCompare(b.name);
					}) as entry (entry.name)}
						<tr
							class="hover:bg-[var(--surface-card-hover)] transition-colors {entry.is_dir ? 'cursor-pointer' : ''}"
							onclick={() => handleEntryClick(entry)}
						>
							<td class="px-4 py-2 text-sm text-[var(--text-primary)]">
								<span class="mr-2">{fileIcon(entry)}</span>
								{#if entry.is_dir}
									<span class="text-[var(--text-link)]">{entry.name}</span>
								{:else}
									{entry.name}
								{/if}
							</td>
							<td class="px-4 py-2 text-right text-xs text-[var(--text-secondary)] tabular-nums">
								{entry.is_dir ? '—' : formatSize(entry.size)}
							</td>
							<td class="px-4 py-2 text-right text-xs text-[var(--text-tertiary)]">
								{formatDate(entry.mod_time)}
							</td>
						</tr>
					{/each}
				</tbody>
			</table>
		</div>
	{/if}
</div>
