import { writable, derived, get } from 'svelte/store';
import { browser } from '$app/environment';

export type TimeFormat = '12h' | '24h';
export type DateFormat = 'MM/DD/YYYY' | 'DD/MM/YYYY' | 'YYYY-MM-DD' | 'DD.MM.YYYY';
export type DownloadFormat = 'tar' | 'tar.gz';

export interface AppSettings {
	confirmDestructive: boolean;
	showStoppedContainers: boolean;
	highlightUpdates: boolean;
	timeFormat: TimeFormat;
	dateFormat: DateFormat;
	downloadFormat: DownloadFormat;
	defaultGrypeArgs: string;
	defaultTrivyArgs: string;
	scheduleRetentionDays: number;
	eventRetentionDays: number;
	scheduleCleanupCron: string;
	eventCleanupCron: string;
	scheduleCleanupEnabled: boolean;
	eventCleanupEnabled: boolean;
	logBufferSizeKb: number;
	defaultTimezone: string;
}

const DEFAULT_SETTINGS: AppSettings = {
	confirmDestructive: true,
	showStoppedContainers: true,
	highlightUpdates: true,
	timeFormat: '24h',
	dateFormat: 'DD.MM.YYYY',
	downloadFormat: 'tar',
	defaultGrypeArgs: '-o json -v {image}',
	defaultTrivyArgs: 'image --format json {image}',
	scheduleRetentionDays: 30,
	eventRetentionDays: 30,
	scheduleCleanupCron: '0 3 * * *',
	eventCleanupCron: '30 3 * * *',
	scheduleCleanupEnabled: true,
	eventCleanupEnabled: true,
	logBufferSizeKb: 500,
	defaultTimezone: 'UTC'
};

