<script lang="ts">
	import { Checkbox } from '$lib/components/ui/checkbox';
	import * as Dialog from '$lib/components/ui/dialog';
	import { Input } from '$lib/components/ui/input';
	import { Label } from '$lib/components/ui/label';
	import * as m from '$lib/paraglide/messages';

	interface Option {
		value: string;
		label: string;
		metadata?: string;
	}

	interface OptionGroup {
		value: string;
		label: string;
		options: Option[];
	}

	interface Props {
		open: boolean;
		mode: 'models' | 'variables';
		groups: OptionGroup[];
		selected: string[];
		dirty: boolean;
		onToggle: (value: string) => void;
		onToggleGroup: (values: string[], select: boolean) => void;
		onApply: () => void;
		onClose: () => void;
		onRestoreDefaults?: () => void;
	}

	let {
		open,
		mode,
		groups,
		selected,
		dirty,
		onToggle,
		onToggleGroup,
		onApply,
		onClose,
		onRestoreDefaults
	}: Props = $props();

	let search = $state('');
	let onlySelected = $state(false);
	let normalizedSearch = $derived(search.trim().toLocaleLowerCase());

	let visibleGroups = $derived.by(() =>
		groups.flatMap((group) => {
			const options = group.options.filter((option) => {
				if (onlySelected && !selected.includes(option.value)) return false;
				if (!normalizedSearch) return true;
				return `${group.label} ${option.label} ${option.value} ${option.metadata ?? ''}`
					.toLocaleLowerCase()
					.includes(normalizedSearch);
			});
			return options.length > 0 ? [{ ...group, options }] : [];
		})
	);

	$effect(() => {
		if (open) return;
		search = '';
		onlySelected = false;
	});

	function groupSelection(group: OptionGroup): { count: number; all: boolean; partial: boolean } {
		const count = group.options.filter((option) => selected.includes(option.value)).length;
		return { count, all: count === group.options.length, partial: count > 0 && count < group.options.length };
	}

	function applyAndClose(): void {
		onApply();
		onClose();
	}
</script>

