<script>
	import { onMount, tick } from 'svelte';
	import * as monaco from 'monaco-editor';
	import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
	import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
	import * as vimModule from 'monaco-vim';

	import { vimModeEnabled } from '$lib/store/vimMode.js';
	import {
		setupVimClipboardIntegration,
		destroyVimClipboardIntegration
	} from '$lib/utils/vimClipboard.js';
	import { setupProxyYamlCompletion } from '$lib/utils/proxyYamlCompletion.js';

	export let value = '';
	export let height = 'medium';
	export let language = 'json';
	export let placeholder = '';
	export let showVimToggle = true;
	export let showExpandButton = true; // control expand button visibility
	export let enableProxyCompletion = false; // enable proxy YAML completion
	export let externalVimMode = null; // allow external control of vim mode
	let localVimMode = externalVimMode !== null ? externalVimMode : $vimModeEnabled;

	let editor = null;
	let editorContainer = null;
	let isDark = false;
	let vimStatusBar = null;
	let vimModeInstance = null;
	let proxyCompletionProvider = null;
	let isDestroyed = false;
	let isExpanded = false;

	const heightClasses = {
		small: 'h-64',
		medium: 'h-80',
		large: 'h-96'
	};

	// Check for dark mode
	const checkDarkMode = () => {
		if (typeof window !== 'undefined') {
			isDark = document.documentElement.classList.contains('dark');
		}
	};

	onMount(() => {
		checkDarkMode();

		// Watch for dark mode changes
		const observer = new MutationObserver(() => {
			const newIsDark = document.documentElement.classList.contains('dark');
			if (newIsDark !== isDark) {
				isDark = newIsDark;
				if (editor) {
					monaco.editor.setTheme(isDark ? 'vs-dark' : 'vs-light');
				}
			}
		});

		observer.observe(document.documentElement, {
			attributes: true,
			attributeFilter: ['class']
		});

		const cleanup = () => {
			isDestroyed = true;
			observer.disconnect();
			// properly cleanup vim mode first
			destroyVimMode();
			if (editor) {
				editor.dispose();
				editor = null;
			}
		};
		/* @ts-ignore */
		self.MonacoEnvironment = {
			getWorker: function (_, label) {
				if (label === 'json') {
					return new jsonWorker();
				}
				return new editorWorker();
			}
		};

		const editorOptions = {
			value: value || '',
			language: language,
			theme: 'vs-dark',
			automaticLayout: true,
			minimap: {
				enabled: false
			},
			scrollBeyondLastLine: false,
			fontSize: 13,
			lineNumbers: 'on',
			folding: true,
			wordWrap: 'on',
			contextmenu: true,
			scrollbar: {
				horizontal: 'hidden'
			},
			// Enable suggestions for YAML with proxy completion
			quickSuggestions: enableProxyCompletion && language === 'yaml' ? true : false,
			parameterHints: {
				enabled: enableProxyCompletion && language === 'yaml'
			},
			suggestOnTriggerCharacters: enableProxyCompletion && language === 'yaml',
			acceptSuggestionOnEnter: enableProxyCompletion && language === 'yaml' ? 'on' : 'off',
			tabCompletion: enableProxyCompletion && language === 'yaml' ? 'on' : 'off',
			wordBasedSuggestions:
				enableProxyCompletion && language === 'yaml' ? 'currentDocument' : 'off',
			// Better YAML editing
			insertSpaces: true,
			tabSize: 2,
			detectIndentation: false,
			trimAutoWhitespace: true,
			// Bracket matching
			matchBrackets: 'always',
			// Selection
			selectOnLineNumbers: true,
			// Find
			find: {
				addExtraSpaceOnTop: false,
				autoFindInSelection: 'never',
				seedSearchStringFromSelection: 'selection'
			}
		};

		/* @ts-ignore - editorOptions is not complete */
		editor = monaco.editor.create(editorContainer, editorOptions);

		// vim mode will be initialized by reactive statement if needed

		// Update value when editor content changes
		editor.getModel().onDidChangeContent(() => {
			value = editor.getValue();
		});

		// Setup proxy YAML completion if enabled
		if (enableProxyCompletion && language === 'yaml') {
			try {
				proxyCompletionProvider = setupProxyYamlCompletion(monaco);
			} catch (error) {
				console.warn('Failed to setup proxy YAML completion:', error);
			}
		}

		return () => {
			cleanup();
			// cleanup completion provider
			if (proxyCompletionProvider) {
				proxyCompletionProvider.dispose();
				proxyCompletionProvider = null;
			}
		};
	});

	// Watch for external value changes
	$: if (editor && value !== undefined && editor.getValue() !== value) {
		editor.setValue(value || '');
	}

	const initializeVimMode = () => {
		if (localVimMode && editor && !vimModeInstance && !isDestroyed) {
			try {
				const statusNode = vimStatusBar;
				vimModeInstance = vimModule.initVimMode(editor, statusNode);

				// integrate system clipboard with vim registers
				setupVimClipboardIntegration(editor, vimModeInstance, localVimMode, monaco);
			} catch (e) {
				console.error('failed to start vim mode', e);
			}
		}
	};

	const destroyVimMode = () => {
		if (vimModeInstance) {
			try {
				destroyVimClipboardIntegration(vimModeInstance);
				vimModeInstance.dispose();
			} catch (e) {
				console.warn('Error disposing vim mode:', e);
			}

			vimModeInstance = null;
		}
	};

	// sync with external vim mode control
	$: if (externalVimMode !== null) {
		localVimMode = externalVimMode;
	} else {
		localVimMode = $vimModeEnabled;
	}

	// Watch for vim mode changes
	$: if (editor && !isDestroyed && typeof localVimMode === 'boolean') {
		if (localVimMode && !vimModeInstance) {
			// Wait for DOM updates to complete
			tick().then(() => {
				if (localVimMode && !vimModeInstance && !isDestroyed) {
					initializeVimMode();
				}
			});
		} else if (!localVimMode && vimModeInstance) {
			destroyVimMode();
		}
	}

	let showExample = false;

	const loadExample = () => {
		if (editor && placeholder) {
			editor.setValue(placeholder);
			value = placeholder;
		}
		showExample = false;
	};
