<script lang="ts">
	import { buttonVariants } from '$lib/components/ui/button/button.svelte';
	import * as Tooltip from '$lib/components/ui/tooltip/index';
	import {
		BookOpenCheck,
		Download,
		GitMerge,
		Trash2,
		SquareCheckBig,
		X,
		Album,
		PlusIcon
	} from '@lucide/svelte';
	import * as DropdownMenu from '$lib/components/ui/dropdown-menu/index';
	import { getBookOperationsState } from '$lib/state/bookOperations.svelte';
	import { getBookSelectionState } from '$lib/state/bookSelection.svelte';
	import { getBookCollectionState } from '$lib/state/bookCollection.svelte';
	import { getLibraryState } from '$lib/state/library.svelte';
	import { getBookshelfState } from '$lib/state/bookshelf.svelte';
	import ShelfCreateDialog from '../forms/shelf-create-dialog.svelte';
	import MergeBooks from '../forms/merge-books/merge-books.svelte';
	import type { Book } from '$lib/schema';

	const libraryState = getLibraryState();
	const bookshelfState = getBookshelfState();
	const selectionState = getBookSelectionState();
	const bookOps = getBookOperationsState();
	const collectionState = getBookCollectionState();

	let selectedBooks = $derived(selectionState.getSelectedBooks());

	let createShelfDialogOpen = $state(false);

	// The books the merge dialog opened on. Snapshotted rather than read live from
	// the selection, so clearing the selection on success cannot empty the dialog
	// underneath itself.
	let mergingBooks = $state<Book[] | null>(null);
</script>

<!-- Mark selected as finished button -->
<Tooltip.Provider>
	<Tooltip.Root ignoreNonKeyboardFocus>
		<Tooltip.Trigger
			onclick={async () => {
				await bookOps.markBooksAsComplete(selectionState.getSelectedIds());
				selectionState.deselectAll();
			}}
			class={buttonVariants({ variant: 'ghost', size: 'icon' })}
		>
			<BookOpenCheck />
		</Tooltip.Trigger>
		<Tooltip.Content>
			<p>Mark as finished</p>
		</Tooltip.Content>
	</Tooltip.Root>
</Tooltip.Provider>

