<script lang="ts">
	import { onMount } from 'svelte';
	import { slide } from 'svelte/transition';
	import { api } from '$lib/api';
	import { t } from '$lib/i18n';
	import { commandTemplateConfigsCache } from '$lib/stores/caches.svelte';
	import PageHeader from '$lib/components/PageHeader.svelte';
	import Card from '$lib/components/Card.svelte';
	import Loading from '$lib/components/Loading.svelte';
	import IconPicker from '$lib/components/IconPicker.svelte';
	import MdiIcon from '$lib/components/MdiIcon.svelte';
	import EmptyState from '$lib/components/EmptyState.svelte';
	import ConfirmModal from '$lib/components/ConfirmModal.svelte';
	import IconButton from '$lib/components/IconButton.svelte';
	import IconGridSelect from '$lib/components/IconGridSelect.svelte';
	import { providerTypeItems as providerTypeItemsFn } from '$lib/grid-items';
	import Modal from '$lib/components/Modal.svelte';
	import JinjaEditor from '$lib/components/JinjaEditor.svelte';
	import { snackSuccess, snackError } from '$lib/stores/snackbar.svelte';
	import { highlightFromUrl } from '$lib/highlight';

	interface CmdTemplateConfig {
		id: number;
		user_id: number;
		provider_type: string;
		name: string;
		description: string;
		icon: string;
		slots: Record<string, Record<string, string>>;
		created_at: string;
	}

	interface SlotDef {
		name: string;
		description: string;
	}

	const LOCALES = ['en', 'ru'] as const;

	let configs = $state<CmdTemplateConfig[]>([]);
	let loaded = $state(false);
	let showForm = $state(false);
	let editing = $state<number | null>(null);
	let error = $state('');
	let confirmDelete = $state<{ id: number; onconfirm: () => Promise<void> } | null>(null);
	let slotPreview = $state<Record<string, string>>({});
	let slotErrors = $state<Record<string, string>>({});
	let slotErrorLines = $state<Record<string, number | null>>({});
	let slotErrorTypes = $state<Record<string, string>>({});
	let validateTimers: Record<string, ReturnType<typeof setTimeout>> = {};
	let varsRef = $state<Record<string, any>>({});
	let showVarsFor = $state<string | null>(null);
	let activeLocale = $state<string>('en');

	// Provider capabilities
	let allCapabilities = $state<Record<string, any>>({});
	let providerTypes = $derived(Object.keys(allCapabilities));
	let commandSlots = $derived<SlotDef[]>(
		allCapabilities[form.provider_type]?.command_slots || []
	);

	const defaultForm = () => ({
		provider_type: 'immich',
		name: '',
		description: '',
		icon: '',
		slots: {} as Record<string, Record<string, string>>,
	});
	let form = $state(defaultForm());

	/** Get slot template for current locale, with fallback. */
	function getSlotValue(slotName: string): string {
		return form.slots[slotName]?.[activeLocale] || '';
	}

	/** Set slot template for current locale. */
	function setSlotValue(slotName: string, value: string) {
		if (!form.slots[slotName]) form.slots[slotName] = {};
		form.slots[slotName][activeLocale] = value;
	}

	onMount(load);

	async function load() {
		try {
			const [cfgs, caps, vars] = await Promise.all([
				commandTemplateConfigsCache.fetch(true),
				api('/providers/capabilities'),
				api('/command-template-configs/variables'),
			]);
			configs = cfgs;
			allCapabilities = caps;
			varsRef = vars;
		} catch (err: any) {
			error = err.message || t('common.loadError');
			snackError(error);
		} finally {
			loaded = true;
			highlightFromUrl();
		}
	}

	function validateSlot(slotKey: string, template: string, immediate = false) {
		if (validateTimers[slotKey]) clearTimeout(validateTimers[slotKey]);
		if (!template) {
			slotErrors = { ...slotErrors, [slotKey]: '' };
			slotErrorLines = { ...slotErrorLines, [slotKey]: null };
			slotErrorTypes = { ...slotErrorTypes, [slotKey]: '' };
			const { [slotKey]: _, ...rest } = slotPreview;
			slotPreview = rest;
			return;
		}

		const doValidate = async () => {
			try {
				const res = await api('/command-template-configs/preview-raw', {
					method: 'POST',
					body: JSON.stringify({ template }),
				});
				slotErrors = { ...slotErrors, [slotKey]: res.error || '' };
				slotErrorLines = { ...slotErrorLines, [slotKey]: res.error_line || null };
				slotErrorTypes = { ...slotErrorTypes, [slotKey]: res.error_type || '' };
				if (res.rendered) {
					slotPreview = { ...slotPreview, [slotKey]: res.rendered };
				} else {
					const { [slotKey]: _, ...rest } = slotPreview;
					slotPreview = rest;
				}
			} catch {
				slotErrors = { ...slotErrors, [slotKey]: '' };
			}
		};
		if (immediate) doValidate();
		else validateTimers[slotKey] = setTimeout(doValidate, 800);
	}

	function refreshAllPreviews() {
		for (const slot of commandSlots) {
			const template = getSlotValue(slot.name);
			if (template) validateSlot(slot.name, template, true);
		}
	}

	function openNew() {
		form = defaultForm();
		editing = null;
		showForm = true;
		activeLocale = 'en';
		slotPreview = {};
		slotErrors = {};
	}

	function edit(c: CmdTemplateConfig) {
		// Deep copy nested slots
		const slotsCopy: Record<string, Record<string, string>> = {};
		for (const [k, v] of Object.entries(c.slots)) {
			slotsCopy[k] = { ...v };
		}
		form = {
			provider_type: c.provider_type,
			name: c.name,
			description: c.description || '',
			icon: c.icon || '',
			slots: slotsCopy,
		};
		editing = c.id;
		showForm = true;
		activeLocale = 'en';
		slotPreview = {};
		slotErrors = {};
		setTimeout(() => refreshAllPreviews(), 100);
	}

	async function save(e: SubmitEvent) {
		e.preventDefault();
		error = '';
		try {
			if (editing) {
				await api(`/command-template-configs/${editing}`, { method: 'PUT', body: JSON.stringify(form) });
			} else {
				await api('/command-template-configs', { method: 'POST', body: JSON.stringify(form) });
			}
			showForm = false;
			editing = null;
			await load();
			snackSuccess(t('snack.cmdTemplateSaved'));
		} catch (err: any) {
			error = err.message;
			snackError(err.message);
		}
	}

	function clone(c: CmdTemplateConfig) {
		const slotsCopy: Record<string, Record<string, string>> = {};
		for (const [k, v] of Object.entries(c.slots)) {
			slotsCopy[k] = { ...v };
		}
		form = {
			provider_type: c.provider_type,
			name: `${c.name} (Copy)`,
			description: c.description || '',
			icon: c.icon || '',
			slots: slotsCopy,
		};
		editing = null;
		showForm = true;
		activeLocale = 'en';
		slotPreview = {};
		slotErrors = {};
		setTimeout(() => refreshAllPreviews(), 100);
	}

	function remove(id: number) {
		confirmDelete = {
			id,
			onconfirm: async () => {
				try {
					await api(`/command-template-configs/${id}`, { method: 'DELETE' });
					await load();
					snackSuccess(t('snack.cmdTemplateDeleted'));
				} catch (err: any) {
					error = err.message;
					snackError(err.message);
				} finally {
					confirmDelete = null;
				}
			},
		};
	}
