<script lang="ts">
	import type BookTrackerPlugin from "@src/main";
	import Book from "@ui/components/bookshelf/Book.svelte";
	import Bookshelf from "@ui/components/bookshelf/Bookshelf.svelte";
	import BookStack from "@ui/components/bookshelf/BookStack.svelte";
	import {
		getMetadataContext,
		type FileMetadata,
	} from "@ui/stores/metadata.svelte";
	import { COLOR_NAMES, type ColorName } from "@utils/color";
	import { randomElement, randomFloat } from "@utils/rand";
	import { v4 as uuidv4 } from "uuid";
	import memoize from "just-memoize";
	import type { TFile } from "obsidian";

	interface Props {
		plugin: BookTrackerPlugin;
	}

	interface BookData {
		id: string;
		title: string;
		subtitle?: string;
		authors: string[];
		width: number;
		color: ColorName;
		design: (typeof designs)[number];
		orientation: "default" | "tilted" | "front";
		file: TFile;
	}

	interface BookStackData {
		id: string;
		books: BookData[];
	}

	const { plugin }: Props = $props();

	const metadataStore = getMetadataContext();

	const designs = ["default", "dual-top-bands", "split-bands"] as const;

	const randomDesign = () => randomElement(designs);
	const randomColor = () => randomElement(COLOR_NAMES);
	function randomOrientation() {
		const n = randomFloat();

		if (n < 0.55) {
			return "default";
		} else if (n < 0.8) {
			return "tilted";
		} else {
			return "front";
		}
	}
	const randomStackChance = () => randomFloat() > 0.9;
	function randomStackSize() {
		const n = randomFloat();
		if (n < 0.15) {
			return 5;
		} else if (n < 0.3) {
			return 4;
		} else if (n < 0.5) {
			return 3;
		} else if (n < 0.8) {
			return 2;
		} else {
			return 1;
		}
	}

	const getBookData = memoize(
		(meta: FileMetadata): BookData => {
			const orientation = randomOrientation();

			return {
				id: meta.file.path,
				title: meta.book.title,
				subtitle:
					meta.book.subtitle === "" ? undefined : meta.book.subtitle,
				authors: meta.book.authors,
				width: Math.min(Math.max(20, meta.book.pageCount / 10), 100),
				color: randomColor(),
				design: orientation === "front" ? "default" : randomDesign(),
				orientation: randomOrientation(),
				file: meta.file,
			};
		},
		(metadata: FileMetadata) => metadata.file.path,
	);

	let books: (BookData | BookStackData)[] = $state([]);
	$effect(() => {
		let newBooks: (BookData | BookStackData)[] = [];

		for (let i = 0; i < metadataStore.metadata.length; i++) {
			if (randomStackChance()) {
				const booksRemaining = metadataStore.metadata.length - i;
				const stackSize = Math.min(booksRemaining, randomStackSize());

				newBooks.push({
					id: uuidv4(),
					books: metadataStore.metadata
						.slice(i, i + stackSize)
						.map(getBookData),
				});
				i += stackSize - 1;
			} else {
				newBooks.push(getBookData(metadataStore.metadata[i]));
			}
		}

		books = newBooks;
	});
</script>

<Bookshelf>
	{#each books as book (book.id)}
		{#if "books" in book}
			<BookStack>
				{#each book.books as bookData (bookData.id)}
					<Book
						title={bookData.title}
						subtitle={bookData.subtitle}
						authors={bookData.authors}
						width={bookData.width}
						color={bookData.color}
						design={bookData.design}
						orientation="flat"
						onClick={() =>
							plugin.app.workspace
								.getLeaf(false)
								.openFile(bookData.file)}
					/>
				{/each}
			</BookStack>
		{:else}
			<Book
				title={book.title}
				subtitle={book.subtitle}
				authors={book.authors}
				width={book.width}
				color={book.color}
				design={book.design}
				orientation={book.orientation}
				onClick={() =>
					plugin.app.workspace.getLeaf(false).openFile(book.file)}
			/>
		{/if}
	{/each}
</Bookshelf>
