import {URLParser} from "../js/navigation_state_url.mjs"
import {NavigationError, NavigationState, navigation_objectify} from "../js/navigation_state.mjs"
import {assert_equal} from "/assert.mjs"


function test_guess_mountpoint(url, correct_result) {
	//console.log(url,"->", correct_result)
	assert_equal(0,2,URLParser.guess_mountpoint(url), correct_result)
}

function parse_href(url_parser, href, correct_state, href_should_be_relative, error_kind) {
	//console.log(href,"->", correct_result, error_kind)
	//console.log(href)
	if (correct_state == NavigationError)
		try {
			url_parser.parse_href(href)
			throw "shit"
		} catch (error) {
			//console.log(error.kind)
			if (!error instanceof NavigationError) throw error
			assert_equal(0, 2, error.kind, error_kind)
		}
	else {
		const parsed = url_parser.parse_href(href)
		assert_equal(0, 2, parsed.relative, href_should_be_relative)
		assert_equal(0, 2, navigation_objectify(parsed.diff.patch(NavigationState.create())), navigation_objectify(correct_state))
	}
}

function generate_hrefs(url_parser, old_url, new_state,  correct_result) {
	//console.log(state,"->", correct_result)
	//console.log(old_url)
	const url = url_parser.parse_url(old_url)
	const external_base_state = url.base_diff.patch(NavigationState.create())
	const internal_base_state = external_base_state
	//const old_state_url = url_parser.generate_url(null, NavigationState.create(), old_state, true)
	//console.log(old_url, old_state_search)
	//generate_hrefs(internal_base_state, external_base_state, external_base_state_is_shareable, external_base_state_applied_version, new_state) {
	assert_equal(0, 2, url_parser.generate_hrefs(internal_base_state, external_base_state, true, url.version, new_state), correct_result)
}

function generate_url(url_parser, state_key, base_state, state, correct_result, correct_is_perfect) {
	//console.log(state_key, base_state, state, "->", correct_result, correct_is_perfect)
	const url = url_parser.generate_url(state_key, base_state, state, true)
	assert_equal(0, 2, url.url, correct_result)
	assert_equal(0, 2, url.is_perfect, correct_is_perfect)
}


function parse_url(url_parser, url, correct_result, correct_error_kind_or_state_key) {
	//console.log(url,"->", correct_result)
	try {
		if (correct_result == null)
			assert_equal(0, 2, url_parser.parse_url(url), null)
		else {
			let parsed = url_parser.parse_url(url)
			console.log(parsed)
			assert_equal(0, 2, parsed.key, correct_error_kind_or_state_key)
			assert_equal(0, 2, parsed.diff.patch(NavigationState.create()), correct_result)
		}
	} catch (exception) {
		if (!(typeof correct_result === 'function')) throw exception
		if (!(exception instanceof NavigationError)) throw "Wrong exception, expected "+correct_result+" got "+exception
		assert_equal(0, 2, exception.kind, correct_error_kind_or_state_key)
		//if (!exception.message.match(correct_message_pattern_or_state_key)) throw "Wrong exception message, expected "+correct_message_pattern_or_state_key+" got "+exception.message
	}

}

