<script lang="ts">
	import { onMount } from 'svelte';
	import { themeColors } from '$lib/stores/theme';
	import { terminalSettings, type SpeedPreset, speedPresets } from '$lib/config';
	import TuiHeader from './tui/TuiHeader.svelte';
	import TuiBody from './tui/TuiBody.svelte';
	import TuiFooter from './tui/TuiFooter.svelte';
	import '$lib/assets/css/terminal-tui.css';

	// Import extracted modules
	import { parseLine, createTerminalAPI } from './tui/terminal-api';
	import { runTypingAnimation, skipTypingAnimation } from './tui/terminal-typing';
	import { createKeyboardHandler, handleNavigation, scrollToHash } from './tui/terminal-keyboard';

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

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

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

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

	// Get colorMap from current theme
	const colorMap = $derived($themeColors.colorMap);

	// Pre-parse all lines upfront (segments + plain text)
	const parsedLines = $derived<ParsedLine[]>(
		lines.map(line => parseLine(line, colorMap))
	);

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

	// Track colorMap identity to detect theme/mode changes
	let lastColorMapId = $state('');
	
	// When colorMap changes (theme/mode toggle), update displayedLines with new parsed segments
	$effect(() => {
		// Create a simple identity string from a few colorMap values
		const colorMapId = `${colorMap.red}-${colorMap.text}-${colorMap.primary}`;
		
		// Only update if colorMap actually changed and animation is complete
		if (colorMapId !== lastColorMapId && isComplete && displayedLines.length > 0) {
			// Store current showImage states before updating
			const showImageStates = displayedLines.map(d => d.showImage);
			
			// Update with new parsed content
			displayedLines = parsedLines.map((parsed, i) => ({
				parsed,
				charIndex: parsed.plainText.length,
				complete: true,
				showImage: showImageStates[i] ?? (parsed.line.type === 'image')
			}));
		}
		
		lastColorMapId = colorMapId;
	});

	// Helper to check if a line or its children contain buttons
	function hasButtons(line: TerminalLine): boolean {
		if (line.type === 'button') return true;
		if (line.type === 'group' && line.children) {
			return line.children.some(child => hasButtons(child));
		}
		return false;
	}

	// Get all interactive button indices (including buttons nested in groups)
	const buttonIndices = $derived(
		displayedLines
			.map((item, i) => hasButtons(item.parsed.line) ? i : -1)
			.filter(i => i !== -1)
	);

	// ========================================================================
	// TYPING ANIMATION
	// ========================================================================

	function typeText() {
		runTypingAnimation({
			parsedLines,
			speedMultiplier,
			terminalSettings,
			buttonIndices,
			interactive,
			autoscroll,
			getBodyElement: () => bodyElement,
			getState: () => ({ displayedLines, currentLineIndex, isTyping, isComplete, skipRequested, selectedIndex }),
			setState: (updates) => {
				if (updates.displayedLines !== undefined) displayedLines = updates.displayedLines;
				if (updates.currentLineIndex !== undefined) currentLineIndex = updates.currentLineIndex;
				if (updates.isTyping !== undefined) isTyping = updates.isTyping;
				if (updates.isComplete !== undefined) isComplete = updates.isComplete;
				if (updates.skipRequested !== undefined) skipRequested = updates.skipRequested;
				if (updates.selectedIndex !== undefined) selectedIndex = updates.selectedIndex;
			},
			onComplete,
			scrollToHash: () => scrollToHash(bodyElement)
		});
	}

	function skipAnimation() {
		skipTypingAnimation(
			parsedLines,
			buttonIndices,
			interactive,
			() => ({ displayedLines, currentLineIndex, isTyping, isComplete, skipRequested, selectedIndex }),
			(updates) => {
				if (updates.displayedLines !== undefined) displayedLines = updates.displayedLines;
				if (updates.currentLineIndex !== undefined) currentLineIndex = updates.currentLineIndex;
				if (updates.isTyping !== undefined) isTyping = updates.isTyping;
				if (updates.isComplete !== undefined) isComplete = updates.isComplete;
				if (updates.skipRequested !== undefined) skipRequested = updates.skipRequested;
				if (updates.selectedIndex !== undefined) selectedIndex = updates.selectedIndex;
			},
			() => bodyElement,
			autoscroll,
			onComplete
		);
	}

	// ========================================================================
	// TERMINAL API
	// ========================================================================

	terminal = createTerminalAPI({
		getState: () => ({
			lines,
			displayedLines,
			isTyping,
			isComplete,
			currentLineIndex,
			selectedIndex,
			skipRequested
		}),
		setState: (updates) => {
			if (updates.lines !== undefined) lines = updates.lines;
			if (updates.displayedLines !== undefined) displayedLines = updates.displayedLines;
			if (updates.isTyping !== undefined) isTyping = updates.isTyping;
			if (updates.isComplete !== undefined) isComplete = updates.isComplete;
			if (updates.currentLineIndex !== undefined) currentLineIndex = updates.currentLineIndex;
			if (updates.selectedIndex !== undefined) selectedIndex = updates.selectedIndex;
			if (updates.skipRequested !== undefined) skipRequested = updates.skipRequested;
		},
		getColorMap: () => colorMap,
		getBodyElement: () => bodyElement,
		typeText
	});

	// ========================================================================
	// KEYBOARD HANDLING
	// ========================================================================

	const handleKeydown = createKeyboardHandler({
		getIsTyping: () => isTyping,
		getIsComplete: () => isComplete,
		getInteractive: () => interactive,
		getButtonIndices: () => buttonIndices,
		getSelectedIndex: () => selectedIndex,
		setSelectedIndex: (index) => { selectedIndex = index; },
		getDisplayedLines: () => displayedLines,
		getBodyElement: () => bodyElement,
		skipAnimation,
		scrollMargin: terminalSettings.scrollMargin
	});

	function handleButtonClick(index: number) {
		selectedIndex = index;
		handleNavigation(displayedLines[index]?.parsed.line);
	}

	function handleLinkClick(index: number) {
		handleNavigation(displayedLines[index]?.parsed.line);
	}

	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-secondary: {$themeColors.secondary};
		--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>
