import { drawText} from "./builtins.ts";
import { getKeysPressed, shiftKeyDown, shiftMap, K } from "./keyboard.ts";
import { font } from "./font.ts";
import { addToContext, evalCode } from "./runcode.ts";
import { clearScreen, fillRect } from "./window.ts";

const lineHeight = 6;

const history: Array<string> = [];
let historyIndex = history.length;
let textLinesAbove: Array<string> = [];
let maxLineLen = 0;
let currentLine = "";
let index = 0;

export const resetRepl = () => {
	historyIndex = history.length;
	textLinesAbove.length = 0;
	maxLineLen = 0;
	currentLine = "";
	index = 0;
}

const print = (arg: unknown) => {
	textLinesAbove.push(...String(arg).split("\n").flatMap((line)=>{
		const wrap = [];
		while (line.length) {
			wrap.push(line.slice(0,32));
			line = line.slice(32);
		}
		return wrap;
	}));
	textLinesAbove = textLinesAbove.slice(-20);
}

const printVal = (arg: unknown) => {
	print(JSON.stringify(arg));
}

addToContext("print", print);
addToContext("printVal", printVal);

const update = () => {
	for (const key of getKeysPressed()) {
		let char = String.fromCharCode(key).toLowerCase();
		if (shiftKeyDown()) {
			if (char in shiftMap) {
				char = shiftMap[char as keyof typeof shiftMap];
			} else {
				char = char.toUpperCase();
			}
		}
		if (char in font) {
			currentLine = currentLine.slice(0, index)+char+currentLine.slice(index);
			index += 1;
		} else if (key === K.BACKSPACE) {
			if (index > 0) {
				currentLine = currentLine.slice(0, index-1)+currentLine.slice(index);
				index -= 1;
			}
		} else if (key === K.ARROW_LEFT) {
			index -= 1;
			if (index < 0) {
				index = 0;
			}
		} else if (key === K.ARROW_RIGHT) {
			index += 1;
			if (index > currentLine.length) {
				index = currentLine.length;
			}
		} else if (key === K.ARROW_UP) {
			historyIndex -= 1;
			if (historyIndex < 0) {
				historyIndex = -1;
			}
			const lineAtHistory = history[historyIndex] ?? "";
			currentLine = lineAtHistory;
			index = currentLine.length;
		} else if (key === K.ARROW_DOWN) {
			historyIndex += 1;
			if (historyIndex > history.length) {
				historyIndex = history.length;
			}
			const lineAtHistory = history[historyIndex] ?? "";
			currentLine = lineAtHistory;
			index = currentLine.length;
		} else if (key === K.ENTER) {
			if (currentLine) {
				history.push(currentLine);
				historyIndex = history.length;
			}
			print("> "+currentLine);
			try {
				const ran = evalCode(currentLine);
				if (ran !== undefined) {
					printVal(ran);
				}
			} catch (err) {
				print(err.name+":\n"+err.message);
			}
			maxLineLen = 0;
			currentLine = "";
			index = 0;
		}
	}
	maxLineLen = Math.max(maxLineLen, currentLine.length);
}

const drawTextAbove = () => {
	textLinesAbove.forEach((line, i) => {
		fillRect(0, 1+i*lineHeight, 4*(line.length+1)+1, lineHeight+1, 0);
		drawText(-1, 1+i*lineHeight, line);
	});
}

const draw = () => {
	clearScreen();

	drawTextAbove();

	fillRect(0, 1+textLinesAbove.length*lineHeight, 4*(2+maxLineLen+1)+1, lineHeight+1, 0);
	fillRect((2+index)*4, textLinesAbove.length*lineHeight+1, 4, lineHeight-1, 3);
	drawText(-1, 1+textLinesAbove.length*lineHeight, "> "+currentLine);
}

export const repl = {
	update, draw
}