<script lang="ts">
	import { SvelteSet } from 'svelte/reactivity';
	import { Button } from '$lib/components/ui/button';
	import { Popover, PopoverTrigger, PopoverContent } from '$lib/components/ui/popover';
	import { Input } from '$lib/components/ui/input';
	import { client } from '$lib/graphql/client';
	import {
		GetReadingListsWithItemsDocument,
		AddToReadingListDocument,
		RemoveFromReadingListDocument,
		CreateReadingListDocument,
		type GetReadingListsWithItemsQuery
	} from '$lib/graphql/__generated__/graphql';
	import { isAuthenticated } from '$lib/auth/authStore';
	import ListPlus from '@lucide/svelte/icons/list-plus';
	import Plus from '@lucide/svelte/icons/plus';
	import Check from '@lucide/svelte/icons/check';
	import Loader2 from '@lucide/svelte/icons/loader-2';

	interface Props {
		novelId: number;
		size?: 'default' | 'sm' | 'icon';
	}

	let { novelId, size = 'default' }: Props = $props();

	type ReadingList = GetReadingListsWithItemsQuery['readingLists'][0];

	// State
	let popoverOpen = $state(false);
	let readingLists: ReadingList[] = $state([]);
	let fetching = $state(false);
	let error: string | null = $state(null);

	// Track which lists the novel is in (by list ID)
	let novelInLists = new SvelteSet<number>();

	// Track loading state for individual list toggles
	let loadingListIds = new SvelteSet<number>();

	// Quick-create state
	let showQuickCreate = $state(false);
	let newListName = $state('');
	let creatingList = $state(false);
	let createError: string | null = $state(null);

	// Fetch reading lists when popover opens
	$effect(() => {
		if (popoverOpen && $isAuthenticated) {
			fetchReadingLists();
		}
	});

	// Reset quick-create form when popover closes
	$effect(() => {
		if (!popoverOpen) {
			showQuickCreate = false;
			newListName = '';
			createError = null;
		}
	});

	async function fetchReadingLists() {
		fetching = true;
		error = null;

		try {
			const result = await client.query(GetReadingListsWithItemsDocument, {}).toPromise();

			if (result.error) {
				error = result.error.message;
				return;
			}

			if (result.data) {
				readingLists = result.data.readingLists;
				// Build the set of list IDs that contain this novel
				const inLists = new SvelteSet<number>();
				for (const list of readingLists) {
					if (list.items.some((item) => item.novelId === novelId)) {
						inLists.add(list.id);
					}
				}
				novelInLists = inLists;
			}
		} catch (e) {
			error = e instanceof Error ? e.message : 'Failed to load reading lists';
		} finally {
			fetching = false;
		}
	}

	async function toggleNovelInList(listId: number) {
		const isInList = novelInLists.has(listId);
		loadingListIds = new SvelteSet([...loadingListIds, listId]);

		try {
			if (isInList) {
				// Remove from list
				const result = await client
					.mutation(RemoveFromReadingListDocument, {
						input: { listId, novelId }
					})
					.toPromise();

				if (result.error) {
					error = result.error.message;
					return;
				}

				if (result.data?.removeFromReadingList?.errors?.length) {
					error = result.data.removeFromReadingList.errors[0]?.message ?? 'Failed to remove from list';
					return;
				}

				if (result.data?.removeFromReadingList?.readingListPayload?.success) {
					// Update local state
					novelInLists = new SvelteSet([...novelInLists].filter((id) => id !== listId));
					// Update item count in list
					readingLists = readingLists.map((list) =>
						list.id === listId
							? { ...list, itemCount: list.itemCount - 1, items: list.items.filter((i) => i.novelId !== novelId) }
							: list
					);
				}
			} else {
				// Add to list
				const result = await client
					.mutation(AddToReadingListDocument, {
						input: { readingListId: listId, novelId }
					})
					.toPromise();

				if (result.error) {
					error = result.error.message;
					return;
				}

				if (result.data?.addToReadingList?.errors?.length) {
					error = result.data.addToReadingList.errors[0]?.message ?? 'Failed to add to list';
					return;
				}

				if (result.data?.addToReadingList?.readingListPayload?.success) {
					// Update local state
					novelInLists = new SvelteSet([...novelInLists, listId]);
					// Update item count in list
					readingLists = readingLists.map((list) =>
						list.id === listId
							? {
									...list,
									itemCount: list.itemCount + 1,
									items: [...list.items, { novelId, order: list.itemCount, addedTime: new Date().toISOString() }]
								}
							: list
					);
				}
			}
		} catch (e) {
			error = e instanceof Error ? e.message : 'An error occurred';
		} finally {
			loadingListIds = new SvelteSet([...loadingListIds].filter((id) => id !== listId));
		}
	}

	async function createListAndAdd() {
		if (!newListName.trim()) {
			createError = 'Name is required';
			return;
		}

		creatingList = true;
		createError = null;

		try {
			const result = await client
				.mutation(CreateReadingListDocument, {
					input: {
						name: newListName.trim(),
						description: null
					}
				})
				.toPromise();

			if (result.error) {
				createError = result.error.message;
				return;
			}

			if (result.data?.createReadingList?.errors?.length) {
				createError = result.data.createReadingList.errors[0]?.message ?? 'Failed to create list';
				return;
			}

			const newList = result.data?.createReadingList?.readingListPayload?.readingList;
			if (newList) {
				// Now add the novel to the new list
				const addResult = await client
					.mutation(AddToReadingListDocument, {
						input: { readingListId: newList.id, novelId }
					})
					.toPromise();

				if (addResult.error) {
					createError = addResult.error.message;
					return;
				}

				if (addResult.data?.addToReadingList?.errors?.length) {
					createError = addResult.data.addToReadingList.errors[0]?.message ?? 'Failed to add to list';
					return;
				}

				// Add the new list to our local state
				const fullNewList: ReadingList = {
					...newList,
					itemCount: 1,
					items: [{ novelId, order: 0, addedTime: new Date().toISOString() }]
				};
				readingLists = [...readingLists, fullNewList];
				novelInLists = new SvelteSet([...novelInLists, newList.id]);

				// Reset quick-create form
				showQuickCreate = false;
				newListName = '';
			}
		} catch (e) {
			createError = e instanceof Error ? e.message : 'An error occurred';
		} finally {
			creatingList = false;
		}
	}

	function handleClick(e: MouseEvent) {
		e.preventDefault();
		e.stopPropagation();
	}

	function handleKeyDown(e: KeyboardEvent) {
		if (e.key === 'Enter') {
			e.preventDefault();
			createListAndAdd();
		}
	}

	// Compute if novel is in any list for button state
	let isInAnyList = $derived(novelInLists.size > 0);