<!-- Add to shelf button -->
<Tooltip.Provider>
	<Tooltip.Root ignoreNonKeyboardFocus>
		<Tooltip.Trigger>
			{#snippet child({ props })}
				<DropdownMenu.Root>
					<DropdownMenu.Trigger
						{...props}
						class={buttonVariants({
							variant: 'ghost',
							size: 'icon'
						})}
					>
						<Album />
					</DropdownMenu.Trigger>
					<DropdownMenu.Content>
						<DropdownMenu.Group>
							<DropdownMenu.GroupHeading>Shelves</DropdownMenu.GroupHeading>
							{#each bookshelfState.getBookshelves(libraryState.activeLibrary!.id) ?? [] as shelf (shelf.id)}
								<DropdownMenu.CheckboxItem
									checked={selectedBooks.every(
										(book) => book.lists.findIndex((sh) => sh.id === shelf.id) !== -1
									)}
									onclick={async () => {
										// Check if all books are in the shelf
										const allBooksInShelf = selectedBooks.every((book) =>
											book.lists.find((sh) => sh.id === shelf.id)
										);

										if (allBooksInShelf) {
											// Remove all books from the shelf
											const bookIds = selectedBooks.map((book) => book.id);
											await bookshelfState.removeBooksFromShelf(shelf.id, bookIds);
											selectedBooks.forEach((book) => {
												book.lists = book.lists.filter((sh) => sh.id !== shelf.id);
											});
										} else {
											// Add all books to the shelf
											const bookIds = selectedBooks.map((book) => book.id);
											await bookshelfState.addBooksToShelf(shelf.id, bookIds);
											selectedBooks.forEach((book) => {
												if (!book.lists.find((sh) => sh.id === shelf.id)) {
													book.lists.push(shelf);
												}
											});
										}
										selectionState.deselectAll();
									}}
								>
									{shelf.title}
								</DropdownMenu.CheckboxItem>
							{/each}
						</DropdownMenu.Group>
						<DropdownMenu.Separator />
						<DropdownMenu.Item
							onclick={() => (createShelfDialogOpen = true)}
							class="text-muted-foreground "
						>
							<PlusIcon class="size-4" />
							New Shelf
						</DropdownMenu.Item>
					</DropdownMenu.Content>
				</DropdownMenu.Root>
			{/snippet}
		</Tooltip.Trigger>
		<Tooltip.Content side="bottom">
			<p>Add/Remove from shelf</p>
		</Tooltip.Content>
	</Tooltip.Root>
</Tooltip.Provider>

<!-- Download selected button -->
<Tooltip.Provider>
	<Tooltip.Root ignoreNonKeyboardFocus>
		<Tooltip.Trigger
			onclick={() => {
				bookOps.downloadBooks(selectionState.getSelectedIds());
			}}
			class={buttonVariants({ variant: 'ghost', size: 'icon' })}
		>
			<Download />
		</Tooltip.Trigger>
		<Tooltip.Content>
			<p>Download selected</p>
		</Tooltip.Content>
	</Tooltip.Root>
</Tooltip.Provider>

<!-- Merge selected button. Two books is the smallest thing a merge can mean, so
     it appears only once there are two. -->
{#if selectedBooks.length > 1}
	<Tooltip.Provider>
		<Tooltip.Root ignoreNonKeyboardFocus>
			<Tooltip.Trigger
				onclick={() => (mergingBooks = selectedBooks)}
				class={buttonVariants({ variant: 'ghost', size: 'icon' })}
			>
				<GitMerge />
			</Tooltip.Trigger>
			<Tooltip.Content>
				<p>Merge {selectedBooks.length} books</p>
			</Tooltip.Content>
		</Tooltip.Root>
	</Tooltip.Provider>
{/if}

<!-- Delete selected button -->
<Tooltip.Provider>
	<Tooltip.Root ignoreNonKeyboardFocus>
		<Tooltip.Trigger
			onclick={() => {
				bookOps.deleteDialogTitle = `Delete ${selectionState.getSelectedIds().length} books?`;
				bookOps.deleteFn = async (deleteFiles: boolean) => {
					await bookOps.deleteBooks(selectionState.getSelectedIds(), deleteFiles);
					libraryState.activeLibrary!.total! -= selectedBooks.length;
					bookshelfState.deletedBooks(selectedBooks);
					selectionState.deselectAll();
				};
				bookOps.deleteDialogOpen = true;
			}}
			class={buttonVariants({ variant: 'ghost', size: 'icon' })}
		>
			<Trash2 />
		</Tooltip.Trigger>
		<Tooltip.Content>
			<p>Delete selected</p>
		</Tooltip.Content>
	</Tooltip.Root>
</Tooltip.Provider>

<!-- Select all button -->
<Tooltip.Provider>
	<Tooltip.Root ignoreNonKeyboardFocus>
		<Tooltip.Trigger
			onclick={() => {
				selectionState.selectAll(collectionState.books);
			}}
			class={buttonVariants({ variant: 'ghost', size: 'icon' })}
		>
			<SquareCheckBig />
		</Tooltip.Trigger>
		<Tooltip.Content>
			<p>Select all</p>
		</Tooltip.Content>
	</Tooltip.Root>
</Tooltip.Provider>

<!-- Deselect all button -->
<Tooltip.Provider>
	<Tooltip.Root ignoreNonKeyboardFocus>
		<Tooltip.Trigger
			onclick={() => {
				selectionState.deselectAll();
			}}
			class={buttonVariants({ variant: 'ghost', size: 'icon' })}
		>
			<X />
		</Tooltip.Trigger>
		<Tooltip.Content>
			<p>Deselect all</p>
		</Tooltip.Content>
	</Tooltip.Root>
</Tooltip.Provider>

<ShelfCreateDialog
	bind:open={createShelfDialogOpen}
	onSubmit={async (name: string) => {
		const bookshelf = await bookshelfState.addBookshelf(
			name,
			libraryState.activeLibrary!.id,
			selectionState.getSelectedIds()
		);
		selectedBooks.forEach((book) => book.lists.push(bookshelf));
		selectionState.deselectAll();
		createShelfDialogOpen = false;
	}}
/>

<!--
	Keyed on the selection so opening merge on a different pair starts from those
	records rather than the previous dialog's draft.
-->
{#if mergingBooks}
	{#key mergingBooks.map((book) => book.id).join()}
		<MergeBooks
			books={mergingBooks}
			libraryId={libraryState.activeLibrary!.id}
			open={true}
			onmerged={(_survivor, folded) => {
				// Only the folded records are gone; the survivor is still in the library.
				libraryState.activeLibrary!.total! -= folded.length;
				bookshelfState.deletedBooks(folded);
				selectionState.deselectAll();
				mergingBooks = null;
			}}
		/>
	{/key}
{/if}
