<script lang="ts" module>
	import type { NovelQuery, NovelStatus, Language } from '$lib/graphql/__generated__/graphql';
	import { TagType } from '$lib/graphql/__generated__/graphql';
	import { SystemTags } from '$lib/constants/systemTags';

	export type NovelNode = NonNullable<NonNullable<NovelQuery['novels']>['nodes']>[number];

	const statusColors: Record<NovelStatus, string> = {
		IN_PROGRESS: 'bg-green-500 text-white',
		COMPLETED: 'bg-blue-500 text-white',
		HIATUS: 'bg-amber-500 text-white',
		ABANDONED: 'bg-gray-500 text-white',
		UNKNOWN: 'bg-gray-500 text-white'
	};

	const statusLabels: Record<NovelStatus, string> = {
		IN_PROGRESS: 'Ongoing',
		COMPLETED: 'Complete',
		HIATUS: 'Hiatus',
		ABANDONED: 'Dropped',
		UNKNOWN: 'Unknown'
	};

	const languageLabels: Record<Language, string> = {
		EN: 'English',
		KR: 'Korean',
		JA: 'Japanese',
		CH: 'Chinese'
	};
</script>

<script lang="ts">
	import { onMount } from 'svelte';
	import { client } from '$lib/graphql/client';
	import { NovelDocument, ImportNovelDocument, DeleteNovelDocument } from '$lib/graphql/__generated__/graphql';
	import { isAuthenticated } from '$lib/auth/authStore';
	import { Card, CardContent, CardHeader } from '$lib/components/ui/card';
	import { Badge } from '$lib/components/ui/badge';
	import { Button } from '$lib/components/ui/button';
	import { Tabs, TabsList, TabsTrigger, TabsContent } from '$lib/components/ui/tabs';
	import {
		Tooltip,
		TooltipTrigger,
		TooltipContent,
		TooltipProvider
	} from '$lib/components/ui/tooltip';
	import { formatRelativeTime, formatAbsoluteTime } from '$lib/utils/time';
	import { sanitizeHtml } from '$lib/utils/sanitize';
	// Direct imports for faster builds
	import ArrowLeft from '@lucide/svelte/icons/arrow-left';
	import ExternalLink from '@lucide/svelte/icons/external-link';
	import BookOpen from '@lucide/svelte/icons/book-open';
	import ChevronDown from '@lucide/svelte/icons/chevron-down';
	import ChevronUp from '@lucide/svelte/icons/chevron-up';
	import RefreshCw from '@lucide/svelte/icons/refresh-cw';
	import Trash2 from '@lucide/svelte/icons/trash-2';
	import X from '@lucide/svelte/icons/x';
	import ChevronLeft from '@lucide/svelte/icons/chevron-left';
	import ChevronRight from '@lucide/svelte/icons/chevron-right';

	interface Props {
		novelId?: string;
	}

	let { novelId }: Props = $props();

	let novel: NovelNode | null = $state(null);
	let fetching = $state(true);
	let error: string | null = $state(null);
	let descriptionExpanded = $state(false);
	let refreshing = $state(false);
	let refreshError: string | null = $state(null);
	let refreshSuccess = $state(false);

	// Delete state
	let showDeleteConfirm = $state(false);
	let deleting = $state(false);
	let deleteError: string | null = $state(null);

	// Image viewer state
	type GalleryImage = {
		src: string;
		alt: string;
		chapterId?: number;
		chapterOrder?: number;
		chapterName?: string;
		isCover: boolean;
	};
	let viewerOpen = $state(false);
	let viewerIndex = $state(0);
	let activeTab = $state('chapters');
	let galleryLoaded = $state(false);

	const DESCRIPTION_PREVIEW_LENGTH = 300;

	// Derived values
	const coverSrc = $derived(novel?.coverImage?.newPath);
	const status = $derived(novel?.rawStatus ?? 'UNKNOWN');
	const statusColor = $derived(statusColors[status]);
	const statusLabel = $derived(statusLabels[status]);
	const language = $derived(novel?.rawLanguage ?? 'EN');
	const languageLabel = $derived(languageLabels[language]);

	const lastUpdated = $derived(novel?.lastUpdatedTime ? new Date(novel.lastUpdatedTime) : null);
	const relativeTime = $derived(lastUpdated ? formatRelativeTime(lastUpdated) : null);
	const absoluteTime = $derived(lastUpdated ? formatAbsoluteTime(lastUpdated) : null);

	const description = $derived(novel?.description ?? '');
	const descriptionHtml = $derived(sanitizeHtml(description));
	const isDescriptionLong = $derived(description.length > DESCRIPTION_PREVIEW_LENGTH);
	const truncatedDescriptionHtml = $derived(
		isDescriptionLong && !descriptionExpanded
			? sanitizeHtml(description.slice(0, DESCRIPTION_PREVIEW_LENGTH) + '...')
			: descriptionHtml
	);

	const sortedChapters = $derived(
		[...(novel?.chapters ?? [])].sort((a, b) => a.order - b.order)
	);

	const chapterCount = $derived(novel?.chapters?.length ?? 0);

	// Filter out system tags for display, check for NSFW
	const displayTags = $derived(novel?.tags?.filter((tag) => tag.tagType !== TagType.System) ?? []);
	const isNsfw = $derived(novel?.tags?.some((tag) => tag.key === SystemTags.Nsfw) ?? false);

	const canRefresh = $derived(() => {
		if (!lastUpdated) return true;
		const sixHoursAgo = Date.now() - 6 * 60 * 60 * 1000;
		return lastUpdated.getTime() < sixHoursAgo;
	});

	// Gallery images - cover + chapter images
	const galleryImages = $derived.by(() => {
		const images: GalleryImage[] = [];

		// Add cover image first
		if (coverSrc && novel) {
			images.push({ src: coverSrc, alt: `${novel.name} cover`, isCover: true });
		}

		// Add chapter images
		for (const chapter of sortedChapters) {
			for (const img of chapter.images ?? []) {
				if (img.newPath) {
					images.push({
						src: img.newPath,
						alt: `Image from ${chapter.name}`,
						chapterId: chapter.id,
						chapterOrder: chapter.order,
						chapterName: chapter.name,
						isCover: false
					});
				}
			}
		}

		return images;
	});

	const currentImage = $derived(galleryImages[viewerIndex]);
	const imageCount = $derived(galleryImages.length);

	// Load gallery images when tab is first activated
	$effect(() => {
		if (activeTab === 'gallery' && !galleryLoaded) {
			galleryLoaded = true;
		}
	});

	// Image viewer functions
	function openImageViewer(index: number) {
		viewerIndex = index;
		viewerOpen = true;
	}

	function closeViewer() {
		viewerOpen = false;
	}

	function nextImage() {
		if (galleryImages.length > 0) {
			viewerIndex = (viewerIndex + 1) % galleryImages.length;
		}
	}

	function prevImage() {
		if (galleryImages.length > 0) {
			viewerIndex = (viewerIndex - 1 + galleryImages.length) % galleryImages.length;
		}
	}

	function handleViewerKeydown(e: KeyboardEvent) {
		if (!viewerOpen) return;
		if (e.key === 'Escape') closeViewer();
		if (e.key === 'ArrowRight') nextImage();
		if (e.key === 'ArrowLeft') prevImage();
	}

	async function fetchNovel() {
		if (!novelId) {
			error = 'No novel ID provided';
			fetching = false;
			return;
		}

		fetching = true;
		error = null;

		try {
			const result = await client
				.query(NovelDocument, { id: parseInt(novelId, 10) })
				.toPromise();

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

			const nodes = result.data?.novels?.nodes;
			if (nodes && nodes.length > 0) {
				novel = nodes[0];
				document.title = novel.name;
			} else {
				error = 'Novel not found';
			}
		} catch (e) {
			error = e instanceof Error ? e.message : 'Unknown error';
		} finally {
			fetching = false;
		}
	}

	async function refreshNovel() {
		if (!novel?.url) return;

		refreshing = true;
		refreshError = null;
		refreshSuccess = false;

		try {
			const result = await client
				.mutation(ImportNovelDocument, { input: { novelUrl: novel.url } })
				.toPromise();

			if (result.error) {
				refreshError = result.error.message;
			} else {
				refreshSuccess = true;
				setTimeout(() => (refreshSuccess = false), 2000);
			}
		} catch (e) {
			refreshError = e instanceof Error ? e.message : 'Failed to refresh';
		} finally {
			refreshing = false;
		}
	}

	async function deleteNovel() {
		if (!novel) return;

		deleting = true;
		deleteError = null;

		try {
			const result = await client
				.mutation(DeleteNovelDocument, { input: { novelId: novel.id } })
				.toPromise();

			if (result.error) {
				deleteError = result.error.message;
			} else if (result.data?.deleteNovel?.errors?.length) {
				deleteError = result.data.deleteNovel.errors[0].message;
			} else {
				// Successfully deleted - redirect to novels list
				window.location.href = '/novels';
			}
		} catch (e) {
			deleteError = e instanceof Error ? e.message : 'Failed to delete';
		} finally {
			deleting = false;
		}
	}

	onMount(() => {
		fetchNovel();
	});