<Dialog.Dialog {open} onOpenChange={(nextOpen) => !nextOpen && onClose()}>
	<Dialog.DialogContent
		showCloseButton={false}
		class="top-0 right-0 bottom-0 left-auto flex h-dvh w-full max-w-none translate-x-0 translate-y-0 flex-col gap-0 rounded-none border-0 p-0 sm:w-[640px] sm:max-w-[90vw] sm:border-l"
	>
		<header class="shrink-0 border-b border-border bg-background px-4 py-4 sm:px-5">
			<div class="flex items-start justify-between gap-4">
				<div class="min-w-0">
					<Dialog.DialogTitle class="text-lg font-bold">
						{mode === 'models' ? m.compare_edit_models() : m.compare_edit_variables()}
					</Dialog.DialogTitle>
					<Dialog.DialogDescription class="mt-0.5 text-xs">
						{mode === 'models'
							? m.compare_edit_models_description()
							: m.compare_edit_variables_description()}
					</Dialog.DialogDescription>
				</div>
				<button
					type="button"
					class="flex size-9 shrink-0 items-center justify-center rounded-lg text-xl text-muted-foreground hover:bg-muted hover:text-foreground"
					onclick={onClose}
					aria-label={m.action_close()}
				>
					<span aria-hidden="true">×</span>
				</button>
			</div>

			<div class="mt-4 flex flex-col gap-2 sm:flex-row">
				<Input
					type="search"
					bind:value={search}
					placeholder={mode === 'models'
						? m.compare_search_models()
						: m.compare_search_variables()}
					aria-label={mode === 'models'
						? m.compare_search_models()
						: m.compare_search_variables()}
				/>
				<div
					class="flex min-h-9 shrink-0 cursor-pointer items-center gap-2 rounded-lg border border-border px-3 text-xs font-semibold hover:bg-muted"
				>
					<Checkbox id="drawer_{mode}_only_selected" bind:checked={onlySelected} />
					<Label for="drawer_{mode}_only_selected" class="cursor-pointer text-xs">
						{m.compare_only_selected()}
					</Label>
				</div>
			</div>
		</header>

		<div class="min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-4 sm:px-5">
			{#if visibleGroups.length > 0}
				<div class="grid items-start gap-3 sm:grid-cols-2">
					{#each visibleGroups as visibleGroup (visibleGroup.value)}
						{@const fullGroup = groups.find((group) => group.value === visibleGroup.value) ?? visibleGroup}
						{@const selection = groupSelection(fullGroup)}
						<section class="overflow-hidden rounded-xl border border-border/70 bg-card">
							<div class="flex min-h-11 items-center gap-2 border-b border-border/60 bg-muted/30 px-3 py-2">
								<Checkbox
									id="drawer_{mode}_group_{fullGroup.value}"
									checked={selection.all}
									indeterminate={selection.partial}
									onCheckedChange={() =>
										onToggleGroup(
											fullGroup.options.map((option) => option.value),
											!selection.all
										)}
								/>
								<Label
									for="drawer_{mode}_group_{fullGroup.value}"
									class="min-w-0 flex-1 cursor-pointer text-sm font-bold"
								>
									{fullGroup.label}
								</Label>
								<span class="shrink-0 text-[11px] text-muted-foreground tabular-nums">
									{selection.count}/{fullGroup.options.length}
								</span>
								<button
									type="button"
									class="shrink-0 rounded-md px-2 py-1 text-[11px] font-semibold text-primary hover:bg-primary/10"
									onclick={() =>
										onToggleGroup(
											fullGroup.options.map((option) => option.value),
											!selection.all
										)}
								>
									{selection.all ? m.compare_clear_group() : m.compare_select_group()}
								</button>
							</div>
							<div class="p-2">
								{#each visibleGroup.options as option (option.value)}
									<div class="flex min-h-10 items-center rounded-lg px-1.5 hover:bg-muted/60">
										<Checkbox
											id="drawer_{mode}_{option.value}"
											checked={selected.includes(option.value)}
											onCheckedChange={() => onToggle(option.value)}
										/>
										<Label
											for="drawer_{mode}_{option.value}"
											class="min-w-0 flex-1 cursor-pointer py-2 pl-2"
										>
											<span class="block text-sm font-medium">{option.label}</span>
											{#if option.metadata}
												<span class="block text-[10px] text-muted-foreground">
													{option.metadata}
												</span>
											{/if}
										</Label>
									</div>
								{/each}
							</div>
						</section>
					{/each}
				</div>
			{:else}
				<div class="rounded-xl border border-dashed border-border px-4 py-10 text-center text-sm text-muted-foreground">
					{m.compare_no_matching_options()}
				</div>
			{/if}
		</div>

		<footer class="shrink-0 border-t border-border bg-background px-4 py-3 sm:px-5">
			<div class="flex flex-wrap items-center justify-between gap-2">
				<div>
					{#if mode === 'variables' && onRestoreDefaults}
						<button
							type="button"
							class="min-h-9 rounded-lg border border-border px-3 py-1.5 text-xs font-semibold hover:bg-muted"
							onclick={onRestoreDefaults}
						>
							{m.compare_restore_defaults()}
						</button>
					{/if}
				</div>
				<div class="flex gap-2">
					<button
						type="button"
						class="min-h-10 rounded-lg border border-border px-4 py-2 text-sm font-semibold hover:bg-muted"
						onclick={onClose}
					>
						{m.action_close()}
					</button>
					<button
						type="button"
						class="min-h-10 rounded-lg bg-primary px-4 py-2 text-sm font-bold text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
						disabled={!dirty}
						onclick={applyAndClose}
					>
						{m.compare_apply_selection()}
					</button>
				</div>
			</div>
		</footer>
	</Dialog.DialogContent>
</Dialog.Dialog>
