<script lang="ts">
	import { t } from 'svelte-i18n';
	import { fade } from 'svelte/transition';
	import { tick } from 'svelte';
	import DynamicIcon from '$lib/components/ui/DynamicIcon.svelte';
	import MultiEntityPicker from '$lib/components/ui/MultiEntityPicker.svelte';

	interface AppInfo {
		id: string;
		name: string;
		icon?: string | null;
		iconType?: string;
	}

	interface Props {
		widgetType: string;
		initialConfig?: Record<string, unknown>;
		apps?: AppInfo[];
		mode: 'create' | 'edit';
		onSave: (config: Record<string, unknown>) => void;
		onCancel: () => void;
	}

	let { widgetType, initialConfig = {}, apps = [], mode, onSave, onCancel }: Props = $props();

	// App search
	let appSearchQuery = $state('');
	const filteredApps = $derived(
		appSearchQuery.trim()
			? apps.filter((a) => a.name.toLowerCase().includes(appSearchQuery.toLowerCase()))
			: apps
	);

	// -- Form fields initialised from config --
	// App
	let appId = $state((initialConfig.appId as string) ?? '');

	// Bookmark
	let bookmarkUrl = $state((initialConfig.url as string) ?? '');
	let bookmarkLabel = $state((initialConfig.label as string) ?? '');
	let bookmarkIcon = $state((initialConfig.icon as string) ?? '');
	let bookmarkDescription = $state((initialConfig.description as string) ?? '');

	// Note
	let noteContent = $state((initialConfig.content as string) ?? '');
	let noteFormat = $state<'markdown' | 'text' | 'html'>((initialConfig.format as 'markdown' | 'text' | 'html') ?? 'markdown');

	// Embed
	let embedUrl = $state((initialConfig.url as string) ?? '');
	let embedHeight = $state((initialConfig.height as number) ?? 300);
	let embedSandbox = $state((initialConfig.sandbox as string) ?? '');

	// Status
	let statusLabel = $state((initialConfig.label as string) ?? '');
	let statusAppIds = $state<string[]>((initialConfig.appIds as string[]) ?? []);

	// Clock
	let clockTimezone = $state((initialConfig.timezone as string) ?? '');
	let clockStyle = $state<string>((initialConfig.clockStyle as string) ?? 'digital');
	let clockShowWeather = $state((initialConfig.showWeather as boolean) ?? false);
	let clockLatitude = $state(String(initialConfig.latitude ?? ''));
	let clockLongitude = $state(String(initialConfig.longitude ?? ''));

	// System Stats
	let sysStatsSourceUrl = $state((initialConfig.sourceUrl as string) ?? '');
	let sysStatsSourceType = $state<string>((initialConfig.sourceType as string) ?? 'custom');
	let sysStatsRefreshInterval = $state((initialConfig.refreshInterval as number) ?? 30);

	// RSS
	let rssFeedUrl = $state((initialConfig.feedUrl as string) ?? '');
	let rssMaxItems = $state((initialConfig.maxItems as number) ?? 10);
	let rssShowSummary = $state((initialConfig.showSummary as boolean) ?? true);

	// Calendar
	let calendarUrlsRaw = $state((initialConfig.icalUrls as Array<{ url: string; color: string; label: string }>) ?? [{ url: '', color: '#e8754f', label: '' }]);
	let calendarDaysAhead = $state((initialConfig.daysAhead as number) ?? 7);

	// Markdown
	let markdownContent = $state((initialConfig.content as string) ?? '');

	// Metric
	let metricLabel = $state((initialConfig.label as string) ?? '');
	let metricSource = $state<string>((initialConfig.source as string) ?? 'static');
	let metricValue = $state(String(initialConfig.value ?? ''));
	let metricUrl = $state((initialConfig.url as string) ?? '');
	let metricJsonPath = $state((initialConfig.jsonPath as string) ?? '');
	let metricQuery = $state((initialConfig.query as string) ?? '');
	let metricUnit = $state((initialConfig.unit as string) ?? '');
	let metricRefreshInterval = $state((initialConfig.refreshInterval as number) ?? 60);

	// Link Group
	let linkGroupLinks = $state<Array<{ label: string; url: string; icon: string }>>((initialConfig.links as Array<{ label: string; url: string; icon: string }>) ?? [{ label: '', url: '', icon: '' }]);
	let linkGroupCollapsible = $state((initialConfig.collapsible as boolean) ?? false);

	// Camera
	let cameraStreamUrl = $state((initialConfig.streamUrl as string) ?? '');
	let cameraType = $state<string>((initialConfig.type as string) ?? 'image');
	let cameraRefreshInterval = $state((initialConfig.refreshInterval as number) ?? 10);
	let cameraAspectRatio = $state((initialConfig.aspectRatio as string) ?? '16/9');

	// Integration
	let integrationAppId = $state((initialConfig.appId as string) ?? '');
	let integrationEndpointId = $state((initialConfig.endpointId as string) ?? '');
	let integrationRefreshInterval = $state((initialConfig.refreshInterval as number) ?? 60);

	function buildConfig(): Record<string, unknown> {
		switch (widgetType) {
			case 'app':
				return { appId };
			case 'bookmark':
				return { url: bookmarkUrl, label: bookmarkLabel, icon: bookmarkIcon || undefined, description: bookmarkDescription || undefined };
			case 'note':
				return { content: noteContent, format: noteFormat };
			case 'embed':
				return { url: embedUrl, height: embedHeight, sandbox: embedSandbox || undefined };
			case 'status':
				return { appIds: statusAppIds, label: statusLabel || undefined };
			case 'clock':
				return { timezone: clockTimezone || undefined, clockStyle, showWeather: clockShowWeather, latitude: clockLatitude ? Number(clockLatitude) : undefined, longitude: clockLongitude ? Number(clockLongitude) : undefined };
			case 'system_stats':
				return { sourceUrl: sysStatsSourceUrl, sourceType: sysStatsSourceType, metrics: ['cpu', 'ram', 'disk'], refreshInterval: sysStatsRefreshInterval };
			case 'rss':
				return { feedUrl: rssFeedUrl, maxItems: rssMaxItems, showSummary: rssShowSummary };
			case 'calendar':
				return { icalUrls: calendarUrlsRaw.filter((u) => u.url.trim()), daysAhead: calendarDaysAhead };
			case 'markdown':
				return { content: markdownContent };
			case 'metric':
				return { label: metricLabel, source: metricSource, value: metricValue || undefined, url: metricUrl || undefined, jsonPath: metricJsonPath || undefined, query: metricQuery || undefined, unit: metricUnit || undefined, refreshInterval: metricRefreshInterval };
			case 'link_group':
				return { links: linkGroupLinks.filter((l) => l.url.trim()), collapsible: linkGroupCollapsible };
			case 'camera':
				return { streamUrl: cameraStreamUrl, type: cameraType, refreshInterval: cameraRefreshInterval, aspectRatio: cameraAspectRatio };
			case 'integration':
				return { appId: integrationAppId, endpointId: integrationEndpointId, refreshInterval: integrationRefreshInterval };
			default:
				return {};
		}
	}

	function handleSave() {
		onSave(buildConfig());
	}

	function handleKeydown(e: KeyboardEvent) {
		if (e.key === 'Escape') onCancel();
	}

	function addLinkGroupLink() {
		linkGroupLinks = [...linkGroupLinks, { label: '', url: '', icon: '' }];
	}

	function removeLinkGroupLink(index: number) {
		linkGroupLinks = linkGroupLinks.filter((_, i) => i !== index);
	}

	function addCalendarUrl() {
		calendarUrlsRaw = [...calendarUrlsRaw, { url: '', color: '#e8754f', label: '' }];
	}

	function removeCalendarUrl(index: number) {
		calendarUrlsRaw = calendarUrlsRaw.filter((_, i) => i !== index);
	}

	// Helper for input styling
	const inputClass = 'w-full rounded-xl border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground transition-colors focus:border-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/30';
	const labelClass = 'mb-1 block text-sm font-medium text-foreground';

	let firstInput: HTMLElement | undefined = $state();
	$effect(() => { tick().then(() => firstInput?.focus()); });
