<script lang="ts">
	import { onMount } from 'svelte';
	import { api } from '$lib/api';
	import { t } from '$lib/i18n';
	import Loading from '$lib/components/Loading.svelte';
	import ErrorBanner from '$lib/components/ErrorBanner.svelte';
	import ConfirmModal from '$lib/components/ConfirmModal.svelte';
	import { snackSuccess, snackError } from '$lib/stores/snackbar.svelte';
	import { externalUrlCache, releaseStatusCache } from '$lib/stores/caches.svelte';

	import SettingsHero from './SettingsHero.svelte';
	import IdentityCassette from './IdentityCassette.svelte';
	import TelegramCassette from './TelegramCassette.svelte';
	import ReleaseCassette from './ReleaseCassette.svelte';
	import CacheLedger from './CacheLedger.svelte';
	import LoggingCassette from './LoggingCassette.svelte';
	import SaveBar from './SaveBar.svelte';

	interface CacheBucketStats {
		count: number;
		total_size_bytes: number;
		oldest: string | null;
		newest: string | null;
	}
	interface CacheStats {
		url: CacheBucketStats;
		asset: CacheBucketStats;
	}

	interface Settings {
		external_url: string;
		telegram_webhook_secret: string;
		telegram_cache_ttl_hours: string;
		telegram_asset_cache_max_entries: string;
		supported_locales: string;
		timezone: string;
		log_level: string;
		log_format: string;
		log_levels: string;
		release_provider_kind: string;
		release_provider_url: string;
		release_provider_repo: string;
		release_include_prereleases: string;
		release_check_interval_hours: string;
	}

	const EMPTY: Settings = {
		external_url: '',
		telegram_webhook_secret: '',
		telegram_cache_ttl_hours: '720',
		telegram_asset_cache_max_entries: '5000',
		supported_locales: 'en,ru',
		timezone: 'UTC',
		log_level: 'INFO',
		log_format: 'text',
		log_levels: '',
		release_provider_kind: 'gitea',
		release_provider_url: 'https://git.dolgolyov-family.by',
		release_provider_repo: 'alexei.dolgolyov/notify-bridge',
		release_include_prereleases: '0',
		release_check_interval_hours: '12',
	};

	let loaded = $state(false);
	let saving = $state(false);
	let clearingCache = $state(false);
	let confirmClearCache = $state(false);
	let error = $state('');

	let settings = $state<Settings>({ ...EMPTY });
	// Snapshot of the last server-known state, used for dirty tracking.
	let baseline = $state<Settings>({ ...EMPTY });
	let cacheStats = $state<CacheStats | null>(null);

	// --- Dirty tracking -----------------------------------------------------

	const dirtyKeys = $derived.by<Array<keyof Settings>>(() => {
		const out: Array<keyof Settings> = [];
		for (const key of Object.keys(settings) as Array<keyof Settings>) {
			if (settings[key] !== baseline[key]) out.push(key);
		}
		return out;
	});
	const dirty = $derived(dirtyKeys.length > 0);

	// --- Data loading -------------------------------------------------------

	async function loadCacheStats(): Promise<void> {
		try {
			cacheStats = await api<CacheStats>('/settings/telegram-cache/stats');
		} catch { cacheStats = null; }
	}

	onMount(async () => {
		try {
			const fetched = await api<Settings>('/settings');
			settings = { ...EMPTY, ...fetched };
			baseline = { ...settings };
			await loadCacheStats();
			// Warm the release status so the cassette renders the strip on first paint.
			await releaseStatusCache.fetch();
		} catch (err: unknown) {
			const msg = err instanceof Error ? err.message : 'Failed to load settings';
			error = msg;
			snackError(msg);
		} finally {
			loaded = true;
		}
	});

	// --- Actions ------------------------------------------------------------

	async function save(): Promise<void> {
		saving = true;
		error = '';
		try {
			const next = await api<Settings>('/settings', {
				method: 'PUT',
				body: JSON.stringify(settings),
			});
			settings = { ...EMPTY, ...next };
			baseline = { ...settings };
			externalUrlCache.invalidate();
			// Release config may have changed → drop the cached status and
			// refetch so the sidebar badge + cassette strip reflect the
			// freshly-rescheduled probe without waiting for the next route
			// change to trigger another read.
			releaseStatusCache.invalidate();
			void releaseStatusCache.fetch(true);
			snackSuccess(t('settings.saved'));
		} catch (err: unknown) {
			const msg = err instanceof Error ? err.message : 'Save failed';
			error = msg;
			snackError(msg);
		} finally {
			saving = false;
		}
	}

	function discard(): void {
		settings = { ...baseline };
	}

	async function clearTelegramCache(): Promise<void> {
		confirmClearCache = false;
		clearingCache = true;
		try {
			await api('/settings/telegram-cache/clear', { method: 'POST' });
			snackSuccess(t('settings.clearCacheDone'));
			await loadCacheStats();
		} catch (err: unknown) {
			const msg = err instanceof Error ? err.message : 'Clear cache failed';
			snackError(msg);
		} finally {
			clearingCache = false;
		}
	}

	const cacheMaxEntriesNum = $derived(
		Math.max(0, Number(settings.telegram_asset_cache_max_entries || '0')),
	);
</script>

<SettingsHero {settings} />

{#if !loaded}
	<Loading />
{:else}
	<ErrorBanner message={error} />

	<div class="settings-page stagger-children">
		<IdentityCassette
			bind:externalUrl={settings.external_url}
			bind:timezone={settings.timezone}
			bind:supportedLocales={settings.supported_locales}
		/>

		<div class="telegram-deck">
			<TelegramCassette
				bind:webhookSecret={settings.telegram_webhook_secret}
				bind:cacheTtlHours={settings.telegram_cache_ttl_hours}
				bind:cacheMaxEntries={settings.telegram_asset_cache_max_entries}
			/>
			<CacheLedger
				stats={cacheStats}
				clearing={clearingCache}
				maxEntries={cacheMaxEntriesNum}
				onRefresh={loadCacheStats}
				onClear={() => (confirmClearCache = true)}
			/>
		</div>

		<ReleaseCassette
			bind:providerKind={settings.release_provider_kind}
			bind:providerUrl={settings.release_provider_url}
			bind:providerRepo={settings.release_provider_repo}
			bind:includePrereleases={settings.release_include_prereleases}
			bind:checkIntervalHours={settings.release_check_interval_hours}
		/>

		<LoggingCassette
			bind:logLevel={settings.log_level}
			bind:logFormat={settings.log_format}
			bind:logLevels={settings.log_levels}
		/>
	</div>

	<SaveBar
		{dirty}
		{saving}
		changedCount={dirtyKeys.length}
		onSave={save}
		onDiscard={discard}
	/>
{/if}

<ConfirmModal
	open={confirmClearCache}
	title={t('settings.clearCacheConfirmTitle')}
	message={t('settings.clearCacheConfirm')}
	confirmLabel={t('settings.clearCacheConfirmBtn')}
	confirmIcon="mdiDeleteSweep"
	onconfirm={clearTelegramCache}
	oncancel={() => (confirmClearCache = false)}
/>

<style>
	.settings-page {
		display: flex;
		flex-direction: column;
		gap: 1.5rem;
	}

	.telegram-deck {
		display: grid;
		grid-template-columns: 1fr;
		gap: 1.25rem;
		align-items: stretch;
	}
	@media (min-width: 960px) {
		.telegram-deck { grid-template-columns: 1fr 1fr; }
	}
</style>
