<script lang="ts">
	import * as Card from '$lib/components/ui/card/index.js';
	import * as Field from '$lib/components/ui/field/index.js';
	import { TagsInput, type TagsInputProps } from '$lib/components/ui/tags-input/index.js';
	import { Input } from '$lib/components/ui/input/index.js';
	import { Textarea } from '$lib/components/ui/textarea/index.js';
	import { Button } from '$lib/components/ui/button/index.js';
	import { toast } from 'svelte-sonner';

	import { updateBookMetadata } from '$lib/api';
	import type { Book } from '$lib/schema';
	import { untrack } from 'svelte';
	import { Minus, Plus } from '@lucide/svelte';

	let { book, open = $bindable() }: { book: Book; open: boolean } = $props();

	let authors = $state(book.authors.map((author) => author.name) || []);
	let tags = $state(book.tags.map((tag) => tag.name) || []);
	let identifierKeys = $state(Object.keys(book.identifiers));
	let identifierValues = $state(Object.values(book.identifiers));

	function handleAddIdentifier() {
		// Add empty strings to both arrays
		identifierKeys = [...identifierKeys, ''];
		identifierValues = [...identifierValues, ''];
	}

	function handleRemoveIdentifier(index: number) {
		identifierKeys = identifierKeys.filter((_, i) => i !== index);
		identifierValues = identifierValues.filter((_, i) => i !== index);
	}

	const validateTagsInput: TagsInputProps['validate'] = (val, tags) => {
		const transformed = val.trim();

		// disallow empties
		if (transformed.length === 0) return undefined;

		// disallow duplicates
		if (tags.find((t) => transformed === t.toLowerCase())) return undefined;

		return transformed;
	};

	// Pre-populate forms
	$effect(() => {
		book;
		untrack(() => {
			updateBookMetadata.fields.set({
				book_id: book.id.toString(),
				title: book.title,
				subtitle: book.subtitle || undefined,
				authors: authors,
				tags: tags,
				identifiers: JSON.stringify(
					Object.fromEntries(identifierKeys.map((key, i) => [key, identifierValues[i]]))
				),
				description: book.description || undefined,
				publisher: book.publisher?.name || undefined,
				published_date: book.published_date || undefined,
				series: book?.series?.title || undefined,
				series_position: book?.series_position || undefined,
				pages: book?.pages || undefined,
				language: book?.language || undefined,
				edition: book.edition || undefined
			});

			identifierKeys = Object.keys(book.identifiers);
			identifierValues = Object.values(book.identifiers);
		});
	});

	// Keep form data in sync
	$effect(() => {
		updateBookMetadata.fields.authors.set(authors);
	});

	$effect(() => {
		updateBookMetadata.fields.tags.set(tags);
	});

	$effect(() => {
		updateBookMetadata.fields.identifiers.set(
			JSON.stringify(Object.fromEntries(identifierKeys.map((key, i) => [key, identifierValues[i]])))
		);
	});
</script>