</script>

<div
	class="rounded-xl border border-border bg-card p-4 shadow-[var(--shadow-soft)]"
	transition:fade={{ duration: 100 }}
	onkeydown={handleKeydown}
	role="dialog"
	tabindex="-1"
>
	<div class="mb-3 flex items-center justify-between">
		<h3 class="text-sm font-semibold text-foreground">
			{mode === 'create' ? ($t('widget.add_widget') ?? 'Add Widget') : ($t('widget.edit_widget') ?? 'Edit Widget')}
			<span class="ml-1 text-xs font-normal text-muted-foreground">({widgetType})</span>
		</h3>
		<button type="button" onclick={onCancel} aria-label="Close" class="rounded p-0.5 text-muted-foreground hover:text-foreground">
			<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></svg>
		</button>
	</div>

	<div class="max-h-80 space-y-3 overflow-y-auto">
		{#if widgetType === 'app'}
			<div>
				<div class={labelClass}>{$t('widget.app') ?? 'App'}</div>
				<!-- Search -->
				<div class="relative mb-2">
					<svg class="absolute left-2.5 top-1/2 -translate-y-1/2 text-muted-foreground" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
						<circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" />
					</svg>
					<input
						type="text"
						bind:value={appSearchQuery}
						bind:this={firstInput}
						placeholder={$t('common.search') ?? 'Search apps...'}
						class="w-full rounded-xl border border-input bg-background py-1.5 pl-8 pr-3 text-sm text-foreground placeholder:text-muted-foreground focus:border-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/30"
					/>
				</div>
				<!-- App grid -->
				<div class="max-h-48 overflow-y-auto rounded-xl border border-input bg-background p-1">
					{#if filteredApps.length === 0}
						<p class="py-4 text-center text-xs text-muted-foreground">{$t('common.no_results') ?? 'No apps found'}</p>
					{:else}
						<div class="grid grid-cols-2 gap-1">
							{#each filteredApps as app (app.id)}
								<button
									type="button"
									onclick={() => { appId = app.id; }}
									class="flex items-center gap-2 rounded-lg px-2.5 py-2 text-left text-sm transition-colors
										{appId === app.id
											? 'bg-primary/10 text-primary ring-1 ring-primary/30'
											: 'text-foreground hover:bg-accent'}"
								>
									{#if app.icon && app.iconType === 'lucide'}
										<DynamicIcon name={app.icon} size={18} />
									{:else if app.icon && app.iconType === 'url'}
										<img src={app.icon} alt="" class="h-[18px] w-[18px] rounded object-contain" />
									{:else if app.icon && app.iconType === 'simple'}
										<img src="https://cdn.simpleicons.org/{app.icon.toLowerCase()}" alt="" class="h-[18px] w-[18px]" />
									{:else if app.icon && app.iconType === 'emoji'}
										<span class="text-base leading-none">{app.icon}</span>
									{:else}
										<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="text-muted-foreground">
											<rect x="2" y="3" width="20" height="14" rx="2" /><line x1="8" y1="21" x2="16" y2="21" /><line x1="12" y1="17" x2="12" y2="21" />
										</svg>
									{/if}
									<span class="truncate">{app.name}</span>
								</button>
							{/each}
						</div>
					{/if}
				</div>
			</div>

		{:else if widgetType === 'bookmark'}
			<div>
				<label class={labelClass}>URL
				<input type="url" bind:value={bookmarkUrl} placeholder="https://..." class={inputClass} bind:this={firstInput} />
				</label>
			</div>
			<div>
				<label class={labelClass}>{$t('common.label') ?? 'Label'}
				<input type="text" bind:value={bookmarkLabel} class={inputClass} />
				</label>
			</div>
			<div>
				<label class={labelClass}>{$t('app.icon') ?? 'Icon'}
				<input type="text" bind:value={bookmarkIcon} placeholder="e.g. globe" class={inputClass} />
				</label>
			</div>
			<div>
				<label class={labelClass}>{$t('common.description') ?? 'Description'}
				<input type="text" bind:value={bookmarkDescription} class={inputClass} />
				</label>
			</div>

		{:else if widgetType === 'note'}
			<div>
				<label class={labelClass}>{$t('widget.content') ?? 'Content'}
				<textarea bind:value={noteContent} rows="4" class={inputClass} bind:this={firstInput}></textarea>
				</label>
			</div>
			<div>
				<label class={labelClass}>{$t('widget.format') ?? 'Format'}
				<select bind:value={noteFormat} class={inputClass}>
					<option value="markdown">Markdown</option>
					<option value="text">Plain Text</option>
					<option value="html">HTML</option>
				</select>
				</label>
			</div>

		{:else if widgetType === 'embed'}
			<div>
				<label class={labelClass}>URL
				<input type="url" bind:value={embedUrl} placeholder="https://..." class={inputClass} bind:this={firstInput} />
				</label>
			</div>
			<div>
				<label class={labelClass}>{$t('widget.height') ?? 'Height'} ({embedHeight}px)
				<input type="range" min="100" max="800" bind:value={embedHeight} class="w-full accent-primary" />
				</label>
			</div>
			<div>
				<label class={labelClass}>Sandbox
				<input type="text" bind:value={embedSandbox} placeholder="allow-scripts allow-same-origin" class={inputClass} />
				</label>
			</div>

		{:else if widgetType === 'status'}
			<div>
				<label class={labelClass}>{$t('common.label') ?? 'Label'}
				<input type="text" bind:value={statusLabel} class={inputClass} bind:this={firstInput} />
				</label>
			</div>
			<div>
				<div class={labelClass}>{$t('widget.apps') ?? 'Apps'}</div>
				<MultiEntityPicker
					items={apps.map((a) => ({ value: a.id, label: a.name, icon: a.icon, iconType: a.iconType }))}
					bind:values={statusAppIds}
					placeholder={$t('widget.select_apps') ?? 'Select apps...'}
					searchPlaceholder={$t('common.search') ?? 'Search...'}
				/>
			</div>

		{:else if widgetType === 'clock'}
			<div>
				<label class={labelClass}>{$t('widget.timezone') ?? 'Timezone'}
				<input type="text" bind:value={clockTimezone} placeholder="America/New_York" class={inputClass} bind:this={firstInput} />
				</label>
			</div>
			<div>
				<label class={labelClass}>{$t('widget.style') ?? 'Style'}
				<select bind:value={clockStyle} class={inputClass}>
					<option value="digital">Digital</option>
					<option value="analog">Analog</option>
					<option value="24h">24h</option>
				</select>
				</label>
			</div>
			<label class="flex items-center gap-2 text-sm text-foreground">
				<input type="checkbox" bind:checked={clockShowWeather} class="h-3.5 w-3.5 rounded border-input accent-primary" />
				{$t('widget.show_weather') ?? 'Show Weather'}
			</label>
			{#if clockShowWeather}
				<div class="grid grid-cols-2 gap-2">
					<div>
						<label class={labelClass}>Latitude
						<input type="text" bind:value={clockLatitude} class={inputClass} />
						</label>
					</div>
					<div>
						<label class={labelClass}>Longitude
						<input type="text" bind:value={clockLongitude} class={inputClass} />
						</label>
					</div>
				</div>
			{/if}

		{:else if widgetType === 'system_stats'}
			<div>
				<label class={labelClass}>Source URL
				<input type="url" bind:value={sysStatsSourceUrl} placeholder="http://localhost:61208/api/3" class={inputClass} bind:this={firstInput} />
				</label>
			</div>
			<div>
				<label class={labelClass}>Source Type
				<select bind:value={sysStatsSourceType} class={inputClass}>
					<option value="glances">Glances</option>
					<option value="prometheus">Prometheus</option>
					<option value="custom">Custom</option>
				</select>
				</label>
			</div>
			<div>
				<label class={labelClass}>Refresh ({sysStatsRefreshInterval}s)
				<input type="range" min="5" max="300" bind:value={sysStatsRefreshInterval} class="w-full accent-primary" />
				</label>
			</div>

		{:else if widgetType === 'rss'}
			<div>
				<label class={labelClass}>Feed URL
				<input type="url" bind:value={rssFeedUrl} placeholder="https://..." class={inputClass} bind:this={firstInput} />
				</label>
			</div>
			<div>
				<label class={labelClass}>Max Items ({rssMaxItems})
				<input type="range" min="1" max="50" bind:value={rssMaxItems} class="w-full accent-primary" />
				</label>
			</div>
			<label class="flex items-center gap-2 text-sm text-foreground">
				<input type="checkbox" bind:checked={rssShowSummary} class="h-3.5 w-3.5 rounded border-input accent-primary" />
				Show Summary
			</label>

		{:else if widgetType === 'calendar'}
			<div>
				<div class={labelClass}>iCal URLs</div>
				{#each calendarUrlsRaw as cal, i (i)}
					<div class="mb-1 flex items-center gap-1">
						<input type="url" bind:value={cal.url} placeholder="https://..." class="{inputClass} flex-1" />
						<input type="text" bind:value={cal.label} placeholder="Label" class="{inputClass} w-20" />
						<input type="color" bind:value={cal.color} class="h-8 w-8 cursor-pointer rounded border-0" />
						{#if calendarUrlsRaw.length > 1}
							<button type="button" onclick={() => removeCalendarUrl(i)} class="text-destructive hover:text-destructive/80">&times;</button>
						{/if}
					</div>
				{/each}
				<button type="button" onclick={addCalendarUrl} class="text-xs text-primary hover:underline">+ Add URL</button>
			</div>
			<div>
				<label class={labelClass}>Days Ahead ({calendarDaysAhead})
				<input type="range" min="1" max="30" bind:value={calendarDaysAhead} class="w-full accent-primary" />
				</label>
			</div>

		{:else if widgetType === 'markdown'}
			<div>
				<label class={labelClass}>{$t('widget.content') ?? 'Content'}
				<textarea bind:value={markdownContent} rows="6" class="{inputClass} font-mono text-xs" bind:this={firstInput}></textarea>
				</label>
			</div>

		{:else if widgetType === 'metric'}
			<div>
				<label class={labelClass}>{$t('common.label') ?? 'Label'}
				<input type="text" bind:value={metricLabel} class={inputClass} bind:this={firstInput} />
				</label>
			</div>
			<div>
				<label class={labelClass}>Source
				<select bind:value={metricSource} class={inputClass}>
					<option value="static">Static</option>
					<option value="json">JSON Endpoint</option>
					<option value="prometheus">Prometheus</option>
				</select>
				</label>
			</div>
			{#if metricSource === 'static'}
				<div>
					<label class={labelClass}>Value
					<input type="text" bind:value={metricValue} class={inputClass} />
					</label>
				</div>
			{:else if metricSource === 'json'}
				<div>
					<label class={labelClass}>URL
					<input type="url" bind:value={metricUrl} class={inputClass} />
				</label>
				</div>
				<div>
					<label class={labelClass}>JSON Path
					<input type="text" bind:value={metricJsonPath} placeholder="$.data.value" class={inputClass} />
				</label>
				</div>
			{:else if metricSource === 'prometheus'}
				<div>
					<label class={labelClass}>URL
					<input type="url" bind:value={metricUrl} class={inputClass} />
				</label>
				</div>
				<div>
					<label class={labelClass}>PromQL Query
					<input type="text" bind:value={metricQuery} class={inputClass} />
				</label>
				</div>
			{/if}
			<div class="grid grid-cols-2 gap-2">
				<div>
					<label class={labelClass}>Unit
					<input type="text" bind:value={metricUnit} placeholder="%" class={inputClass} />
					</label>
				</div>
				<div>
					<label class={labelClass}>Refresh ({metricRefreshInterval}s)
					<input type="range" min="5" max="300" bind:value={metricRefreshInterval} class="w-full accent-primary" />
					</label>
				</div>
			</div>

		{:else if widgetType === 'link_group'}
			<div>
				<div class={labelClass}>Links</div>
				{#each linkGroupLinks as link, i (i)}
					<div class="mb-1 flex items-center gap-1">
						<input type="text" bind:value={link.label} placeholder="Label" class="{inputClass} w-24" />
						<input type="url" bind:value={link.url} placeholder="URL" class="{inputClass} flex-1" />
						<input type="text" bind:value={link.icon} placeholder="Icon" class="{inputClass} w-16" />
						{#if linkGroupLinks.length > 1}
							<button type="button" onclick={() => removeLinkGroupLink(i)} class="text-destructive hover:text-destructive/80">&times;</button>
						{/if}
					</div>
				{/each}
				<button type="button" onclick={addLinkGroupLink} class="text-xs text-primary hover:underline">+ Add Link</button>
			</div>
			<label class="flex items-center gap-2 text-sm text-foreground">
				<input type="checkbox" bind:checked={linkGroupCollapsible} class="h-3.5 w-3.5 rounded border-input accent-primary" />
				Collapsible
			</label>

		{:else if widgetType === 'camera'}
			<div>
				<label class={labelClass}>Stream URL
				<input type="url" bind:value={cameraStreamUrl} placeholder="https://..." class={inputClass} bind:this={firstInput} />
				</label>
			</div>
			<div>
				<label class={labelClass}>Type
				<select bind:value={cameraType} class={inputClass}>
					<option value="image">Image</option>
					<option value="mjpeg">MJPEG</option>
					<option value="hls">HLS</option>
				</select>
				</label>
			</div>
			<div>
				<label class={labelClass}>Refresh ({cameraRefreshInterval}s)
				<input type="range" min="1" max="60" bind:value={cameraRefreshInterval} class="w-full accent-primary" />
				</label>
			</div>
			<div>
				<label class={labelClass}>Aspect Ratio
				<select bind:value={cameraAspectRatio} class={inputClass}>
					<option value="16/9">16:9</option>
					<option value="4/3">4:3</option>
					<option value="1/1">1:1</option>
				</select>
				</label>
			</div>

		{:else if widgetType === 'integration'}
			<div>
				<label class={labelClass}>{$t('widget.app') ?? 'App'}
				<select bind:value={integrationAppId} class={inputClass} bind:this={firstInput}>
					<option value="">Select app...</option>
					{#each apps as app (app.id)}
						<option value={app.id}>{app.name}</option>
					{/each}
				</select>
				</label>
			</div>
			<div>
				<label class={labelClass}>Endpoint ID
				<input type="text" bind:value={integrationEndpointId} class={inputClass} />
				</label>
			</div>
			<div>
				<label class={labelClass}>Refresh ({integrationRefreshInterval}s)
				<input type="range" min="10" max="600" bind:value={integrationRefreshInterval} class="w-full accent-primary" />
				</label>
			</div>
		{/if}
	</div>

	<!-- Footer -->
	<div class="mt-3 flex items-center justify-end gap-2 border-t border-border pt-3">
		<button type="button" onclick={onCancel}
			class="rounded-lg border border-border px-3 py-1.5 text-sm text-foreground transition-colors hover:bg-accent">
			{$t('common.cancel') ?? 'Cancel'}
		</button>
		<button type="button" onclick={handleSave}
			class="rounded-xl bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90">
			{mode === 'create' ? ($t('common.add') ?? 'Add') : ($t('common.save') ?? 'Save')}
		</button>
	</div>
</div>
