<script lang="ts">
	import {
		Download,
		GripVertical,
		LocateFixed,
		Play,
		Upload,
		X,
	} from "@lucide/svelte";
	import { tick } from "svelte";
	import { z } from "zod";
	import * as AlertDialog from "$lib/components/ui/alert-dialog";
	import { Button } from "$lib/components/ui/button";
	import VirtualList from "$lib/components/ui/VirtualList.svelte";
	import { trackSchema } from "$lib/player/persist";
	import { player } from "$lib/player/store.svelte";
	import type { Track } from "$lib/player/types";
	import { songTypeNumberLabel } from "$lib/utils/amq";

	let { visible = true }: { visible?: boolean } = $props();

	let virtualList: ReturnType<typeof VirtualList>;

	function scrollToCurrentlyPlaying() {
		if (player.currentId == null) return;
		const index = player.displayQueue.findIndex(
			(t) => t.id === player.currentId,
		);
		if (index !== -1) virtualList?.scrollToIndex(index);
	}

	$effect(() => {
		if (visible) {
			tick().then(() => scrollToCurrentlyPlaying());
		}
	});

	const ITEM_HEIGHT = 64;

	function onRemove(id: number) {
		player.remove(id);
	}

	function onJump(track: Track) {
		player.playId(track.id);
	}

	let dragOverIndex = $state<number | null>(null);

	function onDragStart(e: DragEvent, index: number) {
		if (!e.dataTransfer) return;
		e.dataTransfer.effectAllowed = "move";
		e.dataTransfer.setData("text/plain", index.toString());
	}

	function onDragOver(e: DragEvent, index: number) {
		e.preventDefault();
		if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
		dragOverIndex = index;
	}

	function onDrop(e: DragEvent, toIndex: number) {
		e.preventDefault();
		dragOverIndex = null;
		const fromIndexStr = e.dataTransfer?.getData("text/plain");
		if (fromIndexStr) {
			const fromIndex = parseInt(fromIndexStr, 10);
			player.move(fromIndex, toIndex);
		}
	}

	function exportQueue() {
		const dataStr = JSON.stringify(player.queue, null, 2);
		const dataUri =
			"data:application/json;charset=utf-8," + encodeURIComponent(dataStr);
		const exportFileDefaultName = "amq-queue.json";

		const linkElement = document.createElement("a");
		linkElement.setAttribute("href", dataUri);
		linkElement.setAttribute("download", exportFileDefaultName);
		linkElement.click();
	}

	let fileInput: HTMLInputElement;

	function importQueue(e: Event) {
		const input = e.target as HTMLInputElement;
		if (!input.files?.length) return;

		const file = input.files[0];
		const reader = new FileReader();

		reader.onload = (event) => {
			try {
				const content = event.target?.result as string;
				const parsed = JSON.parse(content);
				const result = z.array(trackSchema).safeParse(parsed);

				if (result.success) {
					player.clearQueue();
					player.isShuffled = false;
					player.repeatMode = "off";
					player.addAll(result.data);
				} else {
					console.error("Invalid queue format", result.error);
					alert("Failed to import: Invalid queue format.");
				}
			} catch (err) {
				console.error("Error reading file", err);
				alert("Failed to read file.");
			}

			// Reset input so the same file can be selected again
			input.value = "";
		};

		reader.readAsText(file);
	}
</script>

<div
	class="flex flex-col h-full w-full bg-background/50 backdrop-blur rounded-lg border overflow-hidden"
