<script lang="ts">
	import type { Snippet } from 'svelte';
	import type { LibraryController } from '$lib/utils/libraryController.svelte';
	import AlbumImage from '$lib/components/AlbumImage.svelte';
	import ContextMenu from '$lib/components/ContextMenu.svelte';
	import AddToPlaylistModal from '$lib/components/AddToPlaylistModal.svelte';
	import SourceAlbumModal from '$lib/components/SourceAlbumModal.svelte';
	import LibraryFilterBar from '$lib/components/LibraryFilterBar.svelte';
	import { CircleX, Play, Shuffle } from 'lucide-svelte';
	import { onMount, onDestroy } from 'svelte';

	/* eslint-disable @typescript-eslint/no-explicit-any */
	interface Props {
		ctrl: LibraryController<any>;
		headerIcon: Snippet;
		headerTitle: string;
		recentLabel?: string;
		statsPanel?: Snippet;
		recentCardOverlay?: Snippet<[any]>;
		cardTopLeftBadge: Snippet<[any]>;
		cardTopRightExtra?: Snippet<[any]>;
		cardBottomLeft?: Snippet<[any]>;
		cardBodyExtra?: Snippet<[any]>;
		contextMenuBackdrop?: boolean;
		emptyIcon: Snippet;
		emptyTitle: string;
		emptyDescription: string;
	}
	/* eslint-enable @typescript-eslint/no-explicit-any */

	let {
		ctrl,
		headerIcon,
		headerTitle,
		recentLabel = 'Recently Played',
		statsPanel,
		recentCardOverlay,
		cardTopLeftBadge,
		cardTopRightExtra,
		cardBottomLeft,
		cardBodyExtra,
		contextMenuBackdrop = false,
		emptyIcon,
		emptyTitle,
		emptyDescription
	}: Props = $props();

	const a = ctrl.adapter;

	onMount(() => ctrl.init());
	onDestroy(() => ctrl.cleanup());
</script>