// Create a writable store for app settings
function createSettingsStore() {
	const { subscribe, set, update } = writable<AppSettings>(DEFAULT_SETTINGS);
	let initialized = false;

	// Load settings from database on initialization
	async function loadSettings() {
		if (!browser || initialized) return;
		initialized = true;

		try {
			const response = await fetch('/api/settings/general');
			if (response.ok) {
				const settings = await response.json();
				set({
					confirmDestructive: settings.confirmDestructive ?? DEFAULT_SETTINGS.confirmDestructive,
					showStoppedContainers: settings.showStoppedContainers ?? DEFAULT_SETTINGS.showStoppedContainers,
					highlightUpdates: settings.highlightUpdates ?? DEFAULT_SETTINGS.highlightUpdates,
					timeFormat: settings.timeFormat ?? DEFAULT_SETTINGS.timeFormat,
					dateFormat: settings.dateFormat ?? DEFAULT_SETTINGS.dateFormat,
					downloadFormat: settings.downloadFormat ?? DEFAULT_SETTINGS.downloadFormat,
					defaultGrypeArgs: settings.defaultGrypeArgs ?? DEFAULT_SETTINGS.defaultGrypeArgs,
					defaultTrivyArgs: settings.defaultTrivyArgs ?? DEFAULT_SETTINGS.defaultTrivyArgs,
					scheduleRetentionDays: settings.scheduleRetentionDays ?? DEFAULT_SETTINGS.scheduleRetentionDays,
					eventRetentionDays: settings.eventRetentionDays ?? DEFAULT_SETTINGS.eventRetentionDays,
					scheduleCleanupCron: settings.scheduleCleanupCron ?? DEFAULT_SETTINGS.scheduleCleanupCron,
					eventCleanupCron: settings.eventCleanupCron ?? DEFAULT_SETTINGS.eventCleanupCron,
					scheduleCleanupEnabled: settings.scheduleCleanupEnabled ?? DEFAULT_SETTINGS.scheduleCleanupEnabled,
					eventCleanupEnabled: settings.eventCleanupEnabled ?? DEFAULT_SETTINGS.eventCleanupEnabled,
					logBufferSizeKb: settings.logBufferSizeKb ?? DEFAULT_SETTINGS.logBufferSizeKb,
					defaultTimezone: settings.defaultTimezone ?? DEFAULT_SETTINGS.defaultTimezone
				});
			}
		} catch {
			// Silently use defaults if settings can't be loaded
		}
	}

	// Save settings to database
	async function saveSettings(settings: Partial<AppSettings>) {
		if (!browser) return;

		try {
			const response = await fetch('/api/settings/general', {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify(settings)
			});
			if (response.ok) {
				const updatedSettings = await response.json();
				set({
					confirmDestructive: updatedSettings.confirmDestructive ?? DEFAULT_SETTINGS.confirmDestructive,
					showStoppedContainers: updatedSettings.showStoppedContainers ?? DEFAULT_SETTINGS.showStoppedContainers,
					highlightUpdates: updatedSettings.highlightUpdates ?? DEFAULT_SETTINGS.highlightUpdates,
					timeFormat: updatedSettings.timeFormat ?? DEFAULT_SETTINGS.timeFormat,
					dateFormat: updatedSettings.dateFormat ?? DEFAULT_SETTINGS.dateFormat,
					downloadFormat: updatedSettings.downloadFormat ?? DEFAULT_SETTINGS.downloadFormat,
					defaultGrypeArgs: updatedSettings.defaultGrypeArgs ?? DEFAULT_SETTINGS.defaultGrypeArgs,
					defaultTrivyArgs: updatedSettings.defaultTrivyArgs ?? DEFAULT_SETTINGS.defaultTrivyArgs,
					scheduleRetentionDays: updatedSettings.scheduleRetentionDays ?? DEFAULT_SETTINGS.scheduleRetentionDays,
					eventRetentionDays: updatedSettings.eventRetentionDays ?? DEFAULT_SETTINGS.eventRetentionDays,
					scheduleCleanupCron: updatedSettings.scheduleCleanupCron ?? DEFAULT_SETTINGS.scheduleCleanupCron,
					eventCleanupCron: updatedSettings.eventCleanupCron ?? DEFAULT_SETTINGS.eventCleanupCron,
					scheduleCleanupEnabled: updatedSettings.scheduleCleanupEnabled ?? DEFAULT_SETTINGS.scheduleCleanupEnabled,
					eventCleanupEnabled: updatedSettings.eventCleanupEnabled ?? DEFAULT_SETTINGS.eventCleanupEnabled,
					logBufferSizeKb: updatedSettings.logBufferSizeKb ?? DEFAULT_SETTINGS.logBufferSizeKb,
					defaultTimezone: updatedSettings.defaultTimezone ?? DEFAULT_SETTINGS.defaultTimezone
				});
			}
		} catch (error) {
			console.error('Failed to save settings:', error);
		}
	}

	// Load settings on store creation
	if (browser) {
		loadSettings();
	}

	return {
		subscribe,
		set: (value: AppSettings) => {
			set(value);
			saveSettings(value);
		},
		update: (fn: (settings: AppSettings) => AppSettings) => {
			update((current) => {
				const newSettings = fn(current);
				saveSettings(newSettings);
				return newSettings;
			});
		},
		// Convenience methods for individual settings
		setConfirmDestructive: (value: boolean) => {
			update((current) => {
				const newSettings = { ...current, confirmDestructive: value };
				saveSettings({ confirmDestructive: value });
				return newSettings;
			});
		},
		setShowStoppedContainers: (value: boolean) => {
			update((current) => {
				const newSettings = { ...current, showStoppedContainers: value };
				saveSettings({ showStoppedContainers: value });
				return newSettings;
			});
		},
		setHighlightUpdates: (value: boolean) => {
			update((current) => {
				const newSettings = { ...current, highlightUpdates: value };
				saveSettings({ highlightUpdates: value });
				return newSettings;
			});
		},
		setTimeFormat: (value: TimeFormat) => {
			update((current) => {
				const newSettings = { ...current, timeFormat: value };
				saveSettings({ timeFormat: value });
				return newSettings;
			});
		},
		setDateFormat: (value: DateFormat) => {
			update((current) => {
				const newSettings = { ...current, dateFormat: value };
				saveSettings({ dateFormat: value });
				return newSettings;
			});
		},
		setDownloadFormat: (value: DownloadFormat) => {
			update((current) => {
				const newSettings = { ...current, downloadFormat: value };
				saveSettings({ downloadFormat: value });
				return newSettings;
			});
		},
		setDefaultGrypeArgs: (value: string) => {
			update((current) => {
				const newSettings = { ...current, defaultGrypeArgs: value };
				saveSettings({ defaultGrypeArgs: value });
				return newSettings;
			});
		},
		setDefaultTrivyArgs: (value: string) => {
			update((current) => {
				const newSettings = { ...current, defaultTrivyArgs: value };
				saveSettings({ defaultTrivyArgs: value });
				return newSettings;
			});
		},
		setScheduleRetentionDays: (value: number) => {
			update((current) => {
				const newSettings = { ...current, scheduleRetentionDays: value };
				saveSettings({ scheduleRetentionDays: value });
				return newSettings;
			});
		},
		setEventRetentionDays: (value: number) => {
			update((current) => {
				const newSettings = { ...current, eventRetentionDays: value };
				saveSettings({ eventRetentionDays: value });
				return newSettings;
			});
		},
		setScheduleCleanupCron: (value: string) => {
			update((current) => {
				const newSettings = { ...current, scheduleCleanupCron: value };
				saveSettings({ scheduleCleanupCron: value });
				return newSettings;
			});
		},
		setEventCleanupCron: (value: string) => {
			update((current) => {
				const newSettings = { ...current, eventCleanupCron: value };
				saveSettings({ eventCleanupCron: value });
				return newSettings;
			});
		},
		setScheduleCleanupEnabled: (value: boolean) => {
			update((current) => {
				const newSettings = { ...current, scheduleCleanupEnabled: value };
				saveSettings({ scheduleCleanupEnabled: value });
				return newSettings;
			});
		},
		setEventCleanupEnabled: (value: boolean) => {
			update((current) => {
				const newSettings = { ...current, eventCleanupEnabled: value };
				saveSettings({ eventCleanupEnabled: value });
				return newSettings;
			});
		},
		setLogBufferSizeKb: (value: number) => {
			update((current) => {
				const newSettings = { ...current, logBufferSizeKb: value };
				saveSettings({ logBufferSizeKb: value });
				return newSettings;
			});
		},
		setDefaultTimezone: (value: string) => {
			update((current) => {
				const newSettings = { ...current, defaultTimezone: value };
				saveSettings({ defaultTimezone: value });
				return newSettings;
			});
		},
		// Manual refresh from database
		refresh: loadSettings
	};
}

