<script lang="ts">
	import {
		queue,
		goto,
		select,
		clearSel,
		moveHead,
		reorder,
		remove,
		settings,
		toggleStar,
		setRating,
		formatTime,
		playNext,
		moveUp,
		moveDown,
		starSelected,
		rateSelected,
		selectAll,
		moveSelected,
		nav,
		getSortItems,
		t,
	} from "./app.svelte.js";
	import { api } from "./client.svelte.js";
	import { ui } from "./app.svelte.js";
	import ContextMenu from "./ContextMenu.svelte";
	import VirtualList from "./VirtualList.svelte";

	let menu = $state<{ x: number; y: number; index: number } | null>(null),
		drag = $state<{ index: number; isAfter: boolean } | null>(null),
		scrollToIndex = $state<(i: number) => void>();

	$effect(() => {
		if (nav.head >= 0) scrollToIndex?.(nav.head);
	});

	function onDragStart(e: DragEvent, index: number) {
		if (!queue.sel.includes(index)) select(index);
		e.dataTransfer!.effectAllowed = "move";
	}

	function onDragOver(e: DragEvent, index: number) {
		e.preventDefault();
		const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
		drag = { index, isAfter: e.clientY > rect.top + rect.height / 2 };
	}

	function onDrop() {
		if (drag) moveSelected(drag.index + (drag.isAfter ? 1 : 0));
		drag = null;
	}

	function onKey(e: KeyboardEvent) {
		if ((e.target as HTMLElement).tagName === "INPUT") return;
		const key = e.key,
			shift = e.shiftKey,
			alt = e.altKey;
		if (e.ctrlKey || e.metaKey) {
			if (key === "a") {
				e.preventDefault();
				selectAll();
			}
			return;
		}

		const moves: Record<string, () => void> = {
			ArrowUp: () => (alt ? reorder(-1) : moveHead(-1, shift)),
			ArrowDown: () => (alt ? reorder(1) : moveHead(1, shift)),
			Home: () => select(0, false, shift),
			End: () => select(queue.tracks.length - 1, false, shift),
			PageUp: () => moveHead(-10, shift),
			PageDown: () => moveHead(10, shift),
			Enter: () => queue.sel.length && goto(queue.sel[0]),
			Delete: remove,
			Backspace: remove,
			Escape: clearSel,
			ContextMenu: () => showMenu(nav.head),
			"`": () => showMenu(nav.head),
			F10: () => e.shiftKey && showMenu(nav.head),
		};

		if (moves[key]) {
			e.preventDefault();
			moves[key]();
		}
	}

	function showMenu(index: number) {
		if (index < 0) return;
		if (!queue.sel.includes(index)) select(index);
		// Find the row element to position the menu
		const row = document.querySelector(`[data-id="queue-row-${index}"]`);
		if (row) {
			const rect = row.getBoundingClientRect();
			menu = { x: rect.left + 50, y: rect.bottom, index };
		} else {
			// Fallback to a central-ish position if row not found (e.g. virtualized out)
			menu = { x: window.innerWidth / 2, y: window.innerHeight / 3, index };
		}
	}
</script>

<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<div
	id="queue"
	style="grid-area: queue"
	onclick={clearSel}
	onkeydown={onKey}
	onfocusin={() => (ui.activeContext = "queue")}
	tabindex="0"
