<script lang="ts">
	import { onMount } from 'svelte';
	import { themeColors } from '$lib/stores/theme';
	import { toggleMode } from '$lib/stores/theme';
	import { terminalSettings, type SpeedPreset, speedPresets } from '$lib/config';
	import { calculateTypeSpeed } from '$lib'; 
	import TuiHeader from './tui/TuiHeader.svelte';
	import TuiBody from './tui/TuiBody.svelte';
	import TuiFooter from './tui/TuiFooter.svelte';
	import { parseColorText, getPlainText } from './tui/utils';

	import type { TerminalLine, ParsedLine, DisplayedLine } from './tui/types';

	interface Props {
		lines?: TerminalLine[];
		title?: string;
		class?: string;
		onComplete?: () => void;
		interactive?: boolean;
		speed?: SpeedPreset | number;
		autoscroll?: boolean;
	}

	let { 
		lines = [], 
		title = 'terminal',
		class: className = '',
		onComplete,
		interactive = true,
		speed = 'normal',
		autoscroll = true
	}: Props = $props();

	// Calculate speed multiplier from preset or number
	const speedMultiplier = $derived(
		typeof speed === 'number' ? speed : (speedPresets[speed] ?? 1)
	);

	// Pre-parse all lines upfront (segments + plain text)
	const parsedLines = $derived<ParsedLine[]>(
		lines.map(line => {
			const segments = parseColorText(line.content);
			return {
				line,
				segments,
				plainText: getPlainText(segments)
			};
		})
	);

	let displayedLines = $state<DisplayedLine[]>([]);
	let currentLineIndex = $state(0);
	let isTyping = $state(false);
	let isComplete = $state(false);
	let selectedIndex = $state(-1);
	let terminalElement: HTMLDivElement;
	let bodyElement = $state<HTMLDivElement>();

	// Autoscroll to bottom (respects autoscroll prop)
	function scrollToBottom() {
		if (!autoscroll || !bodyElement) return;
		bodyElement.scrollTo({
			top: bodyElement.scrollHeight,
			behavior: 'smooth'
		});
	}

	// Get all interactive button indices
	let buttonIndices = $derived(
		displayedLines
			.map((item, i) => item.parsed.line.type === 'button' ? i : -1)
			.filter(i => i !== -1)
	);

	function sleep(ms: number): Promise<void> {
		return new Promise(resolve => setTimeout(resolve, ms));
	}

	async function typeText() {
		if (parsedLines.length === 0) return;

		isTyping = true;
		
		// Apply speed multiplier to start delay
		const startDelayMs = speedMultiplier === 0 ? 0 : terminalSettings.startDelay * speedMultiplier;
		await sleep(startDelayMs);
		if (skipRequested) return;

		for (let i = 0; i < parsedLines.length; i++) {
			if (skipRequested) return;
			
			const parsed = parsedLines[i];
			const line = parsed.line;
			const plainLength = parsed.plainText.length;
			
			displayedLines = [...displayedLines, { parsed, charIndex: 0, complete: false, showImage: false }];
			currentLineIndex = i;

			if (line.delay && speedMultiplier > 0) {
				await sleep(line.delay * speedMultiplier);
				if (skipRequested) return;
			}

			// Handle different line types
			if (line.type === 'image') {
				await sleep(speedMultiplier === 0 ? 0 : 100 * speedMultiplier);
				if (skipRequested) return;
				displayedLines[i] = { parsed, charIndex: plainLength, complete: true, showImage: true };
				scrollToBottom();
			} else if (line.type === 'blank' || line.type === 'divider') {
				displayedLines[i] = { parsed, charIndex: plainLength, complete: true, showImage: false };
			} else if (line.type === 'button') {
				// Buttons appear instantly
				displayedLines[i] = { parsed, charIndex: plainLength, complete: true, showImage: false };
				scrollToBottom();
			} else if (speedMultiplier === 0) {
				// Instant mode - no typing animation
				displayedLines[i] = { parsed, charIndex: plainLength, complete: true, showImage: false };
				if (i % 5 === 0) scrollToBottom();
			} else if (line.type === 'header') {
				const typeSpeed = calculateTypeSpeed(plainLength, speedMultiplier * 0.25);
				for (let j = 0; j <= plainLength; j++) {
					if (skipRequested) return;
					displayedLines[i] = { 
						parsed, 
						charIndex: j, 
						complete: j === plainLength,
						showImage: false
					};
					if (j < plainLength) await sleep(typeSpeed);
				}
				scrollToBottom();
			} else {
				const typeSpeed = calculateTypeSpeed(plainLength, speedMultiplier);
				
				for (let j = 0; j <= plainLength; j++) {
					if (skipRequested) return;
					displayedLines[i] = { 
						parsed, 
						charIndex: j, 
						complete: j === plainLength,
						showImage: false
					};
					
					if (j % 10 === 0) scrollToBottom();
					
					if (j < plainLength) {
						await sleep(typeSpeed);
					}
				}
			}

			if (skipRequested) return;
			displayedLines[i].complete = true;
			
			scrollToBottom();
			
			if (i < parsedLines.length - 1 && speedMultiplier > 0) {
				await sleep(terminalSettings.lineDelay * speedMultiplier);
			}
		}

		isTyping = false;
		isComplete = true;
		
		if (interactive && buttonIndices.length > 0) {
			selectedIndex = buttonIndices[0];
		}
		
		onComplete?.();
	}

	// Scroll selected button into view with margin for context
	function scrollToSelected() {
		if (bodyElement && selectedIndex >= 0) {
			const buttons = bodyElement.querySelectorAll('.tui-button');
			const selectedButton = Array.from(buttons).find((_, i) => {
				const btnIndices = displayedLines
					.map((item, idx) => item.parsed.line.type === 'button' ? idx : -1)
					.filter(idx => idx !== -1);
				return btnIndices[i] === selectedIndex;
			}) as HTMLElement | undefined;
			
			if (selectedButton && bodyElement) {
				const containerRect = bodyElement.getBoundingClientRect();
				const buttonRect = selectedButton.getBoundingClientRect();
				const margin = 80;
				
				if (buttonRect.top < containerRect.top + margin) {
					const scrollAmount = buttonRect.top - containerRect.top - margin;
					bodyElement.scrollBy({ top: scrollAmount, behavior: 'smooth' });
				}
				else if (buttonRect.bottom > containerRect.bottom - margin) {
					const scrollAmount = buttonRect.bottom - containerRect.bottom + margin;
					bodyElement.scrollBy({ top: scrollAmount, behavior: 'smooth' });
				}
			}
		}
	}

	// Skip animation and show all content instantly
	let skipRequested = $state(false);
	
	function skipAnimation() {
		if (!isTyping) return;
		skipRequested = true;
		
		displayedLines = parsedLines.map(parsed => ({
			parsed,
			charIndex: parsed.plainText.length,
			complete: true,
			showImage: parsed.line.type === 'image'
		}));
		
		isTyping = false;
		isComplete = true;
		currentLineIndex = parsedLines.length - 1;
		
		if (interactive && buttonIndices.length > 0) {
			selectedIndex = buttonIndices[0];
		}
		
		scrollToBottom();
		onComplete?.();
	}

	function handleKeydown(event: KeyboardEvent) {
		// Toggle theme with T key
		if (event.key === 't' || event.key === 'T') {
			event.preventDefault();
			toggleMode();
			return;
		}
		if (isTyping && (event.key === 'y' || event.key === 'Y')) {
			event.preventDefault();
			skipAnimation();
			return;
		}
		
		if (!interactive || !isComplete || buttonIndices.length === 0) return;

		const currentButtonIdx = buttonIndices.indexOf(selectedIndex);

		if (event.key === 'ArrowDown' || event.key === 'j') {
			event.preventDefault();
			const nextIdx = (currentButtonIdx + 1) % buttonIndices.length;
			selectedIndex = buttonIndices[nextIdx];
			scrollToSelected();
		} else if (event.key === 'ArrowUp' || event.key === 'k') {
			event.preventDefault();
			const prevIdx = (currentButtonIdx - 1 + buttonIndices.length) % buttonIndices.length;
			selectedIndex = buttonIndices[prevIdx];
			scrollToSelected();
		} else if (event.key === 'Enter') {
			event.preventDefault();
			const selectedLine = displayedLines[selectedIndex]?.parsed.line;
			if (selectedLine?.action) {
				selectedLine.action();
			} else if (selectedLine?.href) {
				const isExternal = selectedLine.external || selectedLine.href.startsWith('http://') || selectedLine.href.startsWith('https://');
				if (isExternal) {
					window.open(selectedLine.href, '_blank', 'noopener,noreferrer');
				} else {
					window.location.href = selectedLine.href;
				}
			}
		}
	}

	function handleButtonClick(index: number) {
		selectedIndex = index;
		const line = displayedLines[index]?.parsed.line;
		if (line?.action) {
			line.action();
		} else if (line?.href) {
			const isExternal = line.external || line.href.startsWith('http://') || line.href.startsWith('https://');
			if (isExternal) {
				window.open(line.href, '_blank', 'noopener,noreferrer');
			} else {
				window.location.href = line.href;
			}
		}
	}

	function handleLinkClick(index: number) {
		const line = displayedLines[index]?.parsed.line;
		if (line?.action) {
			line.action();
		} else if (line?.href) {
			const isExternal = line.external || line.href.startsWith('http://') || line.href.startsWith('https://');
			if (isExternal) {
				window.open(line.href, '_blank', 'noopener,noreferrer');
			} else {
				window.location.href = line.href;
			}
		}
	}

	onMount(() => {
		typeText();
	});
