<script lang="ts">
	import { untrack } from 'svelte';
	import { toast } from 'svelte-sonner';
	import { Minus, Plus } from '@lucide/svelte';

	import { updateBookMetadata } from '$lib/api';
	import type { Book } from '$lib/schema';

	import * as Field from '$lib/components/ui/field/index.js';
	import { Button } from '$lib/components/ui/button/index.js';
	import { Input } from '$lib/components/ui/input/index.js';
	import { TagsInput, type TagsInputProps } from '$lib/components/ui/tags-input/index.js';
	import { Textarea } from '$lib/components/ui/textarea/index.js';

	let {
		book,
		open = $bindable(),
		/** Lets the dialog footer own the submit button via the `form` attribute. */
		formId
	}: { book: Book; open: boolean; formId: string } = $props();

	// Seeded once per mount; edit-book.svelte keys this form on book.id so a
	// different book gets a fresh form rather than the previous book's values.
	let authors = $state(untrack(() => book.authors.map((author) => author.name) || []));
	let tags = $state(untrack(() => book.tags.map((tag) => tag.name) || []));
	let identifierKeys = $state(untrack(() => Object.keys(book.identifiers)));
	let identifierValues = $state(untrack(() => Object.values(book.identifiers)));

	function handleAddIdentifier() {
		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>

{#snippet groupHeading(label: string)}
	<h3
		class="col-span-full mt-2 border-b pb-1 font-mono text-[10px] tracking-widest text-primary uppercase first:mt-0"
	>
		{label}
	</h3>
{/snippet}

<form
	id={formId}
	{...updateBookMetadata.enhance(async ({ submit }) => {
		try {
			await submit();

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

			open = false;
			toast.success('Updated book metadata!');
		} catch (error) {
			console.error('Error occurred updating book metadata: ', error);
			toast.error('Failed to update book metadata.');
		}
	})}
	class="grid grid-cols-1 items-start gap-x-4 gap-y-3 sm:grid-cols-2"
>
	<input class="hidden" {...updateBookMetadata.fields.book_id.as('text')} />

	{@render groupHeading('Identity')}

	<Field.Field class="col-span-full">
		<Field.Label for="title">Title</Field.Label>
		<Input {...updateBookMetadata.fields.title.as('text')} />
		{#each updateBookMetadata.fields.title.issues() ?? [] as issue, i (i)}
			<Field.Error>{issue.message}</Field.Error>
		{/each}
	</Field.Field>

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

	<Field.Field>
		<Field.Label for="edition">Edition</Field.Label>
		<Input {...updateBookMetadata.fields.edition.as('number')} />
		{#each updateBookMetadata.fields.edition.issues() ?? [] as issue, i (i)}
			<Field.Error>{issue.message}</Field.Error>
		{/each}
	</Field.Field>

	<Field.Field>
		<Field.Label for="series">Series</Field.Label>
		<Input {...updateBookMetadata.fields.series.as('text')} />
		{#each updateBookMetadata.fields.series.issues() ?? [] as issue, i (i)}
			<Field.Error>{issue.message}</Field.Error>
		{/each}
	</Field.Field>

	<div class="grid grid-cols-2 gap-2">
		<Field.Field>
			<Field.Label for="series_position">No.</Field.Label>
			<Input {...updateBookMetadata.fields.series_position.as('text')} />
			{#each updateBookMetadata.fields.series_position.issues() ?? [] as issue, i (i)}
				<Field.Error>{issue.message}</Field.Error>
			{/each}
		</Field.Field>

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

	{@render groupHeading('People and subjects')}

	<Field.Field class="col-span-full">
		<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, i (i)}
			<input class="hidden" {...updateBookMetadata.fields.authors.as('checkbox', author)} />
		{/each}
		{#each updateBookMetadata.fields.authors.issues() ?? [] as issue, i (i)}
			<Field.Error>{issue.message}</Field.Error>
		{/each}
	</Field.Field>

	<Field.Field class="col-span-full">
		<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, i (i)}
			<input class="hidden" {...updateBookMetadata.fields.tags.as('checkbox', tag)} />
		{/each}
		{#each updateBookMetadata.fields.tags.issues() ?? [] as issue, i (i)}
			<Field.Error>{issue.message}</Field.Error>
		{/each}
	</Field.Field>

	{@render groupHeading('Publication')}

	<Field.Field>
		<Field.Label for="publisher">Publisher</Field.Label>
		<Input {...updateBookMetadata.fields.publisher.as('text')} />
		{#each updateBookMetadata.fields.publisher.issues() ?? [] as issue, i (i)}
			<Field.Error>{issue.message}</Field.Error>
		{/each}
	</Field.Field>

	<div class="grid grid-cols-2 gap-2">
		<Field.Field>
			<Field.Label for="published_date">Published</Field.Label>
			<Input {...updateBookMetadata.fields.published_date.as('date')} />
			{#each updateBookMetadata.fields.published_date.issues() ?? [] as issue, i (i)}
				<Field.Error>{issue.message}</Field.Error>
			{/each}
		</Field.Field>

		<Field.Field>
			<Field.Label for="pages">Pages</Field.Label>
			<Input {...updateBookMetadata.fields.pages.as('number')} />
			{#each updateBookMetadata.fields.pages.issues() ?? [] as issue, i (i)}
				<Field.Error>{issue.message}</Field.Error>
			{/each}
		</Field.Field>
	</div>

	<Field.Field class="col-span-full">
		<Field.Label for="identifiers">Identifiers</Field.Label>
		<div class="flex flex-col gap-2">
			{#each identifierKeys as _, idx (idx)}
				<div class="grid grid-cols-[1fr_1.6fr_auto] gap-2">
					<Input bind:value={identifierKeys[idx]} placeholder="ISBN, DOI…" />
					<Input bind:value={identifierValues[idx]} placeholder="Value" />
					<Button
						type="button"
						variant="outline"
						size="icon"
						title="Remove identifier"
						onclick={() => handleRemoveIdentifier(idx)}
					>
						<Minus />
						<span class="sr-only">Remove identifier</span>
					</Button>
				</div>
			{/each}

			<Button type="button" variant="outline" class="w-fit" onclick={handleAddIdentifier}>
				<Plus />
				Add identifier
			</Button>

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

	{@render groupHeading('Description')}

	<Field.Field class="col-span-full">
		<Field.Label for="description" class="sr-only">Description</Field.Label>
		<Textarea {...updateBookMetadata.fields.description.as('text')} rows={6} />
		{#each updateBookMetadata.fields.description.issues() ?? [] as issue, i (i)}
			<Field.Error>{issue.message}</Field.Error>
		{/each}
	</Field.Field>
</form>
