<script lang="ts">
	import { RotateCcw } from '@lucide/svelte';

	import type { ReaderFlow, ReaderSettings } from '$lib/schema/reader';
	import { READER_BOUNDS, READER_FONT_OPTIONS } from '$lib/reader/settings';
	import { getReaderSettingsState } from '$lib/state/reader-settings.svelte';

	import { Button } from '$lib/components/ui/button/index.js';
	import { Label } from '$lib/components/ui/label/index.js';
	import { NativeSelect } from '$lib/components/ui/native-select/index.js';
	import { Separator } from '$lib/components/ui/separator/index.js';
	import { Slider } from '$lib/components/ui/slider/index.js';
	import { Switch } from '$lib/components/ui/switch/index.js';
	import * as Sheet from '$lib/components/ui/sheet/index.js';
	import * as ToggleGroup from '$lib/components/ui/toggle-group/index.js';

	let {
		open = $bindable(false),
		/**
		 * Fixed-layout books render through foliate-fxl, which has no setStyles and
		 * ignores the paginator's attributes — so the controls below would do
		 * nothing. Hide them rather than leave dead sliders on screen.
		 */
		isFixedLayout = false
	}: {
		open?: boolean;
		isFixedLayout?: boolean;
	} = $props();

	const state = getReaderSettingsState();

	/** Slider binds an array; unwrap to the single value the setting holds. */
	function slide<K extends keyof ReaderSettings>(key: K) {
		return (value: number) => state.set(key, value as ReaderSettings[K]);
	}
</script>

