<script lang="ts">
	import { models } from '$lib/stores';
	import { flyAndScale } from '$lib/utils/transitions';
	import WorkspaceFiles from './WorkspaceFiles.svelte';

	export let selectedModels = [''];
	export let disabled = false;
	export let showSetDefault = true;

	const modelOptions = [
		{
			id: 'luna',
			label: 'Luna',
			description: '快速、轻量的本地 Agent',
			location: '本地',
			accent: 'bg-violet-100 text-violet-700 dark:bg-violet-500/15 dark:text-violet-300',
			thinking: '开启',
			thinkingTitle: '思考模式',
			thinkingHelp: '当前固定开启。此模型只支持思考开关，不提供轻、中、高强度档位。'
		},
		{
			id: 'terra',
			label: 'Terra',
			description: '速度与任务能力均衡',
			location: '本地',
			accent: 'bg-sky-100 text-sky-700 dark:bg-sky-500/15 dark:text-sky-300',
			thinking: '开启',
			thinkingTitle: '思考模式',
			thinkingHelp: '当前固定开启。此模型只支持思考开关，不提供轻、中、高强度档位。'
		},
		{
			id: 'sol',
			label: 'Sol',
			description: '面向复杂任务的本地 Agent',
			location: '本地',
			accent: 'bg-amber-100 text-amber-700 dark:bg-amber-500/15 dark:text-amber-300',
			thinking: '开启',
			thinkingTitle: '思考模式',
			thinkingHelp: '当前固定开启。此模型只支持思考开关，不提供轻、中、高强度档位。'
		},
		{
			id: 'deepseek-v4-pro',
			label: 'DeepSeek V4 Pro',
			description: '云端高能力 Agent',
			location: '云端',
			accent: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300',
			thinking: '极高',
			thinkingTitle: '推理强度',
			thinkingHelp: '当前固定为极高（max），由 Agent 服务端管理。'
		}
	];
	const allowed = new Set(modelOptions.map((item) => item.id));

	let showWorkspace = false;
	let showModels = false;
	let showThinking = false;
	let modelTrigger: HTMLElement | null = null;
	let modelPanel: HTMLElement | null = null;
	let thinkingTrigger: HTMLElement | null = null;
	let thinkingPanel: HTMLElement | null = null;
	let modelPosition = { top: 0, left: 0, width: 320 };
	let thinkingPosition = { top: 0, left: 0, width: 288 };

	$: selected = allowed.has(selectedModels?.[0]) ? selectedModels[0] : 'terra';
	$: selectedOption = modelOptions.find((item) => item.id === selected) ?? modelOptions[1];
	$: availableIds = new Set($models.map((model) => model.id));

	$: if ($models.length > 0 && !availableIds.has(selectedModels?.[0])) {
		const fallback = availableIds.has('terra')
			? 'terra'
			: modelOptions.find((item) => availableIds.has(item.id))?.id;
		if (fallback) selectedModels = [fallback];
	}

	const portal = (node: HTMLElement) => {
		document.body.appendChild(node);
		return {
			destroy() {
				node.remove();
			}
		};
	};

	const positionFor = (trigger: HTMLElement | null, preferredWidth: number) => {
		if (!trigger || typeof window === 'undefined') {
			return { top: 0, left: 0, width: preferredWidth };
		}

		const rect = trigger.getBoundingClientRect();
		const width = Math.min(preferredWidth, window.innerWidth - 16);
		return {
			top: rect.bottom + 8,
			left: Math.max(8, Math.min(rect.left, window.innerWidth - width - 8)),
			width
		};
	};

	const updatePositions = () => {
		if (showModels) modelPosition = positionFor(modelTrigger, 320);
		if (showThinking) thinkingPosition = positionFor(thinkingTrigger, 288);
	};

	const toggleModels = () => {
		if (disabled) return;
		showThinking = false;
		showModels = !showModels;
		if (showModels) modelPosition = positionFor(modelTrigger, 320);
	};

	const toggleThinking = () => {
		showModels = false;
		showThinking = !showThinking;
		if (showThinking) thinkingPosition = positionFor(thinkingTrigger, 288);
	};

	const chooseModel = (modelId: string) => {
		if (disabled || ($models.length > 0 && !availableIds.has(modelId))) return;
		selectedModels = [modelId];
		showModels = false;
	};

	const closePopovers = (event: PointerEvent) => {
		const target = event.target as Node;
		if (
			(modelTrigger?.contains(target) ?? false) ||
			(modelPanel?.contains(target) ?? false) ||
			(thinkingTrigger?.contains(target) ?? false) ||
			(thinkingPanel?.contains(target) ?? false)
		) {
			return;
		}
		showModels = false;
		showThinking = false;
	};

	const handleKeydown = (event: KeyboardEvent) => {
		if (event.key !== 'Escape') return;
		const focusTarget = showThinking ? thinkingTrigger : modelTrigger;
		showModels = false;
		showThinking = false;
		focusTarget?.focus();
	};