</script>

<svelte:window on:keydown={handleKeydown} />

<div 
	class="tui-terminal {className}"
	style="
		--terminal-bg: {$themeColors.terminal};
		--terminal-text: {$themeColors.text};
		--terminal-muted: {$themeColors.textMuted};
		--terminal-border: {$themeColors.border};
		--terminal-prompt: {$themeColors.terminalPrompt};
		--terminal-user: {$themeColors.terminalUser};
		--terminal-path: {$themeColors.terminalPath};
		--terminal-primary: {$themeColors.primary};
		--terminal-accent: {$themeColors.accent};
		--terminal-bg-light: {$themeColors.backgroundLight};
	"
	bind:this={terminalElement}
	role="region"
	aria-label="Terminal interface"
>
	<!-- Hyprland-style border glow -->
	<div class="tui-border-glow"></div>
	
	<!-- TUI Content -->
	<div class="tui-content">
		<TuiHeader {title} {interactive} hasButtons={buttonIndices.length > 0} />

		<!-- Main terminal area -->
		<TuiBody bind:ref={bodyElement}
			{displayedLines}
			{currentLineIndex}
			{isTyping}
			{selectedIndex}
			onButtonClick={handleButtonClick}
			onHoverButton={(i) => selectedIndex = i}
			onLinkClick={handleLinkClick}
			terminalSettings={terminalSettings}
		/>

		<TuiFooter isTyping={isTyping} linesCount={displayedLines.length} skipAnimation={skipAnimation} />
	</div>