>
	<div
		class="px-4 py-3 border-b flex text-sm items-center justify-between bg-muted/20"
	>
		<div class="flex items-center gap-1">
			<h3 class="font-semibold">Up Next</h3>
			{#if player.displayQueue.length > 0}
				<span class="text-muted-foreground font-normal ml-1"
					>({player.displayQueue.length})</span
				>
				<Button
					variant="ghost"
					size="sm"
					class="h-6 w-6 p-0"
					aria-label="Scroll to currently playing"
					onclick={scrollToCurrentlyPlaying}
				>
					<LocateFixed class="h-3 w-3" />
				</Button>
			{/if}
		</div>
		<div class="flex items-center gap-1 text-muted-foreground pl-2">
			<input
				type="file"
				accept=".json"
				bind:this={fileInput}
				onchange={importQueue}
				class="hidden"
			/>
			<Button
				variant="ghost"
				size="sm"
				class="h-6 w-6 p-0"
				aria-label="Import Queue"
				onclick={() => fileInput?.click()}
				title="Import Queue"
			>
				<Upload class="h-3 w-3" />
			</Button>
			<Button
				variant="ghost"
				size="sm"
				class="h-6 w-6 p-0"
				aria-label="Export Queue"
				onclick={exportQueue}
				disabled={player.queue.length === 0}
				title="Export Queue"
			>
				<Download class="h-3 w-3" />
			</Button>
			<AlertDialog.Root>
				<AlertDialog.Trigger>
					{#snippet child({ props })}
						<Button
							variant="ghost"
							size="sm"
							class="h-6 w-6 p-0"
							{...props}
							title="Clear Queue"
						>
							<X class="h-3 w-3" aria-label="Clear" />
						</Button>
					{/snippet}
				</AlertDialog.Trigger>
				<AlertDialog.Content>
					<AlertDialog.Header>
						<AlertDialog.Title>Clear queue?</AlertDialog.Title>
						<AlertDialog.Description>
							This will remove all {player.displayQueue.length} songs from the queue.
						</AlertDialog.Description>
					</AlertDialog.Header>
					<AlertDialog.Footer>
						<AlertDialog.Cancel>Cancel</AlertDialog.Cancel>
						<AlertDialog.Action onclick={() => player.clearQueue()}
							>Clear</AlertDialog.Action
						>
					</AlertDialog.Footer>
				</AlertDialog.Content>
			</AlertDialog.Root>
		</div>
	</div>

	<VirtualList
		bind:this={virtualList}
		items={player.displayQueue}
		itemHeight={ITEM_HEIGHT}
		overscan={5}
		class="p-2"
		key={(track) => track.id}
	>
		{#snippet row({ item: track, index: i })}
			<div
				role="button"
				tabindex="0"
				draggable="true"
				ondragstart={(e) => onDragStart(e, i)}
				ondragover={(e) => onDragOver(e, i)}
				ondrop={(e) => onDrop(e, i)}
				onclick={() => onJump(track)}
				onkeydown={(e) => e.key === "Enter" && onJump(track)}
				class="group flex items-center gap-2 px-3 h-full rounded-md hover:bg-muted/50 transition-colors cursor-pointer text-sm"
				class:active={player.currentId === track.id}
				class:border-t-2={dragOverIndex === i}
				class:border-primary={dragOverIndex === i}
			>
				<div
					class="w-6 shrink-0 flex items-center justify-center text-xs text-muted-foreground/60 font-mono"
				>
					<div
						class="group-hover:hidden flex items-center justify-center w-full h-full"
					>
						{#if player.currentId === track.id}
							<div class="w-2 h-2 bg-primary rounded-full animate-pulse"></div>
						{:else}
							<span>{i + 1}</span>
						{/if}
					</div>

					<div
						class="[@media(hover:hover)]:hidden group-hover:flex items-center justify-center w-full h-full cursor-grab active:cursor-grabbing text-muted-foreground/50 hover:text-foreground"
						aria-label="Drag to reorder"
					>
						<GripVertical class="h-4 w-4" />
					</div>
				</div>

				<div class="flex-1 min-w-0">
					<div
						class="font-medium line-clamp-2 leading-tight"
						class:text-primary={player.currentId === track.id}
					>
						{track.animeName}
						<span class="tag"
							>{songTypeNumberLabel(track.type, track.number)}</span
						>
						<span class="text-muted-foreground font-normal"
							>{track.globalPercent}%</span
						>
					</div>
					<div class="text-xs text-foreground/80 truncate">
						{track.title} —
						<span class="text-muted-foreground">{track.artist}</span>
					</div>
				</div>

				<Button
					variant="ghost"
					size="icon"
					class="h-6 w-6 opacity-50 group-hover:opacity-100 transition-opacity shrink-0"
					onclick={(e) => {
						e.stopPropagation();
						onRemove(track.id);
					}}
				>
					<X class="h-3 w-3" />
				</Button>
			</div>
		{/snippet}

		{#snippet empty()}
			<div class="text-center py-8 text-muted-foreground text-sm">
				Queue is empty
			</div>
		{/snippet}
	</VirtualList>
</div>

<style>
	@reference "../../../routes/layout.css";
	.active {
		@apply bg-muted/40;
	}
</style>