</script>

<svelte:window
	on:pointerdown={closePopovers}
	on:keydown={handleKeydown}
	on:resize={updatePositions}
	on:scroll={updatePositions}
/>

<div class="flex max-w-full select-none items-center gap-0.5">
	<button
		bind:this={modelTrigger}
		type="button"
		class="group flex min-w-0 max-w-[13rem] items-center gap-1.5 rounded-xl px-2.5 py-2 text-sm font-semibold text-gray-900 outline-hidden transition hover:bg-gray-100 focus-visible:ring-2 focus-visible:ring-gray-300 disabled:cursor-not-allowed disabled:opacity-50 dark:text-white dark:hover:bg-gray-800 dark:focus-visible:ring-gray-600 sm:max-w-[16rem]"
		on:click={toggleModels}
		disabled={disabled}
		aria-label="选择模型，当前为 {selectedOption.label}"
		aria-haspopup="listbox"
		aria-expanded={showModels}
	>
		<span class="truncate">{selectedOption.label}</span>
		<svg
			viewBox="0 0 20 20"
			class="size-3.5 shrink-0 text-gray-400 transition-transform duration-150 {showModels
				? 'rotate-180'
				: ''}"
			fill="none"
			stroke="currentColor"
			stroke-width="1.8"
			aria-hidden="true"
		>
			<path d="m6 8 4 4 4-4" stroke-linecap="round" stroke-linejoin="round" />
		</svg>
	</button>

	<div class="mx-0.5 h-4 w-px bg-gray-200 dark:bg-gray-700" aria-hidden="true" />

	<button
		bind:this={thinkingTrigger}
		type="button"
		class="group flex shrink-0 items-center gap-1.5 rounded-xl px-2.5 py-2 text-xs font-medium text-gray-500 outline-hidden transition hover:bg-gray-100 hover:text-gray-900 focus-visible:ring-2 focus-visible:ring-gray-300 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-white dark:focus-visible:ring-gray-600"
		on:click={toggleThinking}
		aria-label="{selectedOption.thinkingTitle}：{selectedOption.thinking}"
		aria-haspopup="dialog"
		aria-expanded={showThinking}
	>
		<svg
			viewBox="0 0 20 20"
			class="size-3.5 text-gray-400 group-hover:text-gray-600 dark:group-hover:text-gray-200"
			fill="none"
			stroke="currentColor"
			stroke-width="1.6"
			aria-hidden="true"
		>
			<path
				d="M10 2.5c.3 2.4 1.5 3.6 4 4-2.5.4-3.7 1.6-4 4-.4-2.4-1.6-3.6-4-4 2.4-.4 3.6-1.6 4-4Z"
				stroke-linecap="round"
				stroke-linejoin="round"
			/>
			<path d="M4.5 11.5c.2 1.7 1 2.5 2.7 2.7-1.7.3-2.5 1.1-2.7 2.8-.3-1.7-1.1-2.5-2.8-2.8 1.7-.2 2.5-1 2.8-2.7Z" />
			<path d="M15 12.5c.2 1.2.8 1.8 2 2-1.2.2-1.8.8-2 2-.2-1.2-.8-1.8-2-2 1.2-.2 1.8-.8 2-2Z" />
		</svg>
		<span class="hidden sm:inline">{selectedOption.thinkingTitle}</span>
		<span class="text-gray-800 dark:text-gray-200">{selectedOption.thinking}</span>
		<svg
			viewBox="0 0 20 20"
			class="size-3 shrink-0 text-gray-400 transition-transform duration-150 {showThinking
				? 'rotate-180'
				: ''}"
			fill="none"
			stroke="currentColor"
			stroke-width="1.8"
			aria-hidden="true"
		>
			<path d="m6 8 4 4 4-4" stroke-linecap="round" stroke-linejoin="round" />
		</svg>
	</button>

	<button
		type="button"
		class="ml-0.5 rounded-xl p-2 text-gray-500 outline-hidden transition hover:bg-gray-100 hover:text-gray-900 focus-visible:ring-2 focus-visible:ring-gray-300 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-white dark:focus-visible:ring-gray-600"
		on:click={() => (showWorkspace = true)}
		title="工作区文件"
		aria-label="工作区文件"
	>
		<svg
			viewBox="0 0 24 24"
			class="size-4"
			fill="none"
			stroke="currentColor"
			stroke-width="1.8"
			aria-hidden="true"
		>
			<path d="M3.5 6.5h6l2 2h9v10h-17z" stroke-linejoin="round" />
		</svg>
	</button>
</div>