</div>

<style>
	.tui-terminal {
		font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
		background: var(--terminal-bg);
		border: 2px solid var(--terminal-border);
		border-radius: 8px;
		overflow: hidden;
		position: relative;
		display: flex;
		flex-direction: column;
		width: 95%;

		margin: 0 auto;
		height: calc(100vh - var(--navbar-height) - 80px);
		max-height: calc(100vh - var(--navbar-height) - 80px);
		animation: tuiFadeIn 0.4s ease-out;
	}

	.tui-terminal:focus-within .tui-border-glow {
		opacity: 1;
	}

	@keyframes tuiFadeIn {
		from {
			opacity: 0;
			transform: scale(0.98);
		}
		to {
			opacity: 1;
			transform: scale(1);
		}
	}

	/* Hyprland-style animated border glow */
	.tui-border-glow {
		position: absolute;
		inset: -2px;
		border-radius: 10px;
		background: linear-gradient(
			45deg,
			var(--terminal-primary),
			var(--terminal-accent),
			var(--terminal-primary),
			var(--terminal-accent)
		);
		background-size: 400% 400%;
		animation: borderGlow 8s ease infinite;
		opacity: 0.5;
		z-index: -1;
		filter: blur(4px);
		transition: opacity 0.3s ease;
	}

	@keyframes borderGlow {
		0%, 100% { background-position: 0% 50%; }
		50% { background-position: 100% 50%; }
	}

	.tui-content {
		display: flex;
		flex-direction: column;
		height: 100%;
		background: var(--terminal-bg);
		position: relative;
		z-index: 1;
	}

	/* Responsive */
	@media (max-width: 768px) {
		.tui-terminal {
			width: 95%;
			height: calc(100vh - var(--navbar-height) - 60px);
			max-height: calc(100vh - var(--navbar-height) - 60px);
		}
	}
</style>
