<script lang="ts">
	import * as Dialog from '$lib/components/ui/dialog/index.js';
	import * as Field from '$lib/components/ui/field/index.js';
	import { Button } from '$lib/components/ui/button';
	import * as NativeSelect from '$lib/components/ui/native-select/index.js';
	import {
		displaySize,
		FileDropZone,
		type FileDropZoneProps
	} from '$lib/components/ui/file-drop-zone';
	import { X } from '@lucide/svelte';
	import { toast } from 'svelte-sonner';

	import { Switch } from '$lib/components/ui/switch/index';

	import { tick } from 'svelte';
	import { Spinner } from '$lib/components/ui/spinner/index';
	import { getLibraryState } from '$lib/state/library.svelte';
	import { uploadBooks } from '$lib/api';
	import type { Book, PaginatedResponse } from '$lib/schema';
	import { goto } from '$app/navigation';

	let { open = $bindable() }: { open?: boolean } = $props();

	let libraryState = getLibraryState();

	$effect(() => {
		uploadBooks.fields.library_id.set(libraryState.activeLibrary!.id);
	});

	let files = $derived(uploadBooks.fields.files.value() ?? []);

	let autoUploadOnDrop = $state(true);
	let navigateOnUpload = $state(true);
	let formEl = $state<HTMLFormElement>();

	const onUpload: FileDropZoneProps['onUpload'] = async (uploadedFiles) => {
		uploadBooks.fields.files.set([...Array.from(files), ...uploadedFiles]);
		if (autoUploadOnDrop && files.length > 0) {
			await tick();
			formEl?.requestSubmit();
		}
	};

	const onFileRejected: FileDropZoneProps['onFileRejected'] = async ({ reason, file }) => {
		toast.error(`${file.name} failed to upload!`, { description: reason });
	};

	function navigateToBooks(books: PaginatedResponse<Book>) {
		open = false;
		let libraryId = books.items[0].library_id;
		libraryState.setActive(libraryId);
		if (books.items.length === 1) {
			goto(`/book/${books.items[0].id}`);
		} else {
			goto(`/library/${libraryId}/view?orderBy=created_at&sortOrder=desc`);
		}
	}
</script>

<Dialog.Root bind:open>
	<Dialog.Content>
		{#if uploadBooks.pending}
			<div class="flex flex-col items-center gap-4">
				<span class="text-lg font-semibold"
					>Uploading {uploadBooks.fields.files.value().length} files...</span
				>
				<Spinner class="scale-150" />
			</div>
		{:else}
			<Dialog.Header>
				<Dialog.Title>Upload Books</Dialog.Title>
			</Dialog.Header>

			<form
				{...uploadBooks.enhance(async ({ submit, form }) => {
					try {
						await submit();

						// Check if there are any validation issues
						const issues = uploadBooks.fields.allIssues();
						if (issues && issues.length > 0) {
							return;
						}

						// Update library book count
						const count = uploadBooks.result.total
						libraryState.libraries.find(lib => uploadBooks.fields.library_id.value() == lib.id.toString())!.total += count

						// Reset the files field
						uploadBooks.fields.files.set([]);
						toast.success('Books successfully uploaded!');

						if (navigateOnUpload) {
							navigateToBooks(uploadBooks.result);
						}
					} catch (error) {
						console.error('Failed to upload book: ', error);
						toast.error('Failed to upload books');
					}
				})}
				bind:this={formEl}
				enctype="multipart/form-data"
				class="flex w-full flex-col gap-2 p-4"
			>
				<!-- Library select field  -->
				<Field.Label for="library_id">Select Library</Field.Label>
				<NativeSelect.Root {...uploadBooks.fields.library_id.as('select')} class="w-36">
					{#each libraryState.libraries as library}
						<NativeSelect.Option value={library.id}>
							{library.name}
						</NativeSelect.Option>
					{/each}
				</NativeSelect.Root>

				<FileDropZone
					{onUpload}
					{onFileRejected}
					directory={true}
					accept=".pdf,.epub,.mobi,application/pdf,application/epub+zip,application/x-mobipocket-ebook"
					sublabel="Only PDF, EPUB, and MOBI files supported"
				/>
				<input class="hidden" {...uploadBooks.fields.files.as('file multiple')} />
				<div class="flex max-h-[300px] flex-col gap-2 overflow-y-auto">
					{#each files as file, idx}
						<div class="flex place-items-center justify-between gap-2">
							<div class="flex flex-col">
								<span>{file.name}</span>
								<span class="text-xs text-muted-foreground">{displaySize(file.size)}</span>
							</div>
							<Button
								variant="outline"
								size="icon"
								onclick={() => {
									uploadBooks.fields.files.set([
										...Array.from(files).slice(0, idx),
										...Array.from(files).slice(idx + 1)
									]);
								}}
							>
								<X />
							</Button>
						</div>
					{/each}
				</div>

				<div class="flex flex-col gap-2">
					<div class="flex items-center gap-2">
						<Switch bind:checked={autoUploadOnDrop} />
						<Field.Label for="auto-upload-on-drop">Auto upload on file drop</Field.Label>
						<Button type="submit" class="ml-auto w-fit">Upload</Button>
					</div>
					<div class="flex items-center gap-2">
						<Switch bind:checked={navigateOnUpload} />
						<Field.Label for="navigate-to-book">Navigate to book on upload</Field.Label>
					</div>
				</div>
			</form>
		{/if}
	</Dialog.Content>
</Dialog.Root>