{#if showModels}
	<div
		use:portal
		bind:this={modelPanel}
		class="fixed z-[9999]"
		style="top: {modelPosition.top}px; left: {modelPosition.left}px; width: {modelPosition.width}px;"
		transition:flyAndScale
	>
		<div
			class="overflow-hidden rounded-2xl border border-gray-200/70 bg-white p-1.5 text-gray-900 shadow-xl shadow-black/10 dark:border-gray-700/70 dark:bg-gray-850 dark:text-white dark:shadow-black/30"
			role="listbox"
			aria-label="可用模型"
		>
			<div class="px-2.5 pb-1.5 pt-1 text-xs font-medium text-gray-400 dark:text-gray-500">
				选择模型
			</div>
			{#each modelOptions as item}
				{@const unavailable = $models.length > 0 && !availableIds.has(item.id)}
				<button
					type="button"
					role="option"
					aria-selected={selected === item.id}
					class="group flex w-full items-center gap-3 rounded-xl px-2.5 py-2.5 text-left outline-hidden transition hover:bg-gray-100 focus-visible:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-40 dark:hover:bg-gray-800 dark:focus-visible:bg-gray-800"
					on:click={() => chooseModel(item.id)}
					disabled={disabled || unavailable}
				>
					<span
						class="flex size-8 shrink-0 items-center justify-center rounded-full text-xs font-bold {item.accent}"
						aria-hidden="true"
					>
						{item.label.slice(0, 1)}
					</span>
					<span class="min-w-0 flex-1">
						<span class="flex items-center gap-2">
							<span class="truncate text-sm font-medium">{item.label}</span>
							<span
								class="rounded-full bg-gray-100 px-1.5 py-0.5 text-[10px] font-medium text-gray-500 dark:bg-gray-800 dark:text-gray-400"
							>
								{item.location}
							</span>
						</span>
						<span class="mt-0.5 block truncate text-xs text-gray-500 dark:text-gray-400">
							{unavailable ? '当前不可用' : item.description}
						</span>
					</span>
					{#if selected === item.id}
						<svg
							viewBox="0 0 20 20"
							class="size-4 shrink-0 text-gray-900 dark:text-white"
							fill="none"
							stroke="currentColor"
							stroke-width="2"
							aria-hidden="true"
						>
							<path d="m5 10 3 3 7-7" stroke-linecap="round" stroke-linejoin="round" />
						</svg>
					{/if}
				</button>
			{/each}
		</div>
	</div>
{/if}

{#if showThinking}
	<div
		use:portal
		bind:this={thinkingPanel}
		class="fixed z-[9999]"
		style="top: {thinkingPosition.top}px; left: {thinkingPosition.left}px; width: {thinkingPosition.width}px;"
		transition:flyAndScale
	>
		<div
			class="rounded-2xl border border-gray-200/70 bg-white p-2 text-gray-900 shadow-xl shadow-black/10 dark:border-gray-700/70 dark:bg-gray-850 dark:text-white dark:shadow-black/30"
			role="dialog"
			aria-label="{selectedOption.thinkingTitle}说明"
		>
			<div class="flex items-center gap-3 rounded-xl bg-gray-50 px-3 py-2.5 dark:bg-gray-800/70">
				<span
					class="flex size-8 shrink-0 items-center justify-center rounded-full bg-gray-900 text-white dark:bg-white dark:text-gray-900"
					aria-hidden="true"
				>
					<svg
						viewBox="0 0 20 20"
						class="size-4"
						fill="none"
						stroke="currentColor"
						stroke-width="1.6"
					>
						<path
							d="M10 2.5c.3 2.4 1.5 3.6 4 4-2.5.4-3.7 1.6-4 4-.4-2.4-1.6-3.6-4-4 2.4-.4 3.6-1.6 4-4Z"
							stroke-linecap="round"
							stroke-linejoin="round"
						/>
						<path d="M5 12c.2 1.7 1 2.5 2.7 2.7C6 15 5.2 15.8 5 17.5c-.3-1.7-1.1-2.5-2.8-2.8C3.9 14.5 4.7 13.7 5 12Z" />
					</svg>
				</span>
				<span class="min-w-0 flex-1">
					<span class="block text-xs text-gray-500 dark:text-gray-400">
						{selectedOption.thinkingTitle}
					</span>
					<span class="block text-sm font-semibold">{selectedOption.thinking}</span>
				</span>
				<svg
					viewBox="0 0 20 20"
					class="size-4 shrink-0"
					fill="none"
					stroke="currentColor"
					stroke-width="2"
					aria-hidden="true"
				>
					<path d="m5 10 3 3 7-7" stroke-linecap="round" stroke-linejoin="round" />
				</svg>
			</div>
			<p class="px-2 pb-1 pt-2.5 text-xs leading-5 text-gray-500 dark:text-gray-400">
				{selectedOption.thinkingHelp}
			</p>
		</div>
	</div>
{/if}

<WorkspaceFiles bind:show={showWorkspace} />