</script>

{#if $isAuthenticated}
	<!-- svelte-ignore a11y_click_events_have_key_events -->
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div onclick={handleClick}>
		<Popover bind:open={popoverOpen}>
			<PopoverTrigger asChild>
				{#snippet child({ props })}
					<Button
						variant={isInAnyList ? 'default' : 'outline'}
						{size}
						class={size === 'icon' ? 'h-8 w-8' : 'gap-2'}
						{...props}
					>
						<ListPlus class="h-4 w-4" />
						{#if size !== 'icon'}
							<span>{isInAnyList ? 'In Lists' : 'Add to List'}</span>
						{/if}
					</Button>
				{/snippet}
			</PopoverTrigger>
			<PopoverContent class="w-80">
				<div class="space-y-4">
					<div class="space-y-2">
						<h4 class="font-medium leading-none">Add to Reading List</h4>
						<p class="text-sm text-muted-foreground">
							Select lists to add or remove this novel.
						</p>
					</div>

					{#if fetching}
						<div class="flex items-center justify-center py-4">
							<Loader2 class="h-5 w-5 animate-spin text-muted-foreground" />
						</div>
					{:else if error}
						<p class="text-sm text-destructive">{error}</p>
					{:else if readingLists.length === 0 && !showQuickCreate}
						<div class="text-center py-4">
							<p class="text-sm text-muted-foreground mb-3">No reading lists yet</p>
							<Button size="sm" variant="outline" onclick={() => (showQuickCreate = true)}>
								<Plus class="h-4 w-4 mr-1" />
								Create your first list
							</Button>
						</div>
					{:else}
						<!-- Reading lists -->
						<div class="space-y-1 max-h-[200px] overflow-y-auto">
							{#each readingLists as list (list.id)}
								{@const isInList = novelInLists.has(list.id)}
								{@const isLoading = loadingListIds.has(list.id)}
								<button
									type="button"
									class="flex w-full items-center gap-3 rounded-md px-2 py-2 text-left hover:bg-accent transition-colors disabled:opacity-50"
									onclick={() => toggleNovelInList(list.id)}
									disabled={isLoading}
								>
									<div
										class="flex h-4 w-4 shrink-0 items-center justify-center rounded border {isInList
											? 'bg-primary border-primary'
											: 'border-input'}"
									>
										{#if isLoading}
											<Loader2 class="h-3 w-3 animate-spin text-primary-foreground" />
										{:else if isInList}
											<Check class="h-3 w-3 text-primary-foreground" />
										{/if}
									</div>
									<div class="flex-1 min-w-0">
										<div class="text-sm font-medium truncate">{list.name}</div>
										<div class="text-xs text-muted-foreground">
											{list.itemCount} {list.itemCount === 1 ? 'novel' : 'novels'}
										</div>
									</div>
								</button>
							{/each}
						</div>

						<!-- Quick-create section -->
						{#if showQuickCreate}
							<div class="border-t pt-3 space-y-2">
								<div class="flex gap-2">
									<Input
										type="text"
										placeholder="New list name"
										bind:value={newListName}
										disabled={creatingList}
										onkeydown={handleKeyDown}
										class="flex-1"
									/>
									<Button size="sm" onclick={createListAndAdd} disabled={creatingList || !newListName.trim()}>
										{#if creatingList}
											<Loader2 class="h-4 w-4 animate-spin" />
										{:else}
											Add
										{/if}
									</Button>
								</div>
								{#if createError}
									<p class="text-xs text-destructive">{createError}</p>
								{/if}
							</div>
						{:else}
							<div class="border-t pt-3">
								<Button
									size="sm"
									variant="ghost"
									class="w-full justify-start"
									onclick={() => (showQuickCreate = true)}
								>
									<Plus class="h-4 w-4 mr-2" />
									Create new list
								</Button>
							</div>
						{/if}
					{/if}
				</div>
			</PopoverContent>
		</Popover>
	</div>
{/if}
