<script lang="ts">
	import { FlaskConical, RotateCcw } from '@lucide/svelte';
	import { SettingsChatParameterSourceIndicator } from '$lib/components/app/settings';
	import { Checkbox } from '$lib/components/ui/checkbox';
	import { Input } from '$lib/components/ui/input';
	import Label from '$lib/components/ui/label/label.svelte';
	import * as RadioGroup from '$lib/components/ui/radio-group';
	import * as Select from '$lib/components/ui/select';
	import { Textarea } from '$lib/components/ui/textarea';
	import { ICON_CLASS_DEFAULT, SETTING_CONFIG_INFO, SETTINGS_KEYS } from '$lib/constants';
	import { SettingsFieldType } from '$lib/enums/settings.enums';
	import { modelsStore, serverStore, settingsStore } from '$lib/stores';
	import { normalizeFloatingPoint } from '$lib/utils/precision';
	import type { Component } from 'svelte';

	interface Props {
		fields: SettingsFieldConfig[];
		localConfig: SettingsConfigType;
		onConfigChange: (key: string, value: string | boolean) => void;
		onThemeChange?: (theme: string) => void;
	}

	let { fields, localConfig, onConfigChange, onThemeChange }: Props = $props();

	let currentModelParams = $derived.by(() => {
		void modelsStore.propsCacheVersion;

		if (serverStore.isRouterMode) {
			const currentModelName = modelsStore.selectedModelName;

			if (currentModelName) {
				const currentModelProps = modelsStore.getModelProps(currentModelName);

				return (currentModelProps?.default_generation_settings?.params ?? {}) as Record<
					string,
					unknown
				>;
			}
		}

		return (serverStore.defaultParams ?? {}) as Record<string, unknown>;
	});
</script>