</script>

<div class="space-y-6">
	<!-- Back Navigation -->
	<Button variant="ghost" href="/novels" class="gap-2 -ml-2">
		<ArrowLeft class="h-4 w-4" />
		Back to Novels
	</Button>

	<!-- Loading State -->
	{#if fetching}
		<Card>
			<CardContent>
				<div class="flex items-center justify-center py-12">
					<div
						class="border-primary h-10 w-10 animate-spin rounded-full border-2 border-t-transparent"
						aria-label="Loading novel"
					></div>
				</div>
			</CardContent>
		</Card>
	{/if}

	<!-- Error State -->
	{#if error && !fetching}
		<Card class="border-destructive/40 bg-destructive/5">
			<CardContent class="py-8">
				<div class="text-center">
					<p class="text-destructive text-lg font-medium">
						{error === 'Novel not found' ? 'Novel Not Found' : 'Error Loading Novel'}
					</p>
					<p class="text-muted-foreground mt-2 text-sm">{error}</p>
					<Button variant="outline" onclick={fetchNovel} class="mt-4">
						Try Again
					</Button>
				</div>
			</CardContent>
		</Card>
	{/if}

	<!-- Novel Content -->
	{#if novel && !fetching}
		<!-- Header Section (Metadata + Tags + Description) -->
		<Card class="shadow-md shadow-primary/10 overflow-hidden">
			<CardContent class="p-0">
				<!-- Cover Image + Metadata + Tags -->
				<div class="flex flex-col sm:flex-row gap-6 p-6 pb-4">
					<!-- Cover Image -->
					<div class="shrink-0 sm:w-40">
						{#if coverSrc}
							<div class="aspect-[3/4] w-full overflow-hidden rounded-lg bg-muted/50">
								<img
									src={coverSrc}
									alt={novel.name}
									class="h-full w-full object-cover"
								/>
							</div>
						{:else}
							<div class="aspect-[3/4] w-full rounded-lg bg-muted/50 flex items-center justify-center">
								<BookOpen class="h-12 w-12 text-muted-foreground/50" />
							</div>
						{/if}
					</div>

					<!-- Metadata + Tags -->
					<div class="flex-1 space-y-3">
						<div>
							<h1 class="text-2xl font-bold leading-tight">{novel.name}</h1>
							{#if novel.author}
								<p class="text-muted-foreground mt-1">
									by
									<a
										href="/novels?author={encodeURIComponent(novel.author.name)}"
										class="text-primary hover:underline"
									>
										{novel.author.name}
									</a>
								</p>
							{/if}
						</div>

						<!-- Badges -->
						<div class="flex flex-wrap gap-2 items-center">
							<Badge class={statusColor}>{statusLabel}</Badge>
							{#if isNsfw}
								<Badge class="bg-red-600 text-white">NSFW</Badge>
							{/if}
							<Badge variant="outline">{languageLabel}</Badge>
							{#if $isAuthenticated}
								<TooltipProvider>
									<Tooltip>
										<TooltipTrigger asChild>
											<Button
												variant="outline"
												size="sm"
												onclick={refreshNovel}
												disabled={refreshing || !canRefresh()}
												class="gap-1.5 h-6 text-xs"
											>
												<RefreshCw class="h-3 w-3 {refreshing ? 'animate-spin' : ''}" />
												{refreshing ? 'Refreshing...' : 'Refresh'}
											</Button>
										</TooltipTrigger>
										{#if !canRefresh()}
											<TooltipContent>
												Updated less than 6 hours ago
											</TooltipContent>
										{/if}
									</Tooltip>
								</TooltipProvider>
								<Button
									variant="destructive"
									size="sm"
									onclick={() => (showDeleteConfirm = true)}
									class="gap-1.5 h-6 text-xs"
								>
									<Trash2 class="h-3 w-3" />
									Delete
								</Button>
							{/if}
							{#if refreshSuccess}
								<Badge variant="outline" class="bg-green-500/10 text-green-600 border-green-500/30">
									Refresh queued
								</Badge>
							{/if}
							{#if refreshError}
								<Badge variant="outline" class="bg-destructive/10 text-destructive border-destructive/30">
									{refreshError}
								</Badge>
							{/if}
						</div>

						<!-- Stats (inline) -->
						<div class="text-sm text-muted-foreground flex flex-wrap gap-x-4 gap-y-1">
							{#if novel.source}
								<span>
									Source:
									<a
										href={novel.url}
										target="_blank"
										rel="noopener noreferrer"
										class="text-primary hover:underline inline-flex items-center gap-1"
									>
										{novel.source.name}
										<ExternalLink class="h-3 w-3" />
									</a>
								</span>
							{/if}
							{#if relativeTime && absoluteTime}
								<span>
									Updated:
									<TooltipProvider>
										<Tooltip>
											<TooltipTrigger class="cursor-default hover:text-foreground transition-colors">
												<time datetime={lastUpdated?.toISOString()}>{relativeTime}</time>
											</TooltipTrigger>
											<TooltipContent>{absoluteTime}</TooltipContent>
										</Tooltip>
									</TooltipProvider>
								</span>
							{/if}
							<span>{chapterCount} chapters</span>
						</div>

						<!-- Tags -->
						{#if displayTags.length > 0}
							<div class="flex flex-wrap gap-1.5 pt-1">
								{#each displayTags as tag (tag.key)}
									<Badge
										variant="secondary"
										href="/novels?tags={tag.key}"
										class="cursor-pointer hover:bg-secondary/80 transition-colors text-xs"
									>
										{tag.displayName}
									</Badge>
								{/each}
							</div>
						{/if}
					</div>
				</div>

				<!-- Description (full width below) -->
				{#if description}
					<div class="border-t px-6 py-4">
						<div class="prose prose-sm dark:prose-invert max-w-none text-muted-foreground">
							{@html truncatedDescriptionHtml}
						</div>
						{#if isDescriptionLong}
							<Button
								variant="ghost"
								size="sm"
								onclick={() => (descriptionExpanded = !descriptionExpanded)}
								class="mt-2 gap-1 -ml-2"
							>
								{#if descriptionExpanded}
									<ChevronUp class="h-4 w-4" />
									Show less
								{:else}
									<ChevronDown class="h-4 w-4" />
									Show more
								{/if}
							</Button>
						{/if}
					</div>
				{/if}
			</CardContent>
		</Card>

		<!-- Tabbed Content -->
		<Card>
			<Tabs bind:value={activeTab} class="w-full">
				<CardHeader class="pb-0">
					<TabsList class="grid w-full grid-cols-3 bg-muted/50 p-1 rounded-lg">
						<TabsTrigger
							value="chapters"
							class="rounded-md data-[state=active]:bg-background data-[state=active]:shadow-sm px-3 py-1.5 text-sm font-medium transition-all"
						>
							Chapters ({chapterCount})
						</TabsTrigger>
						<TabsTrigger
							value="gallery"
							class="rounded-md data-[state=active]:bg-background data-[state=active]:shadow-sm px-3 py-1.5 text-sm font-medium transition-all"
						>
							Gallery ({imageCount})
						</TabsTrigger>
						<TabsTrigger
							value="bookmarks"
							disabled
							class="rounded-md data-[state=active]:bg-background data-[state=active]:shadow-sm px-3 py-1.5 text-sm font-medium transition-all disabled:opacity-50 disabled:cursor-not-allowed"
						>
							Bookmarks
						</TabsTrigger>
					</TabsList>
				</CardHeader>

				<CardContent class="pt-4">
					<TabsContent value="chapters" class="mt-0">
						{#if sortedChapters.length === 0}
							<p class="text-muted-foreground text-sm py-4 text-center">
								No chapters available yet.
							</p>
						{:else}
							<div class="max-h-96 overflow-y-auto -mx-2">
								{#each sortedChapters as chapter (chapter.id)}
									{@const chapterDate = chapter.lastUpdatedTime ? new Date(chapter.lastUpdatedTime) : null}
									<a
										href="/novels/{novelId}/chapters/{chapter.order}"
										class="flex items-center justify-between px-3 py-2.5 hover:bg-muted/50 rounded-md transition-colors group"
									>
										<div class="flex items-center gap-3 min-w-0">
											<span class="text-muted-foreground text-sm font-medium shrink-0 w-14">
												Ch. {chapter.order}
											</span>
											<span class="text-sm truncate group-hover:text-primary transition-colors">
												{chapter.name}
											</span>
										</div>
										{#if chapterDate}
											<span class="text-xs text-muted-foreground/70 shrink-0 ml-2">
												{formatRelativeTime(chapterDate)}
											</span>
										{/if}
									</a>
								{/each}
							</div>
						{/if}
					</TabsContent>

					<TabsContent value="gallery" class="mt-0">
						{#if galleryImages.length === 0}
							<p class="text-muted-foreground text-sm py-4 text-center">
								No images available.
							</p>
						{:else if galleryLoaded}
							<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 gap-2">
								{#each galleryImages as image, index (image.src)}
									<button
										type="button"
										onclick={() => openImageViewer(index)}
										class="relative aspect-square overflow-hidden rounded-md bg-muted/50 hover:ring-2 ring-primary transition-all"
									>
										<img src={image.src} alt={image.alt} class="h-full w-full object-cover" loading="lazy" />
										{#if image.isCover}
											<Badge class="absolute top-1 left-1 text-xs">Cover</Badge>
										{/if}
									</button>
								{/each}
							</div>
						{:else}
							<div class="flex items-center justify-center py-8">
								<div
									class="border-primary h-8 w-8 animate-spin rounded-full border-2 border-t-transparent"
									aria-label="Loading gallery"
								></div>
							</div>
						{/if}
					</TabsContent>

					<TabsContent value="bookmarks" class="mt-0">
						<p class="text-muted-foreground text-sm py-8 text-center">
							Bookmarks coming soon.
						</p>
					</TabsContent>
				</CardContent>
			</Tabs>
		</Card>
	{/if}
</div>

<!-- Image Viewer Modal -->
{#if viewerOpen && currentImage}
	<div
		class="fixed inset-0 z-50 flex items-center justify-center bg-black/90 backdrop-blur-sm"
		onclick={closeViewer}
		onkeydown={handleViewerKeydown}
		role="dialog"
		aria-modal="true"
		tabindex="-1"
	>
		<!-- Close button -->
		<Button
			variant="ghost"
			size="icon"
			class="absolute top-4 right-4 text-white hover:bg-white/10"
			onclick={closeViewer}
		>
			<X class="h-6 w-6" />
		</Button>

		<!-- Navigation arrows -->
		{#if galleryImages.length > 1}
			<Button
				variant="ghost"
				size="icon"
				class="absolute left-4 text-white hover:bg-white/10 h-12 w-12"
				onclick={(e: MouseEvent) => { e.stopPropagation(); prevImage(); }}
			>
				<ChevronLeft class="h-8 w-8" />
			</Button>
			<Button
				variant="ghost"
				size="icon"
				class="absolute right-4 top-1/2 -translate-y-1/2 text-white hover:bg-white/10 h-12 w-12"
				onclick={(e: MouseEvent) => { e.stopPropagation(); nextImage(); }}
			>
				<ChevronRight class="h-8 w-8" />
			</Button>
		{/if}

		<!-- Image container -->
		<!-- svelte-ignore a11y_click_events_have_key_events -->
		<!-- svelte-ignore a11y_no_static_element_interactions -->
		<div class="flex flex-col items-center max-w-[90vw] max-h-[90vh]" onclick={(e: MouseEvent) => e.stopPropagation()}>
			<img
				src={currentImage.src}
				alt={currentImage.alt}
				class="max-w-full max-h-[80vh] object-contain rounded-lg"
			/>

			<!-- Chapter link (if not cover) -->
			{#if !currentImage.isCover && currentImage.chapterOrder}
				<a
					href="/novels/{novelId}/chapters/{currentImage.chapterOrder}"
					class="text-white/80 hover:text-white text-sm inline-flex items-center gap-1 mt-3"
				>
					From: Ch. {currentImage.chapterOrder} - {currentImage.chapterName}
					<ExternalLink class="h-3 w-3" />
				</a>
			{/if}

			<!-- Image counter -->
			<div class="text-white/60 text-sm mt-2">
				{viewerIndex + 1} / {galleryImages.length}
			</div>
		</div>
	</div>
{/if}

<!-- Delete Confirmation Modal -->
{#if showDeleteConfirm && novel}
	<div
		class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm"
		onclick={() => !deleting && (showDeleteConfirm = false)}
		onkeydown={(e) => e.key === 'Escape' && !deleting && (showDeleteConfirm = false)}
		role="dialog"
		aria-modal="true"
		aria-labelledby="delete-modal-title"
		tabindex="-1"
	>
		<!-- svelte-ignore a11y_click_events_have_key_events -->
		<!-- svelte-ignore a11y_no_static_element_interactions -->
		<div onclick={(e: MouseEvent) => e.stopPropagation()}>
			<Card class="w-full max-w-md mx-4 shadow-xl">
				<CardHeader>
					<h2 id="delete-modal-title" class="text-lg font-semibold">Delete Novel</h2>
				</CardHeader>
				<CardContent class="space-y-4">
					<p class="text-muted-foreground">
						Are you sure you want to delete <strong class="text-foreground">{novel.name}</strong>?
					</p>
					<p class="text-sm text-muted-foreground">
						This will permanently delete the novel, all chapters, images, and translations. This action cannot be undone.
					</p>
					{#if deleteError}
						<p class="text-sm text-destructive">{deleteError}</p>
					{/if}
					<div class="flex justify-end gap-2 pt-2">
						<Button
							variant="outline"
							onclick={() => (showDeleteConfirm = false)}
							disabled={deleting}
						>
							Cancel
						</Button>
						<Button
							variant="destructive"
							onclick={deleteNovel}
							disabled={deleting}
						>
							{deleting ? 'Deleting...' : 'Delete'}
						</Button>
					</div>
				</CardContent>
			</Card>
		</div>
	</div>
{/if}