<div class="container mx-auto p-6">
	<div class="flex items-center gap-3 mb-2">
		{@render headerIcon()}
		<h1 class="text-2xl font-bold">{headerTitle}</h1>
		{#if ctrl.stats}
			<span class="badge badge-neutral"
				>{(ctrl.stats as { total_albums?: number }).total_albums ?? 0} albums</span
			>
		{/if}
	</div>

	{#if statsPanel}
		{@render statsPanel()}
	{/if}

	{#if ctrl.recentAlbums.length > 0}
		<div class="mb-8">
			<h2 class="text-lg font-semibold mb-3 opacity-80">{recentLabel}</h2>
			<div class="flex gap-3 overflow-x-auto pb-2">
				{#each ctrl.recentAlbums as album (a.getAlbumId(album))}
					<button
						class="flex-shrink-0 w-36 group cursor-pointer transition-transform hover:scale-105 active:scale-95"
						onclick={() => ctrl.openDetail(album)}
					>
						<div class="aspect-square rounded-lg overflow-hidden shadow-sm relative">
							<AlbumImage
								mbid={a.getAlbumMbid(album) ?? String(a.getAlbumId(album))}
								customUrl={a.getAlbumImageUrl(album)}
								alt={a.getAlbumName(album)}
								size="full"
								rounded="none"
								className="w-full h-full"
							/>
							{#if recentCardOverlay}
								{@render recentCardOverlay(album)}
							{/if}
						</div>
						<p class="text-sm font-medium mt-1 line-clamp-1">{a.getAlbumName(album)}</p>
						<p class="text-xs opacity-60 line-clamp-1">{a.getArtistName(album)}</p>
					</button>
				{/each}
			</div>
		</div>
	{/if}

	{#if a.supportsFavorites && ctrl.favoriteAlbums.length > 0}
		<div class="mb-8">
			<h2 class="text-lg font-semibold mb-3 opacity-80">Favorites</h2>
			<div class="flex gap-3 overflow-x-auto pb-2">
				{#each ctrl.favoriteAlbums as album (a.getAlbumId(album))}
					<button
						class="flex-shrink-0 w-36 group cursor-pointer transition-transform hover:scale-105 active:scale-95"
						onclick={() => ctrl.openDetail(album)}
					>
						<div class="aspect-square rounded-lg overflow-hidden shadow-sm">
							<AlbumImage
								mbid={a.getAlbumMbid(album) ?? String(a.getAlbumId(album))}
								customUrl={a.getAlbumImageUrl(album)}
								alt={a.getAlbumName(album)}
								size="full"
								rounded="none"
								className="w-full h-full"
							/>
						</div>
						<p class="text-sm font-medium mt-1 line-clamp-1">{a.getAlbumName(album)}</p>
						<p class="text-xs opacity-60 line-clamp-1">{a.getArtistName(album)}</p>
					</button>
				{/each}
			</div>
		</div>
	{/if}

	<div class="mb-6">
		<h2 class="text-lg font-semibold mb-3 opacity-80">All Albums</h2>
		<LibraryFilterBar
			bind:searchQuery={ctrl.searchQuery}
			onSearchInput={ctrl.handleSearch}
			sortOptions={a.sortOptions}
			sortBy={ctrl.sortBy}
			onSortChange={ctrl.handleSortChange}
			sortOrder={ctrl.sortOrder}
			onToggleSortOrder={ctrl.toggleSortOrder}
			ascValue={a.ascValue}
			genres={a.supportsGenres ? ctrl.genres : undefined}
			selectedGenre={a.supportsGenres ? ctrl.selectedGenre : undefined}
			onGenreChange={a.supportsGenres ? ctrl.handleGenreChange : undefined}
			resultCount={ctrl.loading ? null : ctrl.total}
			loading={ctrl.loading}
		/>
	</div>

	{#if ctrl.fetchError}
		<div role="alert" class="alert alert-error alert-soft mb-4">
			<CircleX class="h-6 w-6 shrink-0" />
			<div class="flex flex-col gap-1">
				<span>{ctrl.fetchError}</span>
				{#if ctrl.fetchErrorCode === 'CIRCUIT_BREAKER_OPEN' || /connection|DNS|not configured/i.test(ctrl.fetchError)}
					<a href="/settings" class="link link-primary text-sm">Check your settings →</a>
				{/if}
			</div>
			<button class="btn btn-sm btn-ghost" onclick={() => ctrl.fetchAlbums(true)}>Retry</button>
		</div>
	{/if}

	{#if ctrl.loading}
		<div
			class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-4"
		>
			{#each Array(12) as _}
				<div class="card bg-base-100 shadow-sm animate-pulse">
					<div class="aspect-square bg-base-300"></div>
					<div class="card-body p-3">
						<div class="h-4 bg-base-300 rounded w-3/4"></div>
						<div class="h-3 bg-base-300 rounded w-1/2 mt-1"></div>
					</div>
				</div>
			{/each}
		</div>
	{:else}
		<div
			class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-4"
		>
			{#each ctrl.albums as album (a.getAlbumId(album))}
				<div
					class="card bg-base-100 w-full shadow-sm group relative cursor-pointer transition-transform hover:scale-105 hover:shadow-lg active:scale-95"
					onclick={() => ctrl.openDetail(album)}
					onkeydown={(e) =>
						(e.key === 'Enter' || e.key === ' ') &&
						(e.preventDefault(), ctrl.openDetail(album))}
					role="button"
					tabindex="0"
				>
					<figure class="aspect-square overflow-hidden relative">
						<AlbumImage
							mbid={a.getAlbumMbid(album) ?? String(a.getAlbumId(album))}
							customUrl={a.getAlbumImageUrl(album)}
							alt={a.getAlbumName(album)}
							size="full"
							rounded="none"
							className="w-full h-full"
						/>
						<div class="absolute top-2 left-2 flex items-center gap-1">
							{@render cardTopLeftBadge(album)}
						</div>
						<div class="absolute top-2 right-2 flex items-start gap-1">
							{#if cardTopRightExtra}
								{@render cardTopRightExtra(album)}
							{:else if a.getAlbumYear(album)}
								<div class="badge badge-sm badge-ghost">{a.getAlbumYear(album)}</div>
							{/if}
							{#if contextMenuBackdrop}
								<div class="rounded-full bg-black/50 backdrop-blur-sm">
									<ContextMenu
										items={ctrl.getAlbumMenuItems(album)}
										position="end"
										size="xs"
									/>
								</div>
							{:else}
								<div>
									<ContextMenu
										items={ctrl.getAlbumMenuItems(album)}
										position="end"
										size="xs"
									/>
								</div>
							{/if}
						</div>
						{#if cardBottomLeft}
							<div class="absolute bottom-2 left-2">
								{@render cardBottomLeft(album)}
							</div>
						{/if}
						<div
							class="absolute bottom-2 right-2 flex items-center gap-1.5 opacity-0 group-hover:opacity-100 transition-opacity"
						>
							{#if a.supportsShuffle}
								<button
									class="btn btn-circle btn-sm btn-ghost bg-black/50 backdrop-blur-sm text-white shadow-md hover:bg-black/70"
									onclick={(e) => ctrl.quickShuffle(album, e)}
									aria-label="Shuffle {a.getAlbumName(album)}"
								>
									<Shuffle class="h-3.5 w-3.5" />
								</button>
							{/if}
							<button
								class="btn btn-circle btn-sm btn-primary shadow-md"
								onclick={(e) => ctrl.quickPlay(album, e)}
								aria-label="Play {a.getAlbumName(album)}"
							>
								{#if ctrl.playingAlbumId === a.getAlbumId(album)}
									<span class="loading loading-spinner loading-xs"></span>
								{:else}
									<Play class="h-4 w-4 fill-current" />
								{/if}
							</button>
						</div>
					</figure>

					<div class="card-body p-3">
						<h2 class="card-title text-sm line-clamp-2 min-h-[2.5rem]">
							{a.getAlbumName(album)}
						</h2>
						{#if cardBodyExtra}
							{@render cardBodyExtra(album)}
						{:else}
							<p class="text-xs opacity-70 line-clamp-1">{a.getArtistName(album)}</p>
						{/if}
					</div>
				</div>
			{/each}
		</div>

		{#if ctrl.albums.length === 0}
			<div class="card bg-base-200 mt-4">
				<div class="card-body items-center text-center">
					{@render emptyIcon()}
					<p class="text-lg opacity-60">{emptyTitle}</p>
					<p class="text-sm opacity-40">{emptyDescription}</p>
				</div>
			</div>
		{/if}

		{#if ctrl.albums.length < ctrl.total}
			<div class="flex justify-center mt-6">
				<button class="btn btn-ghost" onclick={ctrl.loadMore} disabled={ctrl.loadingMore}>
					{#if ctrl.loadingMore}
						<span class="loading loading-spinner loading-sm"></span>
					{/if}
					Load More
				</button>
			</div>
		{/if}
	{/if}
</div>

<AddToPlaylistModal bind:this={ctrl.playlistModalRef} />

<SourceAlbumModal
	bind:open={ctrl.detailModalOpen}
	sourceType={a.sourceType}
	album={ctrl.selectedAlbum}
	onclose={ctrl.handleDetailClose}
/>
