<!--
	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 is opt-in (button-triggered) rather than
	auto-run because it's an O(disk) operation. With size pre-filtering
	the scan stays fast (~250ms for 400 files in practice).

	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';

	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 is a manually-triggered query: `enabled` stays
	// false until the user clicks "Scan filesystem". Subsequent clicks
	// invalidate the cache so each press kicks a fresh scan.
	let scanRequested = $state(false);
	const crossQuery = createQuery<CrossFolderScanResult>(() => ({
		queryKey: ['duplicates-cross-folder'],
		queryFn: scanCrossFolderDuplicates,
		enabled: scanRequested && activeTab === 'cross-folder',
		staleTime: 5 * 60_000
	}));

	function triggerScan() {
		if (scanRequested && !crossQuery.isFetching) {
			void qc.invalidateQueries({ queryKey: ['duplicates-cross-folder'] });
		} else {
			scanRequested = true;
		}
	}

	$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}
			<p class="text-sm text-muted-foreground">Loading stacks…</p>
		{:else if error}
			<p class="text-sm text-destructive">
				Could not load stacks: {error instanceof Error ? error.message : 'unknown error'}
			</p>
		{:else if groups.length === 0}
			<div class="max-w-prose space-y-2 text-sm text-muted-foreground">
				<p>No stacks.</p>
				<p class="text-xs">
					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>
			</div>
		{: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={triggerScan}
			>
				{#if crossQuery.isFetching}
					Scanning…
				{:else if scanRequested}
					Rescan filesystem
				{:else}
					Scan filesystem
				{/if}
			</button>
		</header>

		{#if !scanRequested}
			<p class="text-sm text-muted-foreground">
				Click <em>Scan filesystem</em> to look for byte-identical files spread across
				folders. Pre-filtered by size, so even large libraries finish in a few seconds.
			</p>
		{:else if crossQuery.isFetching && !crossQuery.data}
			<p class="text-sm text-muted-foreground">Hashing files under originals…</p>
		{:else if crossQuery.isError}
			<p class="text-sm text-destructive">
				Scan failed: {crossQuery.error instanceof Error
					? crossQuery.error.message
					: 'unknown error'}
			</p>
		{:else if crossCount === 0}
			<p class="text-sm text-muted-foreground">
				No cross-folder duplicates found.
				{#if crossQuery.data}
					<span class="ml-1 text-[10px] text-muted-foreground/70">
						(scanned in {crossQuery.data.scannedMs} ms)
					</span>
				{/if}
			</p>
		{: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}
