<script lang="ts">
	import { onMount, onDestroy } from 'svelte';
	import { fade, fly } from 'svelte/transition';
	import RequestCard from '$lib/components/RequestCard.svelte';
	import Pagination from '$lib/components/Pagination.svelte';
	import Toast from '$lib/components/Toast.svelte';
	import type { ActiveRequestItem, RequestHistoryItem } from '$lib/types';
	import { TriangleAlert, CheckCircle, Clock, Download, History, Search } from 'lucide-svelte';
	import {
		fetchActiveRequests,
		fetchRequestHistory,
		cancelRequest,
		retryRequest,
		clearHistoryItem,
		notifyRequestCountChanged
	} from '$lib/utils/requestsApi';
	import { requestCountStore } from '$lib/stores/requestCountStore.svelte';
	import { isAbortError } from '$lib/utils/errorHandling';
	import { libraryStore } from '$lib/stores/library';

	let activeTab = $state<'active' | 'history'>('active');

	let activeItems = $state<ActiveRequestItem[]>([]);
	let activeCount = $state(0);
	let prevActiveCount = 0;
	let activeLoading = $state(true);
	let activeError = $state<string | null>(null);

	let historyItems = $state<RequestHistoryItem[]>([]);
	let historyTotal = $state(0);
	let historyPage = $state(1);
	const historyPageSize = 20;
	let historyTotalPages = $state(1);
	let historyLoading = $state(true);
	let historyError = $state<string | null>(null);
	let historyFilter = $state<string | undefined>(undefined);
	let historySort = $state<string | undefined>(undefined);

	let pollInterval: ReturnType<typeof setInterval> | null = null;
	let activeAbortController: AbortController | null = null;
	let historyAbortController: AbortController | null = null;
	let activeRequestId = 0;
	let historyRequestId = 0;
	let toastShow = $state(false);
	let toastMessage = $state('');
	let toastType = $state<'success' | 'error' | 'info'>('success');
	let isPolling = $state(false);

	const downloadingCount = $derived(activeItems.filter((i) => i.status === 'downloading').length);
	const pendingCount = $derived(
		activeItems.filter((i) => i.status === 'pending' || i.status === 'queued').length
	);

	function abortActiveLoad() {
		if (activeAbortController) {
			activeAbortController.abort();
			activeAbortController = null;
		}
	}

	function abortHistoryLoad() {
		if (historyAbortController) {
			historyAbortController.abort();
			historyAbortController = null;
		}
	}

	function showToast(message: string, type: 'success' | 'error' | 'info' = 'success') {
		toastMessage = message;
		toastType = type;
		toastShow = true;
	}

	async function loadActive() {
		const requestId = ++activeRequestId;
		abortActiveLoad();
		const controller = new AbortController();
		activeAbortController = controller;
		isPolling = true;
		try {
			const data = await fetchActiveRequests(controller.signal);
			if (controller.signal.aborted || requestId !== activeRequestId) {
				return;
			}
			activeItems = data.items;
			activeCount = data.count;
			notifyRequestCountChanged(activeCount);
			if (prevActiveCount > 0 && data.count < prevActiveCount) {
				libraryStore.refresh();
			}
			prevActiveCount = data.count;
			activeError = null;
		} catch (e) {
			if (isAbortError(e)) {
				return;
			}
			activeError = "Couldn't load active requests";
		} finally {
			if (!controller.signal.aborted && requestId === activeRequestId) {
				activeLoading = false;
			}
			if (activeAbortController === controller) {
				activeAbortController = null;
			}
			setTimeout(() => {
				isPolling = false;
			}, 500);
		}
	}

	async function loadHistory() {
		const requestId = ++historyRequestId;
		abortHistoryLoad();
		const controller = new AbortController();
		historyAbortController = controller;
		historyLoading = true;
		try {
			const data = await fetchRequestHistory(
				historyPage,
				historyPageSize,
				historyFilter,
				controller.signal,
				historySort
			);
			if (controller.signal.aborted || requestId !== historyRequestId) {
				return;
			}
			historyItems = data.items;
			historyTotal = data.total;
			historyTotalPages = data.total_pages;
			historyError = null;
		} catch (e) {
			if (isAbortError(e)) {
				return;
			}
			historyError = "Couldn't load request history";
		} finally {
			if (!controller.signal.aborted && requestId === historyRequestId) {
				historyLoading = false;
			}
			if (historyAbortController === controller) {
				historyAbortController = null;
			}
		}
	}

	function startPolling() {
		stopPolling();
		void loadActive();
		pollInterval = setInterval(loadActive, 5000);
	}

	function stopPolling() {
		if (pollInterval) {
			clearInterval(pollInterval);
			pollInterval = null;
		}
		abortActiveLoad();
	}

	function handleVisibility() {
		if (document.hidden) {
			stopPolling();
		} else if (activeTab === 'active') {
			startPolling();
		}
	}

	function switchTab(tab: 'active' | 'history') {
		activeTab = tab;
		if (tab === 'active') {
			abortHistoryLoad();
			startPolling();
		} else {
			stopPolling();
			void loadHistory();
		}
	}

	async function handleCancel(mbid: string) {
		try {
			const result = await cancelRequest(mbid);
			if (result.success) {
				showToast(result.message);
				activeItems = activeItems.filter((i) => i.musicbrainz_id !== mbid);
				activeCount = activeItems.length;
				notifyRequestCountChanged(activeCount);
			} else {
				showToast(result.message, 'error');
			}
		} catch {
			showToast("Couldn't cancel that request", 'error');
		}
	}

	async function handleRetry(mbid: string) {
		try {
			const result = await retryRequest(mbid);
			if (result.success) {
				showToast(result.message);
				await Promise.all([loadHistory(), loadActive()]);
			} else {
				showToast(result.message, 'error');
			}
		} catch {
			showToast("Couldn't retry that request", 'error');
		}
	}

	async function handleClear(mbid: string) {
		try {
			const result = await clearHistoryItem(mbid);
			if (result.success) {
				showToast('Removed from history');
				historyItems = historyItems.filter((i) => i.musicbrainz_id !== mbid);
				historyTotal = Math.max(0, historyTotal - 1);
			} else {
				showToast("Couldn't remove that item", 'error');
			}
		} catch {
			showToast("Couldn't remove that item from history", 'error');
		}
	}

	function handleRemoved() {
		void loadHistory();
	}

	function handleHistoryPageChange(page: number) {
		historyPage = page;
		void loadHistory();
	}

	function handleFilterChange(e: Event) {
		const value = (e.target as HTMLSelectElement).value;
		historyFilter = value || undefined;
		historyPage = 1;
		void loadHistory();
	}

	function handleSortChange(e: Event) {
		const value = (e.target as HTMLSelectElement).value;
		historySort = value || undefined;
		historyPage = 1;
		void loadHistory();
	}

	onMount(() => {
		startPolling();
		document.addEventListener('visibilitychange', handleVisibility);
		requestCountStore.setPageActive(true);
	});

	onDestroy(() => {
		stopPolling();
		abortActiveLoad();
		abortHistoryLoad();
		document.removeEventListener('visibilitychange', handleVisibility);
		requestCountStore.setPageActive(false);
	});
