<script lang="ts">
	import { goto } from '$app/navigation';
	import { type DeckCategoryId, DECK_CATEGORY_IDS, DECK_CATEGORY_LABELS } from '@wordeck/domain';
	import { createDeck, generateDeck, generateDeckFromImage } from '$lib/api/decks.ts';
	import { devUser } from '$lib/auth/dev-stub.svelte.ts';
	import { toasts } from '$lib/stores/toasts.svelte.ts';
	import { i18n, t, type Locale } from '$lib/i18n/index.svelte.ts';
	import CardSurface from './CardSurface.svelte';
	import DeckCategoryIcon from './DeckCategoryIcon.svelte';
	import { apiErrorMessage } from '$lib/api/error.ts';

	let open = $state(false);
	let catOpen = $state(false);

	let name = $state('');
	let description = $state('');
	let color = $state('#0088ff');
	let category = $state<DeckCategoryId | undefined>(undefined);
	let count = $state(15);
	let language = $state<Locale>(i18n.current);
	let saving = $state(false);
	let generating = $state(false);
	let aiError = $state<string | null>(null);

	const MAX_IMAGE_FILES = 5;

	let imageFiles = $state<File[]>([]);
	let imagePreviews = $state<string[]>([]);
	let imageUrl = $state('');
	let imageGenerating = $state(false);
	let imageError = $state<string | null>(null);
	let fileInput = $state<HTMLInputElement | null>(null);

	function addImageFiles(incoming: File[]) {
		const images = incoming.filter(isAccepted);
		const combined = [...imageFiles, ...images].slice(0, MAX_IMAGE_FILES);
		// revoke URLs für Dateien die rausfallen (über Limit)
		for (let i = combined.length; i < imagePreviews.length; i++) {
			URL.revokeObjectURL(imagePreviews[i]);
		}
		imageFiles = combined;
		imagePreviews = combined.map((f, i) => imagePreviews[i] ?? URL.createObjectURL(f));
		imageError = null;
	}

	function removeImageFile(i: number) {
		URL.revokeObjectURL(imagePreviews[i]);
		imageFiles = imageFiles.filter((_, j) => j !== i);
		imagePreviews = imagePreviews.filter((_, j) => j !== i);
	}

	function onFileChange(e: Event) {
		const files = Array.from((e.target as HTMLInputElement).files ?? []);
		if (files.length) addImageFiles(files);
	}

	function onImageDrop(e: DragEvent) {
		e.preventDefault();
		const files = Array.from(e.dataTransfer?.files ?? []);
		if (files.length) addImageFiles(files);
	}

	function isAccepted(f: File) {
		return f.type.startsWith('image/') || f.type === 'application/pdf';
	}

	function close() {
		open = false;
		catOpen = false;
		name = '';
		description = '';
		color = '#0088ff';
		category = undefined;
		count = 15;
		saving = false;
		generating = false;
		aiError = null;
		for (const url of imagePreviews) URL.revokeObjectURL(url);
		imageFiles = [];
		imagePreviews = [];
		imageUrl = '';
		imageGenerating = false;
		imageError = null;
	}

	async function onFromImage() {
		if ((imageFiles.length === 0 && !imageUrl.trim()) || !devUser.id || imageGenerating) return;
		imageError = null;
		imageGenerating = true;
		try {
			const result = await generateDeckFromImage(imageFiles, {
				count,
				language,
				url: imageUrl.trim() || undefined,
			});
			toasts.success(`🖼 "${result.deck.name}" mit ${result.cards_created} Karten erstellt`);
			goto(`/decks/${result.deck.id}`);
		} catch (err) {
			imageError = apiErrorMessage(err);
			imageGenerating = false;
		}
	}

	function pickCategory(id: DeckCategoryId) {
		category = category === id ? undefined : id;
		catOpen = false;
	}

	async function onManual(e: SubmitEvent) {
		e.preventDefault();
		if (!name.trim() || !devUser.id) return;
		saving = true;
		try {
			const deck = await createDeck({
				name: name.trim(),
				description: description.trim() || undefined,
				color,
				category,
			});
			toasts.success(`${deck.name} ✓`);
			goto(`/decks/${deck.id}`);
		} catch (err) {
			toasts.error(t('deck_new.create_failed', { msg: apiErrorMessage(err) }));
			saving = false;
		}
	}

	async function onAi() {
		if (!name.trim() || !devUser.id || generating) return;
		aiError = null;
		generating = true;
		try {
			const result = await generateDeck({ prompt: name.trim(), count, language, url: imageUrl.trim() || undefined });
			toasts.success(`✨ "${result.deck.name}" mit ${result.cards_created} Karten erstellt`);
			goto(`/decks/${result.deck.id}`);
		} catch (err) {
			aiError = apiErrorMessage(err);
			generating = false;
		}
	}