export const appSettings = createSettingsStore();

// Cache current settings for synchronous access (updated reactively)
let cachedTimeFormat: TimeFormat = DEFAULT_SETTINGS.timeFormat;
let cachedDateFormat: DateFormat = DEFAULT_SETTINGS.dateFormat;

// Subscribe once to keep cache updated
if (browser) {
	appSettings.subscribe((s) => {
		cachedTimeFormat = s.timeFormat;
		cachedDateFormat = s.dateFormat;
	});
}

/**
 * Format a date part according to user's date format preference.
 * This is a low-level helper - prefer formatDateTime for most uses.
 */
function formatDatePart(d: Date): string {
	const day = d.getDate().toString().padStart(2, '0');
	const month = (d.getMonth() + 1).toString().padStart(2, '0');
	const year = d.getFullYear();

	switch (cachedDateFormat) {
		case 'MM/DD/YYYY':
			return `${month}/${day}/${year}`;
		case 'DD/MM/YYYY':
			return `${day}/${month}/${year}`;
		case 'YYYY-MM-DD':
			return `${year}-${month}-${day}`;
		case 'DD.MM.YYYY':
		default:
			return `${day}.${month}.${year}`;
	}
}

/**
 * Format a time part according to user's time format preference.
 * This is a low-level helper - prefer formatDateTime for most uses.
 */
function formatTimePart(d: Date, includeSeconds = false): string {
	const hours = d.getHours();
	const minutes = d.getMinutes().toString().padStart(2, '0');
	const seconds = d.getSeconds().toString().padStart(2, '0');

	if (cachedTimeFormat === '12h') {
		const hour12 = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
		const ampm = hours >= 12 ? 'PM' : 'AM';
		return includeSeconds
			? `${hour12}:${minutes}:${seconds} ${ampm}`
			: `${hour12}:${minutes} ${ampm}`;
	} else {
		const hour24 = hours.toString().padStart(2, '0');
		return includeSeconds
			? `${hour24}:${minutes}:${seconds}`
			: `${hour24}:${minutes}`;
	}
}

/**
 * Format a timestamp according to user's time and date format preferences.
 * Performant: uses cached settings, no store subscription per call.
 *
 * @param date - Date object, ISO string, or timestamp
 * @param options - Formatting options
 * @returns Formatted string
 */
export function formatTime(
	date: Date | string | number,
	options: { includeDate?: boolean; includeSeconds?: boolean } = {}
): string {
	const d = date instanceof Date ? date : new Date(date);
	const { includeDate = false, includeSeconds = false } = options;

	if (includeDate) {
		return `${formatDatePart(d)} ${formatTimePart(d, includeSeconds)}`;
	}

	return formatTimePart(d, includeSeconds);
}

/**
 * Format a timestamp with date according to user's preferences.
 * Convenience wrapper around formatTime.
 */
export function formatDateTime(date: Date | string | number, includeSeconds = false): string {
	return formatTime(date, { includeDate: true, includeSeconds });
}

/**
 * Format just the date part according to user's preferences.
 */
export function formatDate(date: Date | string | number): string {
	const d = date instanceof Date ? date : new Date(date);
	return formatDatePart(d);
}

/**
 * Get the current time format setting (for components that need it).
 */
export function getTimeFormat(): TimeFormat {
	return cachedTimeFormat;
}

/**
 * Get the current date format setting (for components that need it).
 */
export function getDateFormat(): DateFormat {
	return cachedDateFormat;
}