</script>

<PageHeader title={t('cmdTemplateConfig.title')} description={t('cmdTemplateConfig.description')}>
	<button onclick={() => { showForm ? (showForm = false, editing = null) : openNew(); }}
		class="px-3 py-1.5 bg-[var(--color-primary)] text-[var(--color-primary-foreground)] rounded-md text-sm font-medium hover:opacity-90">
		{showForm ? t('common.cancel') : t('cmdTemplateConfig.newConfig')}
	</button>
</PageHeader>

{#if !loaded}<Loading />{:else}

{#if showForm}
<div in:slide={{ duration: 200 }}>
<Card class="mb-6">
	{#if error}<div class="bg-[var(--color-error-bg)] text-[var(--color-error-fg)] text-sm rounded-md p-3 mb-4">{error}</div>{/if}
	<form onsubmit={save} class="space-y-5">
		<div>
			<label for="ct-name" class="block text-sm font-medium mb-1">{t('cmdTemplateConfig.name')}</label>
			<div class="flex gap-2">
				<IconPicker value={form.icon} onselect={(v: string) => form.icon = v} />
				<input id="ct-name" bind:value={form.name} required placeholder={t('cmdTemplateConfig.namePlaceholder')}
					class="flex-1 px-3 py-2 border border-[var(--color-border)] rounded-md text-sm bg-[var(--color-background)]" />
			</div>
		</div>
		<div>
			<label for="ct-desc" class="block text-sm font-medium mb-1">{t('common.description')}</label>
			<input id="ct-desc" bind:value={form.description} placeholder={t('cmdTemplateConfig.descriptionPlaceholder')}
				class="w-full px-3 py-2 border border-[var(--color-border)] rounded-md text-sm bg-[var(--color-background)]" />
		</div>

		{#if !editing}
		<div>
			<label class="block text-sm font-medium mb-1">{t('templateConfig.providerType')}</label>
			<IconGridSelect items={providerTypeItemsFn()} bind:value={form.provider_type} columns={2} />
		</div>
		{:else}
		<div>
			<span class="block text-sm font-medium mb-1">{t('templateConfig.providerType')}</span>
			<span class="text-sm text-[var(--color-muted-foreground)]">{allCapabilities[form.provider_type]?.display_name || form.provider_type}</span>
		</div>
		{/if}

		<fieldset class="border border-[var(--color-border)] rounded-md p-3">
			<legend class="text-sm font-medium px-1">{t('cmdTemplateConfig.commandResponses')}</legend>
			<p class="text-xs text-[var(--color-muted-foreground)] mb-2">{t('cmdTemplateConfig.commandResponsesHint')}</p>

			<!-- Locale tabs -->
			<div class="flex gap-1 mb-3 border-b border-[var(--color-border)]">
				{#each LOCALES as loc}
					<button type="button"
						class="px-3 py-1.5 text-xs font-medium rounded-t-md transition-colors {activeLocale === loc ? 'bg-[var(--color-primary)] text-[var(--color-primary-foreground)]' : 'text-[var(--color-muted-foreground)] hover:bg-[var(--color-muted)]'}"
						onclick={() => { activeLocale = loc; refreshAllPreviews(); }}>
						{loc.toUpperCase()}
					</button>
				{/each}
			</div>

			<div class="space-y-3">
				{#each commandSlots as slot}
					<div>
						<div class="flex items-center justify-between mb-1">
							<label class="text-xs text-[var(--color-muted-foreground)]">/{slot.name} — {slot.description}</label>
							{#if varsRef[slot.name]}
								<button type="button" onclick={() => showVarsFor = slot.name}
									class="text-xs text-[var(--color-muted-foreground)] hover:underline">{t('templateConfig.variables')}</button>
							{/if}
						</div>
						<JinjaEditor
							value={getSlotValue(slot.name)}
							onchange={(v: string) => { setSlotValue(slot.name, v); validateSlot(slot.name, v); }}
							rows={3}
							errorLine={slotErrorLines[slot.name] || null}
						/>
						{#if slotErrors[slot.name]}
							{#if slotErrorTypes[slot.name] === 'undefined'}
								<p class="mt-1 text-xs" style="color: #d97706;">⚠ {t('common.undefinedVar')}: {slotErrors[slot.name]}</p>
							{:else}
								<p class="mt-1 text-xs" style="color: var(--color-error-fg);">✕ {t('common.syntaxError')}: {slotErrors[slot.name]}{slotErrorLines[slot.name] ? ` (${t('common.line')} ${slotErrorLines[slot.name]})` : ''}</p>
							{/if}
						{/if}
						{#if slotPreview[slot.name] && !slotErrors[slot.name]}
							<div class="mt-1 p-2 bg-[var(--color-muted)] rounded text-sm">
								<pre class="whitespace-pre-wrap text-xs">{slotPreview[slot.name]}</pre>
							</div>
						{/if}
					</div>
				{/each}
			</div>
		</fieldset>

		<button type="submit" class="px-4 py-2 bg-[var(--color-primary)] text-[var(--color-primary-foreground)] rounded-md text-sm font-medium hover:opacity-90">
			{editing ? t('common.save') : t('common.create')}
		</button>
	</form>
</Card>
</div>
{/if}

{#if configs.length === 0 && !showForm}
	<Card>
		<EmptyState icon="mdiConsoleLine" message={t('cmdTemplateConfig.noConfigs')} />
	</Card>
{:else}
	<div class="space-y-3 stagger-children">
		{#each configs as config}
			<Card hover entityId={config.id}>
				<div class="flex items-start justify-between">
					<div class="flex-1">
						<div class="flex items-center gap-2">
							<span style="color: var(--color-primary);"><MdiIcon name={config.icon || 'mdiConsoleLine'} size={20} /></span>
							<p class="font-medium">{config.name}</p>
							<span class="text-xs px-1.5 py-0.5 rounded bg-[var(--color-muted)] text-[var(--color-muted-foreground)]">{config.provider_type}</span>
							{#if config.user_id === 0}
								<span class="text-xs px-1.5 py-0.5 rounded bg-[var(--color-muted)] text-[var(--color-muted-foreground)]">System</span>
							{/if}
							<span class="text-xs px-1.5 py-0.5 rounded bg-[var(--color-muted)] text-[var(--color-muted-foreground)]">{Object.keys(config.slots).length} slots</span>
						</div>
						{#if config.description}
							<p class="text-sm text-[var(--color-muted-foreground)] mt-1">{config.description}</p>
						{/if}
					</div>
					<div class="flex items-center gap-1 ml-4">
						<IconButton icon="mdiContentCopy" title={t('common.clone')} onclick={() => clone(config)} />
						<IconButton icon="mdiPencil" title={t('common.edit')} onclick={() => edit(config)} />
						<IconButton icon="mdiDelete" title={t('common.delete')} onclick={() => remove(config.id)} variant="danger" />
					</div>
				</div>
			</Card>
		{/each}
	</div>
{/if}

{/if}

<ConfirmModal open={confirmDelete !== null} message={t('cmdTemplateConfig.confirmDelete')}
	onconfirm={() => confirmDelete?.onconfirm()} oncancel={() => confirmDelete = null} />

<!-- Variables reference modal -->
<Modal open={showVarsFor !== null} title="{t('templateConfig.variables')}: /{showVarsFor || ''}" onclose={() => showVarsFor = null}>
	{#if showVarsFor && varsRef[showVarsFor]}
		<p class="text-sm text-[var(--color-muted-foreground)] mb-3">{varsRef[showVarsFor].description}</p>
		<div class="space-y-1">
			<p class="text-xs font-medium mb-1">{t('templateConfig.variables')}:</p>
			{#each Object.entries(varsRef[showVarsFor].variables || {}) as [name, desc]}
				<div class="flex items-start gap-2 text-sm">
					<code class="text-xs bg-[var(--color-muted)] px-1 py-0.5 rounded font-mono whitespace-nowrap">{'{{ ' + name + ' }}'}</code>
					<span class="text-xs text-[var(--color-muted-foreground)]">{desc}</span>
				</div>
			{/each}
		</div>
		{#each [
			['asset_fields', 'asset', 'Asset fields'],
			['album_fields', 'album', 'Album fields'],
			['command_fields', 'cmd', 'Command fields'],
			['event_fields', 'event', 'Event fields'],
		] as [fieldKey, prefix, title]}
			{#if varsRef[showVarsFor][fieldKey]}
				<div class="mt-3 pt-3 border-t border-[var(--color-border)]">
					<p class="text-xs font-medium mb-1">{title} <span class="font-normal text-[var(--color-muted-foreground)]">(use {prefix}.field)</span>:</p>
					{#each Object.entries(varsRef[showVarsFor][fieldKey]) as [name, desc]}
						<div class="flex items-start gap-2 text-sm">
							<code class="text-xs bg-[var(--color-muted)] px-1 py-0.5 rounded font-mono whitespace-nowrap">{'{{ ' + prefix + '.' + name + ' }}'}</code>
							<span class="text-xs text-[var(--color-muted-foreground)]">{desc}</span>
						</div>
					{/each}
				</div>
			{/if}
		{/each}
	{/if}
</Modal>