</script>

<div class="container mx-auto px-4 sm:px-6 lg:px-8 py-6 sm:py-8">
	<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 mb-6">
		<div>
			<h1 class="text-2xl sm:text-3xl font-bold text-base-content">Requests</h1>
			<p class="text-base-content/50 text-sm mt-0.5">Track your album requests and downloads</p>
		</div>
		{#if activeCount > 0}
			<div class="flex items-center gap-3 text-xs text-base-content/50">
				{#if downloadingCount > 0}
					<span class="flex items-center gap-1.5">
						<Download class="h-3.5 w-3.5 text-info" />
						{downloadingCount} downloading
					</span>
				{/if}
				{#if pendingCount > 0}
					<span class="flex items-center gap-1.5">
						<Search class="h-3.5 w-3.5 text-warning" />
						{pendingCount} searching
					</span>
				{/if}
			</div>
		{/if}
	</div>

	<div class="flex items-center gap-1 mb-6 border-b border-base-content/5 pb-px" role="tablist">
		<button
			role="tab"
			class="tab-btn"
			class:tab-btn-active={activeTab === 'active'}
			aria-selected={activeTab === 'active'}
			onclick={() => switchTab('active')}
		>
			<Download class="h-4 w-4" />
			Active
			{#if activeCount > 0}
				<span
					class="inline-flex items-center justify-center min-w-5 h-5 px-1.5 rounded-full bg-info/15 text-info text-xs font-medium tabular-nums"
				>
					{activeCount}
				</span>
			{/if}
			{#if isPolling && activeTab === 'active'}
				<span class="polling-dot" aria-hidden="true"></span>
			{/if}
		</button>
		<button
			role="tab"
			class="tab-btn"
			class:tab-btn-active={activeTab === 'history'}
			aria-selected={activeTab === 'history'}
			onclick={() => switchTab('history')}
		>
			<History class="h-4 w-4" />
			History
			{#if historyTotal > 0}
				<span
					class="inline-flex items-center justify-center min-w-5 h-5 px-1.5 rounded-full bg-base-content/8 text-base-content/50 text-xs font-medium tabular-nums"
				>
					{historyTotal}
				</span>
			{/if}
		</button>
	</div>

	{#if activeTab === 'active'}
		<div in:fade={{ duration: 150 }} aria-live="polite">
			{#if activeError}
				<div class="alert alert-warning mb-4">
					<TriangleAlert class="h-5 w-5" />
					<span>{activeError}</span>
					<button class="btn btn-sm" onclick={loadActive}>Retry</button>
				</div>
			{/if}

			{#if activeLoading && activeItems.length === 0}
				<div class="flex flex-col gap-2.5">
					{#each Array(3) as _, i (`active-loading-${i}`)}
						<div
							class="flex items-center gap-3 sm:gap-4 p-3 sm:p-4 bg-base-200 rounded-box animate-pulse"
							style="animation-delay: {i * 100}ms"
						>
							<div class="w-14 h-14 sm:w-18 sm:h-18 bg-base-300 rounded-lg"></div>
							<div class="flex-1">
								<div class="h-4 bg-base-300 rounded w-44 mb-2"></div>
								<div class="h-3 bg-base-300 rounded w-28 mb-1"></div>
								<div class="h-2.5 bg-base-300 rounded w-20"></div>
							</div>
							<div class="flex flex-col items-end gap-2">
								<div class="h-5 bg-base-300 rounded-full w-24"></div>
								<div class="h-1.5 bg-base-300 rounded w-36"></div>
							</div>
						</div>
					{/each}
				</div>
			{:else if activeItems.length === 0}
				<div class="flex flex-col items-center justify-center min-h-60 text-center py-16">
					<div class="w-16 h-16 rounded-full bg-success/5 flex items-center justify-center mb-4">
						<CheckCircle class="h-8 w-8 text-success/30" />
					</div>
					<h2 class="text-lg font-semibold mb-1.5 text-base-content/50">All clear</h2>
					<p class="text-base-content/30 text-sm max-w-xs">
						No active downloads. Search for albums and request them to see progress here.
					</p>
				</div>
			{:else}
				<div class="flex flex-col gap-2.5">
					{#each activeItems as item, i (item.musicbrainz_id)}
						<div in:fly={{ y: 12, duration: 200, delay: i * 30 }}>
							<RequestCard {item} mode="active" oncancel={handleCancel} />
						</div>
					{/each}
				</div>
			{/if}
		</div>
	{:else}
		<div in:fade={{ duration: 150 }}>
			<div class="flex flex-wrap items-center gap-2 mb-4">
				<select
					class="select select-bordered select-sm text-xs"
					aria-label="Filter by status"
					onchange={handleFilterChange}
				>
					<option value="">All statuses</option>
					<option value="imported">Imported</option>
					<option value="incomplete">Incomplete</option>
					<option value="failed">Failed</option>
					<option value="importFailed">Import Failed</option>
					<option value="importBlocked">Import Blocked</option>
					<option value="cancelled">Cancelled</option>
				</select>

				<select
					class="select select-bordered select-sm text-xs"
					aria-label="Sort order"
					onchange={handleSortChange}
				>
					<option value="">Newest first</option>
					<option value="oldest">Oldest first</option>
					<option value="status">By status</option>
				</select>

				<div class="flex-1"></div>

				{#if historyTotalPages > 1}
					<Pagination
						current={historyPage}
						total={historyTotalPages}
						onchange={handleHistoryPageChange}
					/>
				{/if}
			</div>

			{#if historyError}
				<div class="alert alert-error mb-4">
					<span>{historyError}</span>
					<button class="btn btn-sm" onclick={loadHistory}>Retry</button>
				</div>
			{/if}

			{#if historyLoading && historyItems.length === 0}
				<div class="flex flex-col gap-2.5">
					{#each Array(5) as _, i (`history-loading-${i}`)}
						<div
							class="flex items-center gap-3 sm:gap-4 p-3 sm:p-4 bg-base-200 rounded-box animate-pulse"
							style="animation-delay: {i * 80}ms"
						>
							<div class="w-14 h-14 sm:w-18 sm:h-18 bg-base-300 rounded-lg"></div>
							<div class="flex-1">
								<div class="h-4 bg-base-300 rounded w-44 mb-2"></div>
								<div class="h-3 bg-base-300 rounded w-28"></div>
							</div>
							<div class="flex flex-col items-end gap-2">
								<div class="h-5 bg-base-300 rounded-full w-20"></div>
								<div class="h-3 bg-base-300 rounded w-28"></div>
							</div>
						</div>
					{/each}
				</div>
			{:else if historyItems.length === 0}
				<div class="flex flex-col items-center justify-center min-h-60 text-center py-16">
					<div
						class="w-16 h-16 rounded-full bg-base-content/3 flex items-center justify-center mb-4"
					>
						<Clock class="h-8 w-8 text-base-content/15" />
					</div>
					<h2 class="text-lg font-semibold mb-1.5 text-base-content/50">No history yet</h2>
					<p class="text-base-content/30 text-sm max-w-xs">
						Completed and failed requests will appear here.
					</p>
				</div>
			{:else}
				<div class="flex flex-col gap-2.5">
					{#each historyItems as item (item.musicbrainz_id)}
						<RequestCard
							{item}
							mode="history"
							onretry={handleRetry}
							onclear={handleClear}
							onremoved={handleRemoved}
						/>
					{/each}
				</div>

				{#if historyTotalPages > 1}
					<div class="flex justify-center mt-6">
						<Pagination
							current={historyPage}
							total={historyTotalPages}
							onchange={handleHistoryPageChange}
						/>
					</div>
				{/if}
			{/if}
		</div>
	{/if}
</div>

<Toast bind:show={toastShow} message={toastMessage} type={toastType} />

<style>
	.tab-btn {
		display: inline-flex;
		align-items: center;
		gap: 0.4rem;
		padding: 0.5rem 0.85rem;
		font-size: 0.875rem;
		font-weight: 500;
		color: oklch(from var(--color-base-content) l c h / 0.4);
		border-bottom: 2px solid transparent;
		transition: all 0.15s ease;
		cursor: pointer;
		background: none;
		border-top: none;
		border-left: none;
		border-right: none;
		margin-bottom: -1px;
	}
	.tab-btn:hover {
		color: oklch(from var(--color-base-content) l c h / 0.7);
	}
	.tab-btn-active {
		color: oklch(from var(--color-primary) l c h / 1);
		border-bottom-color: oklch(from var(--color-primary) l c h / 1);
	}

	.polling-dot {
		width: 6px;
		height: 6px;
		border-radius: 50%;
		background: oklch(from var(--color-info) l c h / 0.7);
		animation: pulse-dot 1.5s ease-in-out infinite;
	}

	@keyframes pulse-dot {
		0%,
		100% {
			opacity: 0.3;
			transform: scale(0.8);
		}
		50% {
			opacity: 1;
			transform: scale(1.2);
		}
	}
</style>