export async function runTests() {
	console.group("NavigationStateUrl")

	const url_base = window.location.origin + window.location.pathname
	if (window.location.pathname.endsWith("/")) throw "meh"

	console.group("guess_mountpoint()")
	test_guess_mountpoint("", "")
	test_guess_mountpoint("/xxx", "/xxx")
	test_guess_mountpoint("/xxx/b", "/xxx")
	test_guess_mountpoint("/xxx/b/", "/xxx")
	test_guess_mountpoint("/xxx/b/b/", "/xxx")
	test_guess_mountpoint("/xxx/something.html", "/xxx/something.html")
	console.groupEnd()

	console.group("dynamic URLParser:: parse_href()")
	let url_parser = new URLParser(window.location.origin, URLParser.guess_mountpoint(window.location.pathname), "b", true, [])
	parse_href(url_parser, "", NavigationState.create(), true)
	parse_href(url_parser, "?", NavigationState.create(), true)
	parse_href(url_parser, "#", NavigationState.create(), true)
	parse_href(url_parser, "?b", NavigationState.create(), true)
	parse_href(url_parser, "#b", NavigationState.create(), true)
	parse_href(url_parser, window.location.pathname, NavigationState.create(), false)
	parse_href(url_parser, "?a=b", NavigationState.create({ a: "b" }), true)
	parse_href(url_parser, "?a=b&c=d", NavigationState.create({ a: "b", c: "d" }), true)
	parse_href(url_parser, "#a=b", NavigationState.create({ a: "b" }), true)
	parse_href(url_parser, "#a=b&c=d", NavigationState.create({ a: "b", c: "d" }), true)
	parse_href(url_parser, "?a=b#c=d", NavigationState.create({ a: "b", c: "d" }), true)
	parse_href(url_parser, window.location.pathname+"?b&a=b", NavigationState.create({ a: "b" }), false)
	parse_href(url_parser, "http://something/", NavigationError, null, 'WrongHREFStart')
	parse_href(url_parser, "origin/not-mountpoint", NavigationError, null, 'WrongHREFStart')
	parse_href(url_parser, "origin/aoeu.html", NavigationError, null, 'WrongHREFStart')
	parse_href(url_parser, "/aoeu.html", NavigationError, null, 'WrongHREFStart')
	console.groupEnd()

	console.group("static URLParser::parse_href()")
	url_parser = new URLParser(window.location.origin, URLParser.guess_mountpoint(window.location.pathname), "b", false, [])
	parse_href(url_parser, "", NavigationState.create(), true)
	parse_href(url_parser, "?", NavigationState.create(), true)
	parse_href(url_parser, "#", NavigationState.create(), true)
	parse_href(url_parser, window.location.pathname, NavigationState.create(), false)
	parse_href(url_parser, "?b&a=b", NavigationState.create({ a: "b" }), true)
	parse_href(url_parser, "?b&a=b&c=d", NavigationState.create({ a: "b", c: "d" }), true)
	parse_href(url_parser, "?b&a=b#c=d", NavigationState.create({ a: "b", c: "d" }), true)
	parse_href(url_parser, "#b&a=b", NavigationState.create({ a: "b" }), true)
	parse_href(url_parser, "#b&a=b&c=d", NavigationState.create({ a: "b", c: "d" }), true)
	parse_href(url_parser, window.location.pathname+"?b&a=b", NavigationState.create({ a: "b" }), false)
	parse_href(url_parser, "http://something/", NavigationError, null, 'WrongHREFStart')
	parse_href(url_parser, "origin/not-mountpoint", NavigationError, null, 'WrongHREFStart')
	parse_href(url_parser, "origin/aoeu.html", NavigationError, null, 'WrongHREFStart')
	parse_href(url_parser, "/aoeu.html", NavigationError, null, 'WrongHREFStart')
	console.groupEnd()

	console.group("dynamic URLParser::generate_hrefs()")
	url_parser = new URLParser(window.location.origin, URLParser.guess_mountpoint(window.location.pathname), "b", true, [])
	generate_hrefs(url_parser, url_base, NavigationState.create({}), { href: "?" })
	generate_hrefs(url_parser, url_base, NavigationState.create({ a: "b" }), { href: "?b&a=b" })
	generate_hrefs(url_parser, url_base, NavigationState.create({ a: "b", c: "d" }), { href: "?b&a=b&c=d" })
	generate_hrefs(url_parser, url_base, NavigationState.create({ a: "x".repeat(2000) }), { "data-internal-href": ("?a=" + "x".repeat(2000)) })
	generate_hrefs(url_parser, url_base, NavigationState.create().private_merge({ a: "b" }), { href: "?", "data-internal-href": "?~.a=b" })
	generate_hrefs(url_parser, url_base+"?b&a=b", NavigationState.create({}), { href: "?" })
	generate_hrefs(url_parser, url_base+"?b&a=b", NavigationState.create({a: "b"}), { href: "?b&a=b" })
	generate_hrefs(url_parser, url_base+"?b&a=b", NavigationState.create({a: "c"}), { href: "?b&a=c" })
	generate_hrefs(url_parser, url_base+"/b/a/b", NavigationState.create({}), { href: "?a=~" })
	generate_hrefs(url_parser, url_base+"/b/a/b", NavigationState.create({a: "b"}), { href: "?" })
	generate_hrefs(url_parser, url_base+"/b/a/b", NavigationState.create({a: "c"}), { href: "?a=c" })
	generate_hrefs(url_parser, url_base+"/b/a/b", NavigationState.create().private_merge({a: "b"}), { href: "?a=~", "data-internal-href": "?a=~&~.a=b" })
	generate_hrefs(url_parser, url_base+"/b/a/b", NavigationState.create({a: "b"}).private_merge({a: "b"}), { href: "?", "data-internal-href": "?~.a=b" })
	console.groupEnd()

	console.group("static URLParser::generate_href()")
	url_parser = new URLParser(window.location.origin, URLParser.guess_mountpoint(window.location.pathname), "b", false, [])
	generate_hrefs(url_parser, url_base, NavigationState.create({}), { href: "#" })
	generate_hrefs(url_parser, url_base, NavigationState.create({ a: "b" }), { href: "#b&a=b" })
	generate_hrefs(url_parser, url_base, NavigationState.create({ a: "b", c: "d" }), { href: "#b&a=b&c=d" })
	generate_hrefs(url_parser, url_base, NavigationState.create({ a: "x".repeat(2000) }), { "data-internal-href": ("#a=" + "x".repeat(2000)) })
	generate_hrefs(url_parser, url_base, NavigationState.create().private_merge({ a: "b" }), { href: "#", "data-internal-href": "#~.a=b" })
	generate_hrefs(url_parser, url_base+"#b&a=b", NavigationState.create({}), { href: "#" })
	generate_hrefs(url_parser, url_base+"#b&a=b", NavigationState.create({a: "b"}), { href: "#b&a=b" })
	generate_hrefs(url_parser, url_base+"#b&a=b", NavigationState.create({a: "c"}), { href: "#b&a=c" })
	generate_hrefs(url_parser, url_base+"?b&a=b", NavigationState.create({}), { href: "#a=~" })
	generate_hrefs(url_parser, url_base+"?b&a=b", NavigationState.create({a: "b"}), { href: "#" })
	generate_hrefs(url_parser, url_base+"?b&a=b", NavigationState.create({a: "c"}), { href: "#a=c" })
	generate_hrefs(url_parser, url_base+"?b&a=b", NavigationState.create().private_merge({a: "b"}), { href: "#a=~", "data-internal-href": "#a=~&~.a=b" })
	generate_hrefs(url_parser, url_base+"?b&a=b", NavigationState.create({a: "b"}).private_merge({a: "b"}), { href: "#", "data-internal-href": "#~.a=b" })
	console.groupEnd()

	console.group("dynamic URLParser::parse_url()")
	let url_parser_with_slash = new URLParser(window.location.origin, window.location.pathname+"/", "b", true, [["pretty", "ugly.val"]])
	parse_url(url_parser_with_slash, url_base, NavigationError, "WrongURLMountpoint")

	let url_parser_without_slash = new URLParser(window.location.origin, window.location.pathname, "b", true, [["pretty", "ugly.val"]])
	parse_url(url_parser_without_slash, url_base, NavigationState.create(), null)
	parse_url(url_parser_without_slash, url_base+"abc", NavigationError, "WrongURLMountpoint")
	parse_url(url_parser_without_slash, "http://something/", NavigationError, "WrongURLOrigin")
	parse_url(url_parser_without_slash, window.location.origin+"/not-mountpoint", NavigationError, "WrongURLMountpoint")
	parse_url(url_parser_without_slash, url_base, NavigationState.create({}), null)
	parse_url(url_parser_without_slash, url_base+"?b&a=b&c=d", NavigationState.create({ a: "b", c: "d" }), null)
	parse_url(url_parser_without_slash, url_base+"#b&a=b", NavigationState.create({}), null)
	parse_url(url_parser_without_slash, url_base+"#b&a=b&c=d", NavigationState.create({}), null)
	parse_url(url_parser_without_slash, url_base+"?b&a=b#c=d", NavigationState.create({ a: "b" }), null)

	for (url_parser of [url_parser_with_slash, url_parser_without_slash]) {
		console.group("Loop")
		parse_url(url_parser, url_base+"/?b&a=b&c=d", NavigationState.create({ a: "b", c: "d" }), null)
		parse_url(url_parser, url_base+"/", NavigationState.create({}), null)
		parse_url(url_parser, url_base+"/aoeu", NavigationError, "UnknownUrlFormatVersion")
		parse_url(url_parser, url_base+"/==", NavigationError, "URLNotShareable")
		parse_url(url_parser, url_base+"/==NOT_SHAREABLE", NavigationError, "URLNotShareable")
		parse_url(url_parser, url_base+"/b", NavigationState.create({}), null)
		parse_url(url_parser, url_base+"/b/", NavigationState.create({}), null)
		parse_url(url_parser, url_base+"/b/a", NavigationState.create({}), "a")
		parse_url(url_parser, url_base+"/b/a/", NavigationState.create({}), "a")  //TODO rethink this one
		parse_url(url_parser, url_base+"/b/a//", NavigationState.create({ a: "" }), null)
		parse_url(url_parser, url_base+"/b/a/b", NavigationState.create({ a: "b" }), null)
		parse_url(url_parser, url_base+"/b/a/b/", NavigationState.create({ a: "b" }), null)
		parse_url(url_parser, url_base+"/b/a/b/c", NavigationState.create({}), "a")
		parse_url(url_parser, url_base+"/b/a/b?a=c&c=d", NavigationState.create({ a: "c", c: "d" }), null)
		parse_url(url_parser, url_base+"/b/?a=b&c=d", NavigationState.create({ a: "b", c: "d" }), null)
		parse_url(url_parser, url_base+"/b/xyz/?a=b&c=d", NavigationState.create({ a: "b", c: "d" }), "xyz")
		parse_url(url_parser, url_base+"/b/pretty/x", NavigationState.create({ ugly: { val: "x" } }), null)
		parse_url(url_parser, url_base+"/b/a/b/pretty/x/c/d", NavigationState.create({ a: "b", ugly: { val: "x" }, c: "d" }), null)
		console.groupEnd()
	}
	console.groupEnd()

	console.group("static URLParser::parse_url()")
	url_parser_with_slash = new URLParser(window.location.origin, window.location.pathname+"/", "b", false, [])
	parse_url(url_parser_with_slash, url_base, NavigationError, "WrongURLMountpoint")

	url_parser_without_slash = new URLParser(window.location.origin, window.location.pathname, "b", false, [])
	parse_url(url_parser_without_slash, url_base, NavigationState.create({}), null)

	parse_url(url_parser_with_slash, url_base+"/", NavigationState.create({}), null)
	parse_url(url_parser_with_slash, url_base+"/?==", NavigationError, "URLNotShareable")
	parse_url(url_parser_with_slash, url_base+"/?==NOT_SHAREABLE", NavigationError, "URLNotShareable")
	parse_url(url_parser_with_slash, url_base+"/?b&a=b&c=d", NavigationState.create({ a: "b", c: "d" }), null)
	parse_url(url_parser_with_slash, url_base+"/?b&a=b&c=d#e=f", NavigationState.create({ a: "b", c: "d", e: "f" }), null)
	parse_url(url_parser_with_slash, url_base+"/#b&e=f", NavigationState.create({ e: "f" }), null)

	parse_url(url_parser_without_slash, url_base+"", NavigationState.create({}), null)
	parse_url(url_parser_without_slash, url_base+"?==", NavigationError, "URLNotShareable")
	parse_url(url_parser_without_slash, url_base+"?==NOT_SHAREABLE", NavigationError, "URLNotShareable")
	parse_url(url_parser_without_slash, url_base+"?b&a=b&c=d", NavigationState.create({ a: "b", c: "d" }), null)
	parse_url(url_parser_without_slash, url_base+"?b&a=b&c=d#e=f", NavigationState.create({ a: "b", c: "d", e: "f" }), null)
	parse_url(url_parser_without_slash, url_base+"#b&e=f", NavigationState.create({ e: "f" }), null)

	console.groupEnd()

	console.group("dynamic URLParser::generate_url()")
	url_parser = new URLParser(window.location.origin, window.location.pathname, "b", true, [["pretty", "ugly"], ["deep", "so.much"]])
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({}), url_base, true)
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({ a: "b" }), url_base+"/b/a/b", false)
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({ a: "b", c: "d" }), url_base+"/b/a/b/c/d", false)
	//generate_url(url_parser, undefined, NavigationState.create({ a: "b" }), NavigationState.create({ a: "b", c: "d" }), url_base+"/b/c/d", false)
	generate_url(url_parser, "xyz", NavigationState.create({ a: "b" }), NavigationState.create({ a: "b", c: "d" }), url_base+"/b/xyz/c/d", false)
	generate_url(url_parser, "xyz", NavigationState.create({ a: "b", c: "d" }), NavigationState.create({ a: "b", c: "d" }), url_base+"/b/xyz/", true)
	generate_url(url_parser, "xyz", NavigationState.create({ a: "b", ugly: "d" }), NavigationState.create({ a: "b", ugly: "d" }), url_base+"/b/xyz/pretty/d", true)
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({ a: "b", ugly: "d" }), url_base+"/b/pretty/d/a/b", false)
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({ a: "b", so: { much: "yes"}, ugly: "d" }), url_base+"/b/pretty/d/deep/yes/a/b", false)
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({ a: "x".repeat(2000) }), url_base+"/==NOT-SHAREABLE", false)
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({}).private_set("a", "b"), url_base, true)
	generate_url(url_parser, undefined, NavigationState.create({}).private_set("a", "b"), NavigationState.create({}), url_base, true)
	generate_url(url_parser, undefined, NavigationState.create({}).private_set("a", "b"), NavigationState.create({}).private_set("a", "b"), url_base, true)

	url_parser = new URLParser(window.location.origin, window.location.pathname + '/', "b", true, [["pretty", "ugly"], ["deep", "so.much"]])
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({}), url_base+"/", true)
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({ a: "b" }), url_base+"/b/a/b", false)
	console.groupEnd()


	console.group("static URLParser::generate_url()")
	url_parser = new URLParser(window.location.origin, window.location.pathname, "b", false, [["pretty", "ugly"], ["deep", "so.much"]])
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({}), url_base+"", true)
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({ a: "b" }), url_base+"?b&a=b", false)
	generate_url(url_parser, "xyz", NavigationState.create({a: "b"}), NavigationState.create({ a: "b", c: "d" }), url_base+"?b/xyz&c=d", false)
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({ a: "x".repeat(2000) }), url_base+"?==NOT-SHAREABLE", false)
	generate_url(url_parser, undefined, NavigationState.create({}), NavigationState.create({}).private_set("a", "b"), url_base+"", true)
	generate_url(url_parser, undefined, NavigationState.create({}).private_set("a", "b"), NavigationState.create({}).private_set("a", "b"), url_base+"", true)
	generate_url(url_parser, undefined, NavigationState.create({}).private_set("a", "b"), NavigationState.create({}).private_set("a", "b"), url_base+"", true)
	console.groupEnd()

	console.groupEnd()

	document.getElementById("state_url_result").innerHTML = "OK"
}
