/**
 * Terminal API Factory
 * 
 * Creates a reactive API for manipulating terminal content programmatically.
 * Use this with TerminalTUI's bindable `terminal` prop.
 */

import type { TerminalLine, ParsedLine, DisplayedLine, TerminalAPI } from './types';
import { parseColorText, getPlainText } from './utils';
import type { ThemeColorMap } from './utils';

export interface TerminalState {
	lines: TerminalLine[];
	displayedLines: DisplayedLine[];
	isTyping: boolean;
	isComplete: boolean;
	currentLineIndex: number;
	selectedIndex: number;
	skipRequested: boolean;
}

export interface TerminalAPIOptions {
	getState: () => TerminalState;
	setState: (updates: Partial<TerminalState>) => void;
	getColorMap: () => ThemeColorMap;
	getBodyElement: () => HTMLDivElement | undefined;
	typeText: () => void;
}

/**
 * Parse a single terminal line into segments
 */
export function parseLine(line: TerminalLine, colorMap: ThemeColorMap): ParsedLine {
	const segments = parseColorText(line.content, colorMap);
	return {
		line,
		segments,
		plainText: getPlainText(segments)
	};
}

/**
 * Create a terminal API instance
 */
export function createTerminalAPI(options: TerminalAPIOptions): TerminalAPI {
	const { getState, setState, getColorMap, getBodyElement, typeText } = options;

	function refreshDisplayedLines() {
		const state = getState();
		const colorMap = getColorMap();
		const displayedLines = state.lines.map((line, i) => {
			const parsed = parseLine(line, colorMap);
			return {
				parsed,
				charIndex: parsed.plainText.length,
				complete: true,
				showImage: state.displayedLines[i]?.showImage ?? (line.type === 'image')
			};
		});
		setState({ displayedLines, lines: [...state.lines] });
	}

	function apiScrollToBottom() {
		const bodyElement = getBodyElement();
		if (!bodyElement) return;
		bodyElement.scrollTo({
			top: bodyElement.scrollHeight,
			behavior: 'smooth'
		});
	}

	function apiScrollToLine(index: number) {
		const bodyElement = getBodyElement();
		if (!bodyElement) return;
		const lineElements = bodyElement.querySelectorAll('.tui-line');
		const target = lineElements[index] as HTMLElement | undefined;
		if (target) {
			target.scrollIntoView({ behavior: 'smooth', block: 'center' });
		}
	}

	return {
		clear: () => {
			setState({
				lines: [],
				displayedLines: [],
				isComplete: true,
				isTyping: false
			});
		},

		write: (line: TerminalLine) => {
			const state = getState();
			const colorMap = getColorMap();
			const parsed = parseLine(line, colorMap);
			setState({
				lines: [...state.lines, line],
				displayedLines: [...state.displayedLines, {
					parsed,
					charIndex: parsed.plainText.length,
					complete: true,
					showImage: line.type === 'image'
				}]
			});
			setTimeout(apiScrollToBottom, 10);
		},

		writeLines: (newLines: TerminalLine[]) => {
			const state = getState();
			const colorMap = getColorMap();
			const newDisplayed = newLines.map(line => {
				const parsed = parseLine(line, colorMap);
				return {
					parsed,
					charIndex: parsed.plainText.length,
					complete: true,
					showImage: line.type === 'image'
				};
			});
			setState({
				lines: [...state.lines, ...newLines],
				displayedLines: [...state.displayedLines, ...newDisplayed]
			});
			setTimeout(apiScrollToBottom, 10);
		},

		update: (index: number, updates: Partial<TerminalLine>) => {
			const state = getState();
			if (index < 0 || index >= state.lines.length) return;
			// Cast to TerminalLine to allow partial updates across union types
			state.lines[index] = { ...state.lines[index], ...updates } as TerminalLine;
			refreshDisplayedLines();
		},

		updateContent: (index: number, content: string) => {
			const state = getState();
			if (index < 0 || index >= state.lines.length) return;
			state.lines[index] = { ...state.lines[index], content };
			refreshDisplayedLines();
		},

		insert: (index: number, line: TerminalLine) => {
			const state = getState();
			const clampedIndex = Math.max(0, Math.min(index, state.lines.length));
			setState({
				lines: [...state.lines.slice(0, clampedIndex), line, ...state.lines.slice(clampedIndex)]
			});
			refreshDisplayedLines();
		},

		remove: (index: number) => {
			const state = getState();
			if (index < 0 || index >= state.lines.length) return;
			setState({
				lines: [...state.lines.slice(0, index), ...state.lines.slice(index + 1)]
			});
			refreshDisplayedLines();
		},

		removeRange: (startIndex: number, count: number) => {
			const state = getState();
			if (startIndex < 0 || startIndex >= state.lines.length) return;
			setState({
				lines: [...state.lines.slice(0, startIndex), ...state.lines.slice(startIndex + count)]
			});
			refreshDisplayedLines();
		},

		setLines: (newLines: TerminalLine[]) => {
			setState({ lines: [...newLines] });
			refreshDisplayedLines();
		},

		getLineCount: () => getState().lines.length,

		getLine: (index: number) => getState().lines[index],

		getLines: () => [...getState().lines],

		findById: (id: string) => getState().lines.findIndex(line => line.id === id),

		updateById: (id: string, updates: Partial<TerminalLine>) => {
			const state = getState();
			const index = state.lines.findIndex(line => line.id === id);
			if (index !== -1) {
				// Cast to TerminalLine to allow partial updates across union types
				state.lines[index] = { ...state.lines[index], ...updates } as TerminalLine;
				refreshDisplayedLines();
			}
		},

		removeById: (id: string) => {
			const state = getState();
			const index = state.lines.findIndex(line => line.id === id);
			if (index !== -1) {
				setState({
					lines: [...state.lines.slice(0, index), ...state.lines.slice(index + 1)]
				});
				refreshDisplayedLines();
			}
		},

		scrollToBottom: apiScrollToBottom,

		scrollToLine: apiScrollToLine,

		isAnimating: () => getState().isTyping,

		skip: () => {
			const state = getState();
			if (!state.isTyping) return;

			const colorMap = getColorMap();
			const displayedLines = state.lines.map(line => {
				const parsed = parseLine(line, colorMap);
				return {
					parsed,
					charIndex: parsed.plainText.length,
					complete: true,
					showImage: line.type === 'image'
				};
			});

			setState({
				skipRequested: true,
				displayedLines,
				isTyping: false,
				isComplete: true,
				currentLineIndex: state.lines.length - 1
			});

			apiScrollToBottom();
		},

		restart: () => {
			setState({
				displayedLines: [],
				currentLineIndex: 0,
				isTyping: false,
				isComplete: false,
				skipRequested: false,
				selectedIndex: -1
			});
			typeText();
		}
	};
}