</script>

<div
	class="w-full"
	class:fixed={isExpanded}
	class:inset-0={isExpanded}
	class:z-50={isExpanded}
	class:bg-white={isExpanded}
	class:dark:bg-gray-900={isExpanded}
>
	<div
		class="bg-white dark:bg-gray-800 transition-colors duration-200"
		class:rounded-md={!isExpanded}
		class:h-full={isExpanded}
		class:flex={isExpanded}
		class:flex-col={isExpanded}
		role={isExpanded ? 'dialog' : undefined}
		on:keydown={(e) => {
			if (isExpanded && e.key === 'Escape') {
				e.stopPropagation();
				isExpanded = false;
			}
		}}
	>
		{#if showVimToggle || showExpandButton || enableProxyCompletion}
			<div
				class="flex items-center flex-wrap gap-2 bg-slate-900 w-full justify-start p-4 rounded-t-md"
			>
				{#if showVimToggle}
					<button
						type="button"
						on:click={() => {
							vimModeEnabled.update((v) => !v);
						}}
						class="h-8 border-2 rounded-md w-36 px-3 text-center cursor-pointer hover:opacity-80 flex items-center justify-center gap-2 transition-colors duration-200"
						class:font-bold={localVimMode}
						class:bg-blue-600={localVimMode}
						class:dark:bg-blue-500={localVimMode}
						class:text-white={localVimMode}
						class:border-blue-600={localVimMode}
						class:dark:border-blue-500={localVimMode}
						class:text-gray-700={!localVimMode}
						class:dark:text-gray-200={!localVimMode}
						class:bg-white={!localVimMode}
						class:dark:bg-gray-700={!localVimMode}
						class:border-gray-300={!localVimMode}
						class:dark:border-gray-600={!localVimMode}
					>
						<span>Vim</span>
					</button>
				{/if}
				{#if showExpandButton}
					<button
						type="button"
						on:click={() => (isExpanded = !isExpanded)}
						class="h-8 border-2 border-gray-300 dark:border-gray-600 rounded-md px-3 text-center cursor-pointer hover:opacity-80 flex items-center justify-center gap-2 bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 transition-colors duration-200"
					>
						{#if !isExpanded}
							<!-- Expand icon -->
							<svg class="h-4 w-4" viewBox="0 0 20 20" fill="none">
								<path
									d="M4 8V4h4M16 8V4h-4M4 12v4h4M16 12v4h-4"
									stroke="currentColor"
									stroke-width="1.5"
									stroke-linecap="round"
								/>
								<path
									d="M4 4l5 5M16 4l-5 5M4 16l5-5M16 16l-5-5"
									stroke="currentColor"
									stroke-width="1.5"
									stroke-linecap="round"
								/>
							</svg>
							<span>Expand</span>
						{:else}
							<!-- Collapse icon -->
							<svg class="h-4 w-4" viewBox="0 0 20 20" fill="none">
								<path
									d="M9 4h-5v5M11 4h5v5M9 16h-5v-5M11 16h5v-5"
									stroke="currentColor"
									stroke-width="1.5"
									stroke-linecap="round"
								/>
								<path
									d="M9 9l-5-5M11 9l5-5M9 11l-5 5M11 11l5 5"
									stroke="currentColor"
									stroke-width="1.5"
									stroke-linecap="round"
								/>
							</svg>
							<span>Collapse</span>
						{/if}
					</button>
				{/if}
				{#if enableProxyCompletion}
					<div class="flex items-center text-xs text-gray-500 dark:text-gray-400">
						<span>Ctrl+Space for suggestions • Tab to accept</span>
					</div>
				{/if}
			</div>
		{/if}
		<div
			class="border-2 border-gray-800 w-full rounded-lg overflow-hidden"
			class:flex-1={isExpanded}
			class:flex={isExpanded}
			class:flex-col={isExpanded}
		>
			<div
				bind:this={editorContainer}
				class="w-full"
				class:h-64={height === 'small' && !localVimMode && !isExpanded}
				class:h-80={height === 'medium' && !localVimMode && !isExpanded}
				class:h-96={height === 'large' && !localVimMode && !isExpanded}
				class:flex-1={isExpanded}
				style={isExpanded
					? ''
					: localVimMode
						? `height: ${height === 'small' ? '224px' : height === 'medium' ? '294px' : '359px'}`
						: ''}
			></div>
			{#if localVimMode}
				<div
					bind:this={vimStatusBar}
					class="px-2 py-1 bg-gray-700 text-xs font-mono text-gray-300"
					style="height: 25px;"
				></div>
			{/if}
		</div>
	</div>
	{#if placeholder}
		<div class="mt-2">
			<button
				type="button"
				on:click={() => (showExample = !showExample)}
				class="text-xs text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 underline focus:outline-none transition-colors duration-200"
			>
				{showExample ? 'Hide' : 'Show'} example
			</button>
			{#if showExample}
				<div
					class="mt-2 p-3 bg-gray-900 dark:bg-black border border-gray-600 dark:border-gray-700 rounded-md transition-colors duration-200"
				>
					<div class="flex justify-between items-start mb-2">
						<span
							class="text-xs font-medium text-gray-300 dark:text-gray-200 transition-colors duration-200"
							>Example:</span
						>
						<button
							type="button"
							on:click={loadExample}
							class="text-xs text-blue-400 dark:text-blue-300 hover:text-blue-300 dark:hover:text-blue-200 underline transition-colors duration-200"
						>
							Load example
						</button>
					</div>
					<pre
						class="text-xs text-gray-300 dark:text-gray-200 whitespace-pre-wrap transition-colors duration-200 select-text cursor-text">{placeholder}</pre>
				</div>
			{/if}
		</div>
	{/if}
</div>

<style>
	:global(.monaco-editor .current-line) {
		background-color: rgba(255, 255, 255, 0.05) !important;
	}
</style>
