<!--
	Duplicate-resolution page body. Two panels driven by the parent
	route's `activeTab` prop (URL-bound):

	1. Stacks — PhotoPrism's own auto-grouped variants (RAW+JPG, Live
	   HEIC+MOV, etc.). Source of truth is PhotoPrism's DB; we list via
	   `stack:true` and resolve via `setPrimary` + `deleteFile`.

	2. Cross-folder — files PhotoPrism silently rejected at index time
	   because they were byte-identical to an existing entry. PhotoPrism
	   never adds those rows to its DB, so we scan the filesystem via the
	   mule-sidecar. Resolution moves the unwanted copies into a
	   `.duplicates/` quarantine folder PhotoPrism's indexer ignores.

	The cross-folder scan auto-fires when its tab is active — with size
	pre-filtering it stays fast (~250ms for 400 files in practice) and a
	long staleTime keeps tab bounces from re-running it. The button is
	kept for manual "rescan after I moved files" refreshes.

	Tabs themselves render in the parent route's Toolbar so they line up
	visually with the `/tags` pill row.
-->
<script lang="ts">
	import { createQuery, useQueryClient } from '@tanstack/svelte-query';
	import { toast } from 'svelte-sonner';
	import {
		scanCrossFolderDuplicates,
		type CrossFolderScanResult
	} from '$lib/services/photoprism';
	import type { DuplicateGroup } from '$lib/services/adapters/duplicates';
	import StackGroupCard from './StackGroupCard.svelte';
	import CrossFolderGroupCard from './CrossFolderGroupCard.svelte';
	import { EmptyState, InlineLoader } from '$lib/components/feedback';
	import { AlertCircle, CheckCircle2, Copy } from 'lucide-svelte';

	type Tab = 'stacks' | 'cross-folder';

	interface Props {
		activeTab: Tab;
		groups: DuplicateGroup[];
		pending: boolean;
		error: unknown;
	}
	let { activeTab, groups, pending, error }: Props = $props();

	const qc = useQueryClient();

	// Cross-folder scan auto-fires when the tab is active. The 5-minute
	// staleTime means a fresh visit reuses the prior result; the
	// "Rescan filesystem" button invalidates to force a re-scan after
	// the user has moved files around.
	const crossQuery = createQuery<CrossFolderScanResult>(() => ({
		queryKey: ['duplicates-cross-folder'],
		queryFn: scanCrossFolderDuplicates,
		enabled: activeTab === 'cross-folder',
		staleTime: 5 * 60_000
	}));

	function rescan() {
		void qc.invalidateQueries({ queryKey: ['duplicates-cross-folder'] });
	}

	$effect(() => {
		if (crossQuery.error) {
			toast.error(
				crossQuery.error instanceof Error
					? crossQuery.error.message
					: 'Cross-folder scan failed'
			);
		}
	});

	const crossCount = $derived(crossQuery.data?.groups.length ?? 0);
</script>

<!-- Stacks tab ----------------------------------------------------- -->
{#if activeTab === 'stacks'}
	<div role="tabpanel" aria-label="Stack duplicates" class="px-6 py-4 pb-6">
		{#if pending}
			<InlineLoader label="Loading stacks…" />
		{:else if error}
			<EmptyState
				tone="destructive"
				icon={AlertCircle}
				title="Could not load stacks"
				description={error instanceof Error ? error.message : 'unknown error'}
			/>
		{:else if groups.length === 0}
			<EmptyState icon={Copy} title="No stacks">
				{#snippet descriptionSnippet()}
					<p>
						PhotoPrism stacks byte-identical (or EXIF-identical) files. If you don't have
						any, this tab stays empty. Cross-folder copies PhotoPrism rejected at index
						time live under the Cross-folder tab.
					</p>
				{/snippet}
			</EmptyState>
		{:else}
			<div class="space-y-3">
				{#each groups as group, i (group.photo.UID)}
					<StackGroupCard {group} autoFocus={i === 0} />
				{/each}
			</div>
		{/if}
	</div>
{/if}

<!-- Cross-folder tab ----------------------------------------------- -->
{#if activeTab === 'cross-folder'}
	<div role="tabpanel" aria-label="Cross-folder duplicates" class="space-y-3 px-6 py-4 pb-6">
		<header class="flex items-baseline justify-between gap-3">
			<p class="text-[11px] text-muted-foreground">
				Byte-identical files PhotoPrism dropped at index time. Found by scanning the
				originals tree directly.
			</p>
			<button
				type="button"
				class="inline-flex shrink-0 items-center gap-1.5 rounded-md border border-border px-3 py-1.5 text-xs hover:bg-accent disabled:opacity-50"
				disabled={crossQuery.isFetching}
				onclick={rescan}
			>
				{#if crossQuery.isFetching}
					Scanning…
				{:else}
					Rescan filesystem
				{/if}
			</button>
		</header>

		{#if crossQuery.isFetching && !crossQuery.data}
			<InlineLoader label="Hashing files under originals…" />
		{:else if crossQuery.isError}
			<EmptyState
				tone="destructive"
				icon={AlertCircle}
				title="Scan failed"
				description={crossQuery.error instanceof Error
					? crossQuery.error.message
					: 'unknown error'}
			/>
		{:else if crossCount === 0}
			<EmptyState icon={CheckCircle2} title="No cross-folder duplicates found">
				{#snippet descriptionSnippet()}
					{#if crossQuery.data}
						<p class="text-[10px] text-muted-foreground/70">
							scanned in {crossQuery.data.scannedMs} ms
						</p>
					{/if}
				{/snippet}
			</EmptyState>
		{:else}
			<div class="space-y-3">
				{#each crossQuery.data?.groups ?? [] as group, i (group.hash)}
					<CrossFolderGroupCard {group} autoFocus={i === 0} />
				{/each}
			</div>
		{/if}
	</div>
{/if}