>
	<div class="head">
		{#if settings.artSong > 0}<div
				style="inline-size: {settings.artSong}px;"
			></div>{/if}
		<div class="col">{t("title")}</div>
		{#if settings.enableArtist}<div class="col">{t("artist")}</div>{/if}
		{#if settings.enableAlbum}<div class="col">{t("album")}</div>{/if}
		{#if settings.enableQuality}<div class="col-num">{t("quality")}</div>{/if}
		{#if settings.enableDuration}<div class="col-num">{t("time")}</div>{/if}
		{#if settings.enableDisc}<div class="col-num">{t("disc")}</div>{/if}
		{#if settings.enableTrackNum}<div class="col-num">{t("track")}</div>{/if}
		{#if settings.enableQueueNum}<div class="col-num">{t("queue")}</div>{/if}
		{#if settings.enableFavorites}<div class="col-fav">♥</div>{/if}
		{#if settings.enableRatings}<div class="col-rate">{t("rating")}</div>{/if}
		<div class="col-touch"></div>
	</div>

	<div class="body">
		<VirtualList
			items={queue.tracks}
			itemHeight={Math.max(18, settings.artSong + 2)}
			// +2 for 1px padding top and bottom around icon
			bind:scrollToIndex
		>
			{#snippet children(track, index)}
				<!-- svelte-ignore a11y_click_events_have_key_events -->
				<div
					class="row"
					data-id="queue-row-{index}"
					class:playing={queue.pos === index}
					class:selected={queue.sel.includes(index)}
					class:odd={index % 2 !== 0}
					class:over-a={drag?.index === index && !drag.isAfter}
					class:over-b={drag?.index === index && drag.isAfter}
					style="block-size: {Math.max(18, settings.artSong + 2)}px;"
					// +2 for 1px padding top and bottom around icon
					draggable={true}
					ondragstart={(e) => onDragStart(e, index)}
					ondragover={(e) => onDragOver(e, index)}
					ondrop={onDrop}
					ondragend={() => (drag = null)}
					onclick={(e) => {
						e.stopPropagation();
						select(index, e.ctrlKey || e.metaKey, e.shiftKey);
					}}
					ondblclick={() => {
						goto(index);
						clearSel();
					}}
					oncontextmenu={(e) => {
						e.preventDefault();
						if (!queue.sel.includes(index)) select(index);
						menu = { x: e.clientX, y: e.clientY, index };
					}}
				>
					{#if settings.artSong > 0}
						{@const artId = track.albumId || track.coverArt || track.id}
						<div class="col-art" style="inline-size: {settings.artSong}px;">
							<img
								class="art"
								src={api.art(artId, settings.artSong)}
								srcset="{api.art(artId, settings.artSong)} 1x, {api.art(
									artId,
									settings.artSong * 2,
								)} 2x"
								style="inline-size: {settings.artSong}px; block-size: {settings.artSong}px;"
								alt=""
								loading="lazy"
							/>
						</div>
					{/if}
					<div class="col">{track.title}</div>
					{#if settings.enableArtist}<div class="col">{track.artist}</div>{/if}
					{#if settings.enableAlbum}<div class="col">{track.album}</div>{/if}
					{#if settings.enableQuality}
						<div class="col-num">
							{track.suffix || ""}{#if track.suffix && track.bitRate}
								{" "}{/if}{track.bitRate || ""}
						</div>
					{/if}
					{#if settings.enableDuration}
						<div class="col-num">{formatTime(track.duration)}</div>
					{/if}
					{#if settings.enableDisc}<div class="col-num">
							{track.discNumber || ""}
						</div>{/if}
					{#if settings.enableTrackNum}<div class="col-num">
							{track.track || ""}
						</div>{/if}
					{#if settings.enableQueueNum}<div class="col-num">
							{index + 1}
						</div>{/if}
					{#if settings.enableFavorites}
						<div class="col-fav">
							<button
								tabindex="-1"
								class="btn-fav"
								class:active={track.starred}
								onclick={(e) => {
									e.stopPropagation();
									toggleStar(track);
								}}
							>
								♥
							</button>
						</div>
					{/if}
					{#if settings.enableRatings}
						<div class="col-rate">
							{#each [1, 2, 3, 4, 5] as rating}
								<button
									tabindex="-1"
									class="btn-rate"
									class:active={track.userRating >= rating}
									onclick={(e) => {
										e.stopPropagation();
										setRating(track, track.userRating === rating ? 0 : rating);
									}}
								>
									★
								</button>
							{/each}
						</div>
					{/if}
					<div class="col-touch">
						<button
							tabindex="-1"
							class="btn-touch"
							onclick={(e) => {
								e.stopPropagation();
								if (!queue.sel.includes(index)) select(index);
								reorder(-1);
							}}
							title={t("move_up")}
						>
							▲
						</button>
						<button
							tabindex="-1"
							class="btn-touch"
							onclick={(e) => {
								e.stopPropagation();
								if (!queue.sel.includes(index)) select(index);
								reorder(1);
							}}
							title={t("move_down")}
						>
							▼
						</button>
						<button
							tabindex="-1"
							class="btn-touch"
							onclick={(e) => {
								e.stopPropagation();
								goto(index);
								clearSel();
							}}
							title={t("play")}
						>
							▶
						</button>
					</div>
				</div>
			{/snippet}
		</VirtualList>
	</div>
</div>

{#if menu}
	<ContextMenu
		x={menu.x}
		y={menu.y}
		onclose={() => (menu = null)}
		items={[
			{ label: t("play"), action: () => goto(menu!.index) },
			{ label: t("play_next"), action: playNext },
			{
				label: t("sort"),
				items: getSortItems(),
			},
			{ label: t("favorite"), action: () => starSelected(true) },
			{ label: t("unfavorite"), action: () => starSelected(false) },
			{
				label: t("rating"),
				items: [
					{ label: "★★★★★", action: () => rateSelected(5) },
					{ label: "★★★★", action: () => rateSelected(4) },
					{ label: "★★★", action: () => rateSelected(3) },
					{ label: "★★", action: () => rateSelected(2) },
					{ label: "★", action: () => rateSelected(1) },
					{ label: t("none"), action: () => rateSelected(0) },
				],
			},
			{ label: t("move_up"), action: moveUp },
			{ label: t("move_down"), action: moveDown },
			{
				label: t("clear"),
				action: remove,
			},
		]}
	/>
{/if}

<style>
	#queue {
		display: flex;
		flex-direction: column;
		overflow: hidden;
		padding-block-start: 0.5rem;
	}
	.body {
		flex: 1;
		overflow: hidden;
	}
	.head {
		font-weight: bold;
		color: inherit;
		padding-inline: 1rem;
	}
	.head,
	.row {
		display: flex;
		align-items: center;
	}
	.col {
		flex: 1;
		padding-inline: 0.5rem;
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}
	.col-num {
		inline-size: 6rem;
		text-align: end;
	}
	.col-fav {
		inline-size: 2rem;
		text-align: end;
	}
	.col-rate {
		inline-size: 6rem;
		text-align: end;
	}
	.col-art {
		display: flex;
		justify-content: center;
	}
	.row.odd {
		background: var(--bg-row);
	}
	.row.playing {
		background: var(--playing);
	}
	.row.selected {
		background: Highlight;
		color: HighlightText;
	}
	#queue:not(:focus-within) .row.selected {
		background: GrayText;
		color: HighlightText;
	}
	.row.over-a {
		box-shadow: inset 0 2px 0 var(--text);
	}
	.row.over-b {
		box-shadow: inset 0 -2px 0 var(--text);
	}
	.btn-fav,
	.btn-rate {
		background: none;
		border: none;
		padding: 0;
		opacity: 0.25;
	}
	.btn-rate {
		transform: scale(0.75);
	}
	.btn-fav.active {
		color: #ff0008;
		opacity: 1;
	}
	.btn-rate.active {
		color: #ffd700;
		opacity: 1;
		transform: scale(1);
	}
	.btn-fav:hover,
	.btn-rate:hover {
		opacity: 0.75;
	}
	.col-touch {
		display: none;
		inline-size: 6rem;
		justify-content: flex-end;
	}
	@media (pointer: coarse) {
		.col-touch {
			display: flex;
		}
	}
	.btn-touch {
		background: none;
		border: none;
		padding: 0;
		opacity: 0.25;
		font-size: 0.75rem;
		display: flex;
		align-items: center;
		justify-content: center;
		inline-size: 1.5rem;
		block-size: 1rem;
	}
	:global(body.rounded-art) #queue .art,
	:global(body.rounded-art) #queue .row {
		border-radius: 2px;
	}
</style>