{#each fields as field (field.key)}
	{#if !field.dependsOn || Boolean(localConfig[field.dependsOn])}
		<div class={field.dependsOn ? 'space-y-2 pl-6' : 'space-y-2'}>
			{#if field.type === SettingsFieldType.INPUT}
				{@const currentValue = String(localConfig[field.key] ?? '')}
				{@const serverDefault = currentModelParams[field.key]}
				{@const isCustomRealTime = (() => {
					if (serverDefault == null) return false;

					if (currentValue === '') return false;

					const numericInput = parseFloat(currentValue);
					const normalizedInput = !isNaN(numericInput)
						? Math.round(numericInput * 1000000) / 1000000
						: currentValue;
					const normalizedDefault =
						typeof serverDefault === 'number'
							? Math.round(serverDefault * 1000000) / 1000000
							: serverDefault;

					return normalizedInput !== normalizedDefault;
				})()}

				<div class="flex items-center gap-2">
					<Label for={field.key} class="flex items-center gap-1.5 text-sm font-medium">
						{field.label}

						{#if field.isExperimental}
							<FlaskConical class="h-3.5 w-3.5 text-muted-foreground" />
						{/if}
					</Label>
					{#if isCustomRealTime}
						<SettingsChatParameterSourceIndicator />
					{/if}
				</div>

				<div class="relative w-full">
					<Input
						id={field.key}
						type={field.isPrivate ? 'password' : field.isPositiveInteger ? 'number' : 'text'}
						autocomplete={field.isPrivate ? 'new-password' : undefined}
						{...field.isPositiveInteger
							? {
									min: String(field.min ?? 1),
									step: '1',
									...(field.max != null ? { max: String(field.max) } : {})
								}
							: {}}
						value={currentValue}
						oninput={(e) => onConfigChange(field.key, e.currentTarget.value)}
						placeholder={currentModelParams[field.key] != null
							? `Default: ${normalizeFloatingPoint(currentModelParams[field.key])}`
							: (field.placeholder ?? '')}
						class="w-full {isCustomRealTime ? 'pr-8' : ''}"
					/>
					{#if isCustomRealTime}
						<button
							type="button"
							onclick={() => {
								settingsStore.resetParameterToServerDefault(field.key);
								onConfigChange(field.key, '');
							}}
							class="absolute top-1/2 right-2 inline-flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded transition-colors hover:bg-muted"
							aria-label="Reset to default"
							title="Reset to default"
						>
							<RotateCcw class="h-3 w-3" />
						</button>
					{/if}
				</div>
				{#if field.help || SETTING_CONFIG_INFO[field.key]}
					<p class="mt-1 text-xs text-muted-foreground">
						{@html field.help || SETTING_CONFIG_INFO[field.key]}
					</p>
				{/if}
			{:else if field.type === SettingsFieldType.TEXTAREA}
				{#if field.label}
					<Label for={field.key} class="block flex items-center gap-1.5 text-sm font-medium">
						{field.label}

						{#if field.isExperimental}
							<FlaskConical class="h-3.5 w-3.5 text-muted-foreground" />
						{/if}
					</Label>
				{/if}

				<Textarea
					id={field.key}
					value={String(localConfig[field.key] ?? '')}
					onchange={(e) => onConfigChange(field.key, e.currentTarget.value)}
					placeholder=""
					class="min-h-[10rem] w-full md:max-w-3xl"
				/>

				{#if field.help || SETTING_CONFIG_INFO[field.key]}
					<p class="mt-1 text-xs text-muted-foreground">
						{field.help || SETTING_CONFIG_INFO[field.key]}
					</p>
				{/if}

				{#if field.key === SETTINGS_KEYS.SYSTEM_MESSAGE}
					<div class="mt-3 flex items-center gap-2">
						<Checkbox
							id="showSystemMessage"
							checked={Boolean(localConfig.showSystemMessage ?? true)}
							onCheckedChange={(checked) =>
								onConfigChange(SETTINGS_KEYS.SHOW_SYSTEM_MESSAGE, Boolean(checked))}
						/>

						<Label for="showSystemMessage" class="cursor-pointer text-sm font-normal">
							Show system message in conversations
						</Label>
					</div>
				{/if}
			{:else if field.type === SettingsFieldType.SELECT}
				{@const selectedOption = field.options?.find(
					(opt: { value: string; label: string; icon?: Component }) =>
						opt.value === localConfig[field.key]
				)}
				{@const currentValue = localConfig[field.key]}
				{@const serverDefault = currentModelParams[field.key]}
				{@const isCustomRealTime = (() => {
					if (serverDefault == null) return false;

					if (currentValue === '' || currentValue === undefined) return false;

					return currentValue !== serverDefault;
				})()}

				<div class="flex items-center gap-2">
					<Label for={field.key} class="flex items-center gap-1.5 text-sm font-medium">
						{field.label}

						{#if field.isExperimental}
							<FlaskConical class="h-3.5 w-3.5 text-muted-foreground" />
						{/if}
					</Label>
					{#if isCustomRealTime}
						<SettingsChatParameterSourceIndicator />
					{/if}
				</div>

				<Select.Root
					type="single"
					value={currentValue}
					onValueChange={(value) => {
						if (field.key === SETTINGS_KEYS.THEME && value && onThemeChange) {
							onThemeChange(value);
						} else {
							onConfigChange(field.key, value);
						}
					}}
				>
					<div class="relative w-full md:w-auto">
						<Select.Trigger class="w-full">
							<div class="flex items-center gap-2">
								{#if selectedOption?.icon}
									{@const IconComponent = selectedOption.icon}
									<IconComponent class={ICON_CLASS_DEFAULT} />
								{/if}

								{selectedOption?.label || `Select ${field.label.toLowerCase()}`}
							</div>
						</Select.Trigger>
						{#if isCustomRealTime}
							<button
								type="button"
								onclick={() => {
									settingsStore.resetParameterToServerDefault(field.key);
									onConfigChange(field.key, '');
								}}
								class="absolute top-1/2 right-8 inline-flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded transition-colors hover:bg-muted"
								aria-label="Reset to default"
								title="Reset to default"
							>
								<RotateCcw class="h-3 w-3" />
							</button>
						{/if}
					</div>
					<Select.Content>
						{#if field.options}
							{#each field.options as option (option.value)}
								<Select.Item value={option.value} label={option.label}>
									<div class="flex items-center gap-2">
										{#if option.icon}
											{@const IconComponent = option.icon}
											<IconComponent class={ICON_CLASS_DEFAULT} />
										{/if}
										{option.label}
									</div>
								</Select.Item>
							{/each}
						{/if}
					</Select.Content>
				</Select.Root>
				{#if field.help || SETTING_CONFIG_INFO[field.key]}
					<p class="mt-1 text-xs text-muted-foreground">
						{field.help || SETTING_CONFIG_INFO[field.key]}
					</p>
				{/if}
			{:else if field.type === SettingsFieldType.RADIO && field.radioOptions}
				{@const radioOptions = field.radioOptions}
				{@const currentMode =
					radioOptions.find((o: { key: string }) => Boolean(localConfig[o.key]))?.value ??
					radioOptions[0].value}

				<Label class="flex items-center gap-1.5 text-sm font-medium mb-4">
					{field.label}

					{#if field.isExperimental}
						<FlaskConical class="h-3.5 w-3.5 text-muted-foreground" />
					{/if}
				</Label>

				<RadioGroup.Root
					class="gap-4"
					value={currentMode}
					onValueChange={(value) => {
						for (const opt of radioOptions) {
							onConfigChange(opt.key, opt.value === value);
						}
					}}
				>
					{#each radioOptions as opt (opt.value)}
						{@const itemId = `${field.key}-${opt.value}`}
						<div class="flex items-center gap-2">
							<RadioGroup.Item value={opt.value} id={itemId} />
							<Label
								for={itemId}
								class="flex cursor-pointer items-center gap-1.5 text-sm font-normal"
							>
								{opt.label}

								{#if opt.isExperimental}
									<FlaskConical class="h-3.5 w-3.5 text-muted-foreground" />
								{/if}
							</Label>
						</div>
					{/each}
				</RadioGroup.Root>

				{#if field.help || SETTING_CONFIG_INFO[field.key]}
					<p class="text-xs text-muted-foreground">
						{field.help || SETTING_CONFIG_INFO[field.key]}
					</p>
				{/if}
			{:else if field.type === SettingsFieldType.CHECKBOX}
				<div class="flex items-start space-x-3">
					<Checkbox
						id={field.key}
						checked={Boolean(localConfig[field.key])}
						onCheckedChange={(checked) => onConfigChange(field.key, checked)}
						class="mt-1"
					/>

					<div class="space-y-1">
						<label
							for={field.key}
							class="flex cursor-pointer items-center gap-1.5 pt-1 pb-0.5 text-sm leading-none font-medium"
						>
							{field.label}

							{#if field.isExperimental}
								<FlaskConical class="h-3.5 w-3.5 text-muted-foreground" />
							{/if}
						</label>

						{#if field.help || SETTING_CONFIG_INFO[field.key]}
							<p class="text-xs text-muted-foreground">
								{field.help || SETTING_CONFIG_INFO[field.key]}
							</p>
						{/if}
					</div>
				</div>
			{/if}
		</div>
	{/if}
{/each}
