<!--
  Settings › DNS

  Wildcard vs. per-subdomain DNS, and Cloudflare provider configuration.
  Split out of the General page so the token, zone picker, and "test
  connection" flow aren't buried under unrelated infra fields.
-->
<script lang="ts">
	import { onMount } from 'svelte';
	import { get } from 'svelte/store';
	import { updateSettings, testDnsConnection, listDnsZones } from '$lib/api';
	import type { EntityPickerItem, Settings } from '$lib/types';
	import { settingsCache } from '$lib/stores/caches';
	import FormField from '$lib/components/FormField.svelte';
	import EntityPicker from '$lib/components/EntityPicker.svelte';
	import Skeleton from '$lib/components/Skeleton.svelte';
	import ToggleSwitch from '$lib/components/ToggleSwitch.svelte';
	import { toasts } from '$lib/stores/toast';
	import { t } from '$lib/i18n';
	import { IconLoader, IconX } from '$lib/components/icons';

	let loading = $state(true);
	let saving = $state(false);

	let wildcardDns = $state(true);
	let dnsProvider = $state('');
	let cloudflareApiToken = $state('');
	let hasCloudflareApiToken = $state(false);
	let cloudflareZoneId = $state('');
	let zonePickerOpen = $state(false);
	let zonePickerItems = $state<EntityPickerItem[]>([]);
	let loadingZones = $state(false);
	let zoneName = $state('');
	let testingDns = $state(false);

	// Seed once from the shared settings cache (warm → no skeleton on revisit);
	// never re-applied during background refresh, so unsaved edits are safe.
	function seed(s: Settings) {
		wildcardDns = s.wildcard_dns ?? true;
		dnsProvider = s.dns_provider ?? '';
		hasCloudflareApiToken = s.has_cloudflare_api_token ?? false;
		cloudflareZoneId = s.cloudflare_zone_id ?? '';
		if (!wildcardDns && cloudflareZoneId) resolveZoneName();
	}

	async function loadSettings() {
		const cached = get(settingsCache).value;
		if (cached) {
			seed(cached);
			loading = false;
		}
		await settingsCache.refresh();
		const fresh = get(settingsCache).value;
		if (fresh && loading) seed(fresh);
		loading = false;
		const { error } = get(settingsCache);
		if (error && !cached) toasts.error(error || $t('settingsGeneral.loadFailed'));
	}

	async function handleSave() {
		saving = true;
		try {
			const payload: Partial<Settings> = {
				wildcard_dns: wildcardDns,
				dns_provider: wildcardDns ? '' : dnsProvider,
				cloudflare_zone_id: cloudflareZoneId
			};
			if (cloudflareApiToken) payload.cloudflare_api_token = cloudflareApiToken;
			await updateSettings(payload);
			// PUT returns {status:"updated"}, not Settings — refetch the cache.
			await settingsCache.refresh();
			toasts.success($t('settingsGeneral.saved'));
			cloudflareApiToken = '';
			hasCloudflareApiToken = hasCloudflareApiToken || Boolean(payload.cloudflare_api_token);
		} catch (err) {
			toasts.error(err instanceof Error ? err.message : $t('settingsGeneral.saveFailed'));
		} finally {
			saving = false;
		}
	}

	async function openZonePicker() {
		loadingZones = true;
		zonePickerOpen = true;
		try {
			const token = cloudflareApiToken || undefined;
			const zones = await listDnsZones(token);
			zonePickerItems = zones.map((zone): EntityPickerItem => ({
				value: zone.id,
				label: zone.name,
				description: zone.id
			}));
			if (zonePickerItems.length === 0) {
				toasts.error($t('settingsGeneral.noZonesFound'));
				zonePickerOpen = false;
			}
		} catch (err) {
			toasts.error(err instanceof Error ? err.message : $t('settingsGeneral.noZonesFound'));
			zonePickerOpen = false;
		} finally {
			loadingZones = false;
		}
	}

	function handleZoneSelect(value: string) {
		cloudflareZoneId = value;
		const item = zonePickerItems.find((i) => i.value === value);
		zoneName = item?.label ?? '';
		zonePickerOpen = false;
	}

	async function handleTestDns() {
		testingDns = true;
		try {
			const token = cloudflareApiToken || '';
			const result = await testDnsConnection('cloudflare', token, cloudflareZoneId);
			if (result.success) {
				toasts.success($t('settingsGeneral.connectionSuccess'));
			} else {
				toasts.error(`${$t('settingsGeneral.connectionFailed')}: ${result.error}`);
			}
		} catch (err) {
			toasts.error(err instanceof Error ? err.message : $t('settingsGeneral.connectionFailed'));
		} finally {
			testingDns = false;
		}
	}

	async function resolveZoneName() {
		if (!cloudflareZoneId) return;
		try {
			const zones = await listDnsZones();
			const match = zones.find((z) => z.id === cloudflareZoneId);
			zoneName = match?.name ?? cloudflareZoneId;
		} catch {
			zoneName = cloudflareZoneId;
		}
	}

	onMount(loadSettings);
</script>

<svelte:head>
	<title>{$t('settingsDns.title')} - {$t('app.name')}</title>
</svelte:head>