<Sheet.Root bind:open>
	<Sheet.Content side="right" class="w-full gap-0 overflow-y-auto sm:max-w-sm">
		<Sheet.Header>
			<Sheet.Title class="font-serif">Reading</Sheet.Title>
			<Sheet.Description>
				{isFixedLayout
					? 'This book has a fixed layout, so its typography is set by the publisher.'
					: 'Applies to every book you read.'}
			</Sheet.Description>
		</Sheet.Header>

		<div class="flex flex-col gap-6 px-4 pb-6">
			{#if !isFixedLayout}
				<section class="flex flex-col gap-4">
					<h3 class="font-mono text-[10px] tracking-widest text-muted-foreground uppercase">
						Typography
					</h3>

					<div class="flex flex-col gap-2">
						<Label for="reader-font">Typeface</Label>
						<NativeSelect
							id="reader-font"
							class="w-full"
							value={state.settings.fontFamily}
							onchange={(event) => state.set('fontFamily', event.currentTarget.value)}
						>
							{#each READER_FONT_OPTIONS as font (font.value)}
								<option value={font.value}>{font.label}</option>
							{/each}
						</NativeSelect>
					</div>

					<div class="flex flex-col gap-2">
						<div class="flex items-center justify-between">
							<Label for="reader-size">Size</Label>
							<span class="font-mono text-xs text-muted-foreground tabular-nums">
								{state.settings.fontSize}px
							</span>
						</div>
						<Slider
							id="reader-size"
							type="single"
							value={state.settings.fontSize}
							min={READER_BOUNDS.fontSize.min}
							max={READER_BOUNDS.fontSize.max}
							step={READER_BOUNDS.fontSize.step}
							onValueChange={slide('fontSize')}
						/>
					</div>

					<div class="flex flex-col gap-2">
						<div class="flex items-center justify-between">
							<Label for="reader-weight">Weight</Label>
							<span class="font-mono text-xs text-muted-foreground tabular-nums">
								{state.settings.fontWeight}
							</span>
						</div>
						<Slider
							id="reader-weight"
							type="single"
							value={state.settings.fontWeight}
							min={READER_BOUNDS.fontWeight.min}
							max={READER_BOUNDS.fontWeight.max}
							step={READER_BOUNDS.fontWeight.step}
							onValueChange={slide('fontWeight')}
						/>
					</div>

					<div class="flex flex-col gap-2">
						<div class="flex items-center justify-between">
							<Label for="reader-leading">Line height</Label>
							<span class="font-mono text-xs text-muted-foreground tabular-nums">
								{state.settings.lineHeight.toFixed(2)}
							</span>
						</div>
						<Slider
							id="reader-leading"
							type="single"
							value={state.settings.lineHeight}
							min={READER_BOUNDS.lineHeight.min}
							max={READER_BOUNDS.lineHeight.max}
							step={READER_BOUNDS.lineHeight.step}
							onValueChange={slide('lineHeight')}
						/>
					</div>

					<div class="flex flex-col gap-2">
						<div class="flex items-center justify-between">
							<Label for="reader-tracking">Letter spacing</Label>
							<span class="font-mono text-xs text-muted-foreground tabular-nums">
								{state.settings.letterSpacing.toFixed(2)}em
							</span>
						</div>
						<Slider
							id="reader-tracking"
							type="single"
							value={state.settings.letterSpacing}
							min={READER_BOUNDS.letterSpacing.min}
							max={READER_BOUNDS.letterSpacing.max}
							step={READER_BOUNDS.letterSpacing.step}
							onValueChange={slide('letterSpacing')}
						/>
					</div>

					<div class="flex items-center justify-between gap-4">
						<Label for="reader-justify" class="font-normal">Justify text</Label>
						<Switch
							id="reader-justify"
							checked={state.settings.justify}
							onCheckedChange={(checked) => state.set('justify', checked)}
						/>
					</div>

					<div class="flex items-center justify-between gap-4">
						<Label for="reader-hyphenate" class="font-normal">Hyphenate</Label>
						<Switch
							id="reader-hyphenate"
							checked={state.settings.hyphenate}
							onCheckedChange={(checked) => state.set('hyphenate', checked)}
						/>
					</div>
				</section>

				<Separator />
			{/if}

			<section class="flex flex-col gap-4">
				<h3 class="font-mono text-[10px] tracking-widest text-muted-foreground uppercase">
					Layout
				</h3>

				<div class="flex flex-col gap-2">
					<Label>Flow</Label>
					<ToggleGroup.Root
						type="single"
						variant="outline"
						value={state.settings.flow}
						onValueChange={(value) => value && state.set('flow', value as ReaderFlow)}
						class="justify-start"
					>
						<ToggleGroup.Item value="paginated">Pages</ToggleGroup.Item>
						<ToggleGroup.Item value="scrolled">Scroll</ToggleGroup.Item>
					</ToggleGroup.Root>
				</div>

				{#if !isFixedLayout}
					<div class="flex flex-col gap-2">
						<Label>Columns</Label>
						<ToggleGroup.Root
							type="single"
							variant="outline"
							value={String(state.settings.maxColumnCount)}
							onValueChange={(value) => value && state.set('maxColumnCount', Number(value))}
							class="justify-start"
						>
							<ToggleGroup.Item value="1">Single</ToggleGroup.Item>
							<ToggleGroup.Item value="2">Spread</ToggleGroup.Item>
						</ToggleGroup.Root>
						<p class="text-xs text-muted-foreground">
							A spread needs the window to be wide enough for two columns.
						</p>
					</div>

					<div class="flex flex-col gap-2">
						<div class="flex items-center justify-between">
							<Label for="reader-width">Line width</Label>
							<span class="font-mono text-xs text-muted-foreground tabular-nums">
								{state.settings.maxInlineSize}px
							</span>
						</div>
						<Slider
							id="reader-width"
							type="single"
							value={state.settings.maxInlineSize}
							min={READER_BOUNDS.maxInlineSize.min}
							max={READER_BOUNDS.maxInlineSize.max}
							step={READER_BOUNDS.maxInlineSize.step}
							onValueChange={slide('maxInlineSize')}
						/>
					</div>

					<div class="flex flex-col gap-2">
						<div class="flex items-center justify-between">
							<Label for="reader-gap">Column gap</Label>
							<span class="font-mono text-xs text-muted-foreground tabular-nums">
								{state.settings.gap}%
							</span>
						</div>
						<Slider
							id="reader-gap"
							type="single"
							value={state.settings.gap}
							min={READER_BOUNDS.gap.min}
							max={READER_BOUNDS.gap.max}
							step={READER_BOUNDS.gap.step}
							onValueChange={slide('gap')}
						/>
					</div>
				{/if}

				<div class="flex flex-col gap-2">
					<div class="flex items-center justify-between">
						<Label for="reader-margin">Margins</Label>
						<span class="font-mono text-xs text-muted-foreground tabular-nums">
							{state.settings.margin}px
						</span>
					</div>
					<Slider
						id="reader-margin"
						type="single"
						value={state.settings.margin}
						min={READER_BOUNDS.margin.min}
						max={READER_BOUNDS.margin.max}
						step={READER_BOUNDS.margin.step}
						onValueChange={slide('margin')}
					/>
				</div>
			</section>

			<Separator />

			<Button variant="outline" onclick={() => state.reset()} class="self-start">
				<RotateCcw class="size-4" />
				Reset to defaults
			</Button>
		</div>
	</Sheet.Content>
</Sheet.Root>
