
export class AssertionFailedError extends Error {
}

function log(print_stack_frames_from, print_stack_frames_to) {
	console.log("• "+new Error().stack.split('\n').slice(print_stack_frames_from+2, print_stack_frames_from+print_stack_frames_to+2).map((frame)=> frame.split('/').pop()).join(" / "))
}


export function assert(print_stack_frames_from, print_stack_frames_to, v) {
	log(print_stack_frames_from, print_stack_frames_to)
	if (!v) {
		throw new AssertionFailedError("Condition not true")
	}
}

export function assert_equal(print_stack_frames_from, print_stack_frames_to, v1, v2) {
	log(print_stack_frames_from, print_stack_frames_to)
	if (!equal(v1, v2)) {
		console.error(v1, v2)
		throw new AssertionFailedError("Not equal:\n"+JSON.stringify(v1)+"\n"+JSON.stringify(v2))
	}
}

// Implemented by LLM/devstral-small-2:24b
function equal(a, b) {
	if (a === b) return true;
	if (typeof a !== typeof b) return false;
	if (a === null || b === null) return false;
	if (typeof a !== 'object') return false;

	if (Array.isArray(a) !== Array.isArray(b)) return false;
	if (Array.isArray(a)) {
		if (a.length !== b.length) return false;
		for (let i = 0; i < a.length; i++) {
			if (!equal(a[i], b[i])) return false;
		}
		return true;
	}

	if (a.constructor !== b.constructor) return false;

	const keysA = Object.keys(a);
	const keysB = Object.keys(b);

	if (keysA.length !== keysB.length) return false;

	for (const key of keysA) {
		if (!keysB.includes(key)) return false;
		if (!equal(a[key], b[key])) return false;
	}

	return true;
}

export function assert_matches(print_stack_frames_from, print_stack_frames_to, v1, pattern) {
	log(print_stack_frames_from, print_stack_frames_to)
	if (v1.match(pattern) == null) {
		throw new AssertionFailedError("Doesn't match: "+JSON.stringify(v1)+"    "+JSON.stringify(pattern))
	}
}

export function assert_not_equal(print_stack_frames_from, print_stack_frames_to, v1, v2) {
	log(print_stack_frames_from, print_stack_frames_to)
	if (equal(v1, v2)) {
		throw new AssertionFailedError("Not equal: "+JSON.stringify(v1)+"    "+JSON.stringify(v2))
	}
}