<div class="space-y-6">
	{#if loading}
		<div class="space-y-4">
			<Skeleton height="2rem" width="12rem" />
			<Skeleton height="4rem" />
			<Skeleton height="12rem" />
		</div>
	{:else}
		<div class="rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] p-6 shadow-[var(--shadow-sm)]">
			<h2 class="mb-1 text-lg font-semibold text-[var(--text-primary)]">{$t('settingsDns.title')}</h2>
			<p class="mb-4 text-sm text-[var(--text-secondary)]">{$t('settingsDns.description')}</p>

			<div class="flex items-center gap-3">
				<ToggleSwitch bind:checked={wildcardDns} label={$t('settingsGeneral.wildcardDns')} />
				<div>
					<span class="text-sm font-medium text-[var(--text-primary)]">{$t('settingsGeneral.wildcardDns')}</span>
					<p class="text-xs text-[var(--text-tertiary)]">{$t('settingsGeneral.wildcardDnsHelp')}</p>
				</div>
			</div>

			{#if !wildcardDns}
				<div class="mt-4 space-y-4 rounded-lg border border-[var(--border-primary)] bg-[var(--surface-card-hover)] p-4">
					<div>
						<label for="dnsProvider" class="block text-sm font-medium text-[var(--text-primary)]">{$t('settingsGeneral.dnsProvider')}</label>
						<p class="mt-0.5 text-xs text-[var(--text-tertiary)]">{$t('settingsGeneral.dnsProviderHelp')}</p>
						<select id="dnsProvider" bind:value={dnsProvider}
							class="mt-1.5 w-full max-w-xs rounded-lg border border-[var(--border-primary)] bg-[var(--surface-card)] px-3 py-2 text-sm text-[var(--text-primary)] focus:border-[var(--color-brand-500)] focus:outline-none focus:ring-1 focus:ring-[var(--color-brand-500)]">
							<option value="">-- Select --</option>
							<option value="cloudflare">Cloudflare</option>
						</select>
					</div>

					{#if dnsProvider === 'cloudflare'}
						<div>
							<FormField
								label={$t('settingsGeneral.cloudflareApiToken')}
								name="cloudflareApiToken"
								type="password"
								bind:value={cloudflareApiToken}
								placeholder={hasCloudflareApiToken ? '••••••••' : $t('settingsGeneral.cloudflareApiTokenPlaceholder')}
								helpText={hasCloudflareApiToken ? $t('settingsGeneral.cloudflareApiTokenConfigured') : $t('settingsGeneral.cloudflareApiTokenHelp')}
							/>
						</div>

						<div>
							<label for="cloudflareZoneBtn" class="block text-sm font-medium text-[var(--text-primary)]">{$t('settingsGeneral.cloudflareZone')}</label>
							<p class="mt-0.5 text-xs text-[var(--text-tertiary)]">{$t('settingsGeneral.cloudflareZoneHelp')}</p>
							<div class="mt-1.5 flex items-center gap-2">
								<button
									id="cloudflareZoneBtn"
									type="button"
									onclick={openZonePicker}
									class="inline-flex items-center gap-2 rounded-lg border border-[var(--border-primary)] px-3 py-2 text-sm text-[var(--text-secondary)] hover:bg-[var(--surface-card)] transition-colors"
								>
									{#if loadingZones}
										{$t('settingsGeneral.loadingZones')}
									{:else if cloudflareZoneId && zoneName}
										{zoneName}
									{:else}
										{$t('settingsGeneral.noZone')}
									{/if}
								</button>
								{#if cloudflareZoneId}
									<button
										type="button"
										onclick={() => { cloudflareZoneId = ''; zoneName = ''; }}
										class="inline-flex items-center gap-1 rounded-lg border border-[var(--border-primary)] px-2 py-2 text-sm text-[var(--text-tertiary)] hover:text-[var(--color-danger)] hover:bg-[var(--surface-card)] transition-colors"
									>
										<IconX size={14} />
									</button>
								{/if}
							</div>
						</div>

						<div>
							<button
								type="button"
								onclick={handleTestDns}
								disabled={testingDns || (!cloudflareApiToken && !hasCloudflareApiToken)}
								class="inline-flex items-center gap-2 rounded-lg border border-[var(--color-brand-600)] px-3 py-2 text-sm font-medium text-[var(--color-brand-600)] hover:bg-[var(--color-brand-50)] transition-colors disabled:opacity-50"
							>
								{#if testingDns}<IconLoader size={16} />{/if}
								{testingDns ? $t('settingsGeneral.testingConnection') : $t('settingsGeneral.testConnection')}
							</button>
						</div>
					{/if}
				</div>
			{/if}

			<div class="mt-6">
				<button onclick={handleSave} disabled={saving} class="inline-flex items-center gap-2 rounded-lg bg-[var(--color-brand-600)] px-4 py-2.5 text-sm font-medium text-white shadow-sm transition-all duration-150 hover:bg-[var(--color-brand-700)] disabled:opacity-50 active:animate-press">
					{#if saving}<IconLoader size={16} />{/if}
					{saving ? $t('settingsGeneral.saving') : $t('settingsGeneral.saveSettings')}
				</button>
			</div>
		</div>
	{/if}
</div>

<EntityPicker
	bind:open={zonePickerOpen}
	items={zonePickerItems}
	current={cloudflareZoneId}
	title={$t('settingsGeneral.selectZone')}
	onselect={handleZoneSelect}
	onclose={() => { zonePickerOpen = false; }}
/>