</script>

<div class="new-wrap">
	{#if !open}
		<CardSurface size="md" as="button" onclick={() => (open = true)} ariaLabel={t('deck_new.title')} class="new-card">
			<div class="new-inner">
				<span class="new-plus" aria-hidden="true">+</span>
				<span class="new-label">{t('deck_new.title')}</span>
			</div>
		</CardSurface>
	{:else}
		<CardSurface size="md" class="form-card">
			<form class="form-scroll" onsubmit={onManual}>

				<label class="field">
					<span class="label">Name / Thema</span>
					<input bind:value={name} required maxlength="200" autofocus
						placeholder="z.B. Französische Revolution" class="input" />
				</label>

				<label class="field">
					<span class="label">{t('deck_new.description_label')}</span>
					<textarea bind:value={description} maxlength="2000" rows="2" class="input"></textarea>
				</label>

				<!-- Fach: einzelner Trigger-Button, klappt Picker inline auf -->
				<div class="field">
					<span class="label">Fach</span>
					<button type="button" class="picker-trigger" onclick={() => (catOpen = !catOpen)}
						aria-expanded={catOpen}>
						{#if category}
							<DeckCategoryIcon category={category} size={14} color={color} weight="fill" />
							<span>{DECK_CATEGORY_LABELS[category]}</span>
						{:else}
							<span class="placeholder">Kein Fach</span>
						{/if}
						<span class="chevron" class:flipped={catOpen} aria-hidden="true">▾</span>
					</button>
					{#if catOpen}
						<div class="cat-grid">
							{#each DECK_CATEGORY_IDS as id}
								<button type="button" class="cat-btn" class:selected={category === id}
									onclick={() => pickCategory(id)}
									aria-pressed={category === id}>
									<DeckCategoryIcon category={id} size={13}
										color={category === id ? color : null}
										weight={category === id ? 'fill' : 'regular'} />
									<span class="cat-label">{DECK_CATEGORY_LABELS[id]}</span>
								</button>
							{/each}
						</div>
					{/if}
				</div>

				<label class="field">
					<span class="label">{t('deck_new.color_label')}</span>
					<input type="color" bind:value={color} class="color-input" />
				</label>

				<label class="field">
					<span class="label">Anzahl Karten (KI)</span>
					<input type="number" bind:value={count} min="3" max="40" class="input" />
				</label>

				<label class="field">
					<span class="label">Sprache (KI)</span>
					<select bind:value={language} class="input">
						<option value="de">Deutsch</option>
						<option value="en">English</option>
					</select>
				</label>

				<!-- Bild-Dropzone für Vision-Generierung (bis zu 5 Bilder) -->
				<div class="field">
					<div
						class="img-drop"
						role="button"
						tabindex="0"
						onclick={() => fileInput?.click()}
						onkeydown={(e) => e.key === 'Enter' && fileInput?.click()}
						ondrop={onImageDrop}
						ondragover={(e) => e.preventDefault()}
					>
						{#if imagePreviews.length > 0}
							<div class="img-strip">
								{#each imageFiles as file, i}
									<div class="img-thumb-wrap">
										{#if file.type === 'application/pdf'}
											<div class="img-thumb img-pdf-thumb"><span>📄</span></div>
										{:else}
											<img src={imagePreviews[i]} alt="Bild {i + 1}" class="img-thumb" />
										{/if}
										<button
											type="button"
											class="img-remove"
											onclick={(e) => { e.stopPropagation(); removeImageFile(i); }}
											aria-label="Datei entfernen"
										>×</button>
									</div>
								{/each}
								{#if imagePreviews.length < MAX_IMAGE_FILES}
									<div class="img-add-hint">+ weitere</div>
								{/if}
							</div>
						{:else}
							<span class="img-placeholder">🖼 Bilder oder PDFs für KI (bis zu 5)</span>
						{/if}
						<input
							bind:this={fileInput}
							type="file"
							accept="image/*,application/pdf"
							multiple
							class="sr-only"
							onchange={onFileChange}
						/>
					</div>
				</div>

				<label class="field">
					<span class="label">URL als Kontext (optional)</span>
					<input
						bind:value={imageUrl}
						type="url"
						placeholder="https://…"
						class="input"
					/>
				</label>

				{#if aiError}
					<p class="ai-error" role="alert">{aiError}</p>
				{/if}
				{#if imageError}
					<p class="ai-error" role="alert">{imageError}</p>
				{/if}
				{#if generating}
					<p class="ai-hint" aria-live="polite">Generiere… ca. 10–60 s</p>
				{/if}
				{#if imageGenerating}
					<p class="ai-hint" aria-live="polite">
						{imageFiles.length > 0 && imageUrl.trim() ? 'Bild + URL' : imageUrl.trim() ? 'URL' : 'Bild'} wird analysiert… ca. 15–60 s
					</p>
				{/if}

				<div class="actions">
					<button type="submit" disabled={saving || generating || imageGenerating || !name.trim()} class="btn-primary">
						{saving ? t('deck_new.creating') : t('deck_new.create')}
					</button>
					<button type="button" disabled={generating || saving || imageGenerating || !name.trim()} onclick={onAi} class="btn-ai">
						{generating ? '✨ Generiere…' : '✨ Mit KI generieren'}
					</button>
					<button type="button" disabled={(imageFiles.length === 0 && !imageUrl.trim()) || imageGenerating || saving || generating} onclick={onFromImage} class="btn-ai">
						{#if imageGenerating}
							{imageUrl.trim() && imageFiles.length === 0 ? '🌐' : '🖼'} Analysiere…
						{:else if imageFiles.length > 0 && imageUrl.trim()}
							🖼 Bild + URL
						{:else if imageUrl.trim()}
							🖼 Aus URL
						{:else}
							🖼 Aus Bild
						{/if}
					</button>
					<button type="button" onclick={close} class="btn-cancel">
						{t('deck_new.cancel')}
					</button>
				</div>

			</form>
		</CardSurface>
	{/if}
</div>

<style>
	.new-wrap {
		position: relative;
		width: 100%;
		max-width: 18rem;
		aspect-ratio: 5 / 7;
	}

	.new-wrap :global(.new-card) {
		border-style: dashed;
		background: transparent;
		transition: border-color 0.15s, background 0.15s;
		width: 100%;
		height: 100%;
	}
	.new-wrap :global(.new-card:hover) {
		border-color: hsl(var(--color-primary) / 0.6);
		background: hsl(var(--color-primary) / 0.04);
	}

	.new-inner {
		position: absolute;
		inset: 0;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		gap: 0.75rem;
		color: hsl(var(--color-muted-foreground));
	}

	.new-plus {
		font-size: 2.5rem;
		font-weight: 300;
		line-height: 1;
	}

	.new-label {
		font-size: 0.875rem;
		font-weight: 500;
		text-align: center;
	}

	.new-wrap :global(.form-card) {
		width: 100%;
		height: 100%;
	}

	.form-scroll {
		position: absolute;
		inset: 0;
		overflow-y: auto;
		padding: 0.75rem;
		display: flex;
		flex-direction: column;
		gap: 0.5rem;
		scrollbar-width: thin;
	}

	.field {
		display: flex;
		flex-direction: column;
		gap: 0.1875rem;
	}

	.label {
		font-size: 0.6875rem;
		font-weight: 500;
		color: hsl(var(--color-muted-foreground));
	}

	.input {
		width: 100%;
		padding: 0.3125rem 0.5rem;
		font-size: 0.8125rem;
		font-family: inherit;
		border-radius: 0.3125rem;
		border: 1px solid hsl(var(--color-border));
		background: hsl(var(--color-card));
		color: hsl(var(--color-foreground));
		box-sizing: border-box;
	}
	.input:focus {
		outline: 2px solid hsl(var(--color-primary) / 0.4);
		outline-offset: 1px;
	}

	/* Fach-Trigger — sieht aus wie ein Select */
	.picker-trigger {
		display: flex;
		align-items: center;
		gap: 0.375rem;
		width: 100%;
		padding: 0.3125rem 0.5rem;
		font-size: 0.8125rem;
		font-family: inherit;
		border-radius: 0.3125rem;
		border: 1px solid hsl(var(--color-border));
		background: hsl(var(--color-card));
		color: hsl(var(--color-foreground));
		cursor: pointer;
		text-align: left;
	}
	.picker-trigger:hover {
		border-color: hsl(var(--color-primary) / 0.5);
	}

	.placeholder {
		color: hsl(var(--color-muted-foreground));
	}

	.chevron {
		margin-left: auto;
		font-size: 0.75rem;
		color: hsl(var(--color-muted-foreground));
		transition: transform 0.15s;
	}
	.chevron.flipped {
		transform: rotate(180deg);
	}

	/* Kategorie-Picker — Flexwrap Pills mit Icon + Label */
	.cat-grid {
		display: flex;
		flex-wrap: wrap;
		gap: 0.25rem;
		padding-top: 0.25rem;
	}

	.cat-btn {
		display: inline-flex;
		align-items: center;
		gap: 0.25rem;
		padding: 0.25rem 0.5rem;
		border-radius: 9999px;
		border: 1px solid hsl(var(--color-border));
		background: hsl(var(--color-surface));
		color: hsl(var(--color-muted-foreground));
		cursor: pointer;
		transition: border-color 0.12s, background 0.12s, color 0.12s;
	}
	.cat-btn:hover {
		border-color: hsl(var(--color-primary) / 0.5);
		color: hsl(var(--color-foreground));
	}
	.cat-btn.selected {
		border-color: hsl(var(--color-primary));
		background: hsl(var(--color-primary) / 0.08);
		color: hsl(var(--color-foreground));
	}

	.cat-label {
		font-size: 0.75rem;
		font-weight: 500;
	}

	/* Farbe — volle Breite, feste Höhe wie ein Input */
	.color-input {
		width: 100%;
		height: 2rem;
		padding: 0.125rem 0.25rem;
		border-radius: 0.3125rem;
		border: 1px solid hsl(var(--color-border));
		background: transparent;
		cursor: pointer;
		box-sizing: border-box;
	}

	.ai-error {
		margin: 0;
		font-size: 0.6875rem;
		color: hsl(var(--color-error));
	}

	.ai-hint {
		margin: 0;
		font-size: 0.6875rem;
		color: hsl(var(--color-muted-foreground));
	}

	.actions {
		display: flex;
		flex-direction: column;
		gap: 0.375rem;
		margin-top: auto;
		padding-top: 0.25rem;
	}

	.btn-primary {
		width: 100%;
		padding: 0.375rem 0.625rem;
		font-size: 0.8125rem;
		font-family: inherit;
		border-radius: 0.375rem;
		border: none;
		background: hsl(var(--color-primary));
		color: hsl(var(--color-primary-foreground));
		cursor: pointer;
	}
	.btn-primary:disabled {
		opacity: 0.5;
		cursor: not-allowed;
	}

	.btn-ai {
		width: 100%;
		padding: 0.375rem 0.625rem;
		font-size: 0.8125rem;
		font-family: inherit;
		border-radius: 0.375rem;
		border: 1px solid hsl(var(--color-primary));
		background: transparent;
		color: hsl(var(--color-primary));
		cursor: pointer;
	}
	.btn-ai:hover:not(:disabled) {
		background: hsl(var(--color-primary) / 0.08);
	}
	.btn-ai:disabled {
		opacity: 0.5;
		cursor: not-allowed;
	}

	.btn-cancel {
		width: 100%;
		padding: 0.375rem 0.625rem;
		font-size: 0.8125rem;
		font-family: inherit;
		border-radius: 0.375rem;
		border: 1px solid hsl(var(--color-border));
		background: hsl(var(--color-surface));
		color: hsl(var(--color-foreground));
		cursor: pointer;
	}
	.btn-cancel:hover {
		background: hsl(var(--color-surface-hover));
	}

	.img-drop {
		display: flex;
		align-items: center;
		justify-content: center;
		min-height: 2.75rem;
		border: 1.5px dashed hsl(var(--color-border));
		border-radius: 0.3125rem;
		cursor: pointer;
		overflow: hidden;
		transition: border-color 0.12s;
	}
	.img-drop:hover {
		border-color: hsl(var(--color-primary) / 0.5);
	}

	.img-placeholder {
		font-size: 0.6875rem;
		color: hsl(var(--color-muted-foreground));
		padding: 0.375rem 0.5rem;
		text-align: center;
	}

	.img-strip {
		display: flex;
		align-items: center;
		gap: 0.25rem;
		padding: 0.25rem;
		flex-wrap: wrap;
	}

	.img-thumb-wrap {
		position: relative;
		flex-shrink: 0;
	}

	.img-thumb {
		width: 2.5rem;
		height: 2.5rem;
		object-fit: cover;
		border-radius: 0.25rem;
		display: block;
	}

	.img-pdf-thumb {
		background: hsl(var(--color-surface));
		border: 1px solid hsl(var(--color-border));
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 1.125rem;
	}

	.img-remove {
		position: absolute;
		top: -0.3rem;
		right: -0.3rem;
		width: 1rem;
		height: 1rem;
		font-size: 0.625rem;
		line-height: 1;
		border-radius: 50%;
		border: none;
		background: hsl(var(--color-error));
		color: #fff;
		cursor: pointer;
		display: flex;
		align-items: center;
		justify-content: center;
		padding: 0;
	}

	.img-add-hint {
		font-size: 0.625rem;
		color: hsl(var(--color-muted-foreground));
		padding: 0 0.25rem;
	}
</style>