<Card.Root class="w-full ">
	<form
		{...updateBookMetadata.enhance(async ({ submit, form }) => {
			try {
				await submit();

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

				open = false;
				book = book;
				toast.success('Updated book metadata!');
			} catch (error) {
				console.error('Error occurred updating book metadata: ', error);
				toast.error('Failed to update book metadata.');
			}
		})}
	>
		<Card.Content>
			<Field.Set>
				<Field.Group class="flex flex-col">
					<!-- Book ID field -->
					<Field.Field class="hidden">
						<Field.Label for="book_id">Book ID</Field.Label>
						<Input {...updateBookMetadata.fields.book_id.as('text')} />
						{#each updateBookMetadata.fields.book_id.issues() ?? [] as issue}
							<Field.Error>{issue.message}</Field.Error>
						{/each}
					</Field.Field>

					<!-- Title field -->
					<Field.Field>
						<Field.Label for="title">Title</Field.Label>
						<Input {...updateBookMetadata.fields.title.as('text')} />
						{#each updateBookMetadata.fields.title.issues() ?? [] as issue}
							<Field.Error>{issue.message}</Field.Error>
						{/each}
					</Field.Field>

					<!-- Subtitle field -->
					<Field.Field>
						<Field.Label for="subtitle">Subtitle</Field.Label>
						<Input {...updateBookMetadata.fields.subtitle.as('text')} />
						{#each updateBookMetadata.fields.subtitle.issues() ?? [] as issue}
							<Field.Error>{issue.message}</Field.Error>
						{/each}
					</Field.Field>

					<div class="grid grid-cols-[3fr_1fr] gap-2">
						<!-- Series field -->
						<Field.Field>
							<Field.Label for="series">Series</Field.Label>
							<Input {...updateBookMetadata.fields.series.as('text')} />
							{#each updateBookMetadata.fields.series.issues() ?? [] as issue}
								<Field.Error>{issue.message}</Field.Error>
							{/each}
						</Field.Field>

						<!-- Series position field -->
						<Field.Field>
							<Field.Label for="series_position">Series position</Field.Label>
							<Input {...updateBookMetadata.fields.series_position.as('text')} />
							{#each updateBookMetadata.fields.series_position.issues() ?? [] as issue}
								<Field.Error>{issue.message}</Field.Error>
							{/each}
						</Field.Field>
					</div>

					<!-- Authors field -->
					<Field.Field>
						<Field.Label for="authors">Authors</Field.Label>
						<TagsInput
							bind:value={authors}
							validate={validateTagsInput}
							placeholder="Add an author"
							class="min-h-10 p-2 text-sm"
						/>
						{#each authors as author}
							<input class="hidden" {...updateBookMetadata.fields.authors.as('checkbox', author)} />
						{/each}
						{#each updateBookMetadata.fields.authors.issues() ?? [] as issue}
							<Field.Error>{issue.message}</Field.Error>
						{/each}
					</Field.Field>

					<!-- Tags field -->
					<Field.Field>
						<Field.Label for="tags">Tags</Field.Label>
						<TagsInput
							bind:value={tags}
							validate={validateTagsInput}
							placeholder="Add a tag"
							class="min-h-10 p-2 text-sm"
						/>
						{#each tags as tag}
							<input class="hidden" {...updateBookMetadata.fields.tags.as('checkbox', tag)} />
						{/each}
						{#each updateBookMetadata.fields.tags.issues() ?? [] as issue}
							<Field.Error>{issue.message}</Field.Error>
						{/each}
					</Field.Field>

					<!-- Description field -->
					<Field.Field>
						<Field.Label for="description">Description</Field.Label>
						<Textarea {...updateBookMetadata.fields.description.as('text')} />
						{#each updateBookMetadata.fields.description.issues() ?? [] as issue}
							<Field.Error>{issue.message}</Field.Error>
						{/each}
					</Field.Field>

					<!-- Identifier fields -->
					<Field.Field>
						<Field.Label for="identifiers">Identifiers</Field.Label>
						<div class="grid grid-cols-[5fr_10fr_0.5fr] gap-2">
							{#each identifierKeys as _, idx}
								<Input bind:value={identifierKeys[idx]} placeholder="Identifier..." />
								<Input bind:value={identifierValues[idx]} placeholder="Value..." />

								<Button variant="outline" size="icon" onclick={() => handleRemoveIdentifier(idx)}>
									<Minus />
								</Button>
							{/each}

							<Button variant="outline" onclick={() => handleAddIdentifier()}>
								<Plus />
								Add Identifier
							</Button>

							<input {...updateBookMetadata.fields.identifiers.as('text')} class="hidden" />
						</div>
					</Field.Field>

					<!-- Publisher field -->
					<div class="grid grid-cols-[2fr_1fr] gap-2">
						<Field.Field>
							<Field.Label for="publisher">Publisher</Field.Label>
							<Input {...updateBookMetadata.fields.publisher.as('text')} />
							{#each updateBookMetadata.fields.publisher.issues() ?? [] as issue}
								<Field.Error>{issue.message}</Field.Error>
							{/each}
						</Field.Field>

						<!-- Published date field -->
						<Field.Field>
							<Field.Label for="published_date">Date published</Field.Label>
							<Input {...updateBookMetadata.fields.published_date.as('date')} />
							{#each updateBookMetadata.fields.published_date.issues() ?? [] as issue}
								<Field.Error>{issue.message}</Field.Error>
							{/each}
						</Field.Field>
					</div>

					<div class="grid grid-cols-[2fr_1fr_1fr] gap-2">
						<!-- Pages field -->
						<Field.Field>
							<Field.Label for="pages">Pages</Field.Label>
							<Input {...updateBookMetadata.fields.pages.as('number')} />
							{#each updateBookMetadata.fields.pages.issues() ?? [] as issue}
								<Field.Error>{issue.message}</Field.Error>
							{/each}
						</Field.Field>

						<!-- Language field -->
						<Field.Field>
							<Field.Label for="language">Language</Field.Label>
							<Input {...updateBookMetadata.fields.language.as('text')} />
							{#each updateBookMetadata.fields.language.issues() ?? [] as issue}
								<Field.Error>{issue.message}</Field.Error>
							{/each}
						</Field.Field>

						<!-- Edition field -->
						<Field.Field>
							<Field.Label for="edition">Edition</Field.Label>
							<Input {...updateBookMetadata.fields.edition.as('number')} />
							{#each updateBookMetadata.fields.edition.issues() ?? [] as issue}
								<Field.Error>{issue.message}</Field.Error>
							{/each}
						</Field.Field>
					</div>
				</Field.Group>
			</Field.Set>
		</Card.Content>

		<!-- Submit button -->
		<Card.Footer class="flex-col gap-2 pt-6">
			<Button type="submit" class="w-full">Save</Button>
		</Card.Footer>
	</form>
</Card.Root>
