-- lx-bundle:true
local tests = {}

-- Returns sorted list of Lua test file paths under tests/
local function collect_test_files()
	local files = {}
	local seen = {}
	local roots = {}
	if TESTS_DIR then
		roots[#roots + 1] = TESTS_DIR
	end
	for r = 1, #roots do
		local root = roots[r]
		local names = system.list_dir(root) or {}
		for i = 1, #names do
			local name = names[i]
			if name:match("%.lua$") then
				local path = root .. PATHSEP .. name
				if not seen[path] then
					seen[path] = true
					files[#files + 1] = path
				end
			end
		end
	end
	table.sort(files)
	return files
end

-- Derives unit label from test file path
local function unit_label_from_path(path)
	local name = (type(path) == "string" and path:match("([^/\\]+)$")) or "unit"
	return (name:gsub("%.lua$", ""))
end

-- Executes tests/*.lua files and reports a compact aggregate summary
function tests.run_tests(core, config, opts)
	opts = opts or {}
	local force = opts.force == true
	local traceback = (_G.debug and _G.debug.traceback) or tostring -- Use global debug.traceback without shadowing module table
	local testmod = require("core.test")
	local files = collect_test_files()
	local unit_total = #files
	local unit_passed = 0
	local unit_failed = 0
	local unit_skipped = 0
	local test_total = 0
	local test_passed = 0
	local test_failed = 0

	if not force then
		if config and config.debug_auto_run_tests == false then
			return true
		end
		if config and config.debug_auto_run_tests == true then
			core.log_quiet("[Debug] Auto-running tests on startup")
		end
	end

	if unit_total == 0 then
		if force then
			core.log("[Debug] No units found in <tests/*.lua>")
			if opts.cli == true then
				print("[Test] RESULT=PASS units=0 tests=0")
			end
		end
		return true
	end

	for i = 1, unit_total do
		local path = files[i]
		local unit_name = unit_label_from_path(path)
		local unit_state = "ok"
		local unit_stats = nil
		if type(testmod._set_current_unit) == "function" then
			testmod._set_current_unit(path)
		end
		if type(testmod._take_finished_result) == "function" then
			testmod._take_finished_result()
		end
		local chunk, load_err = loadfile(path)
		if not chunk then
			unit_state = "fail"
			-- Show test file path with shared core log-path formatting
			core.error("[Debug] Error in test unit <%s>\n%s", unit_name, tostring(load_err))
		else
			local function run_unit()
				return chunk()
			end
			local ok, run_a, run_b = xpcall(run_unit, traceback)
			if type(testmod._take_finished_result) == "function" then
				unit_stats = testmod._take_finished_result()
			end
			if not ok then
				unit_state = "fail"
				core.log_quiet_level("error", "[Debug] Failed test unit <%s>\n%s", unit_name, tostring(run_a))
			elseif run_a == true then
				unit_state = "ok"
				core.log_quiet_level("success", "[Debug] Passed test unit <%s>", unit_name)
			elseif run_a == false then
				unit_state = "fail"
				core.log_quiet_level(
					"error",
					'[Debug] Failed test unit <%s> "%s"',
					unit_name,
					tostring(run_b or "returned false")
				)
				-- Print per-test failure details so unit-level failures are immediately actionable
				if unit_stats and type(unit_stats.failures) == "table" then
					for j = 1, #unit_stats.failures do
						core.log_quiet_level("error", "[Debug] <%s> %s", unit_name, tostring(unit_stats.failures[j]))
					end
				end
			elseif run_a == nil then
				unit_state = "skip"
				core.log_quiet_level("warning", "[Debug] Skipped test unit <%s>", unit_name)
			else
				unit_state = "fail"
				core.log_quiet_level(
					"error",
					'[Debug] Test unit <%s> returns invalid type "%s"',
					unit_name,
					type(run_a)
				)
			end
		end

		if unit_stats then
			test_total = test_total + (unit_stats.total or 0)
			test_passed = test_passed + (unit_stats.passed or 0)
			test_failed = test_failed + (unit_stats.failed or 0)
			if unit_state ~= "skip" then
				if unit_stats.ok == true then
					unit_state = "ok"
				elseif unit_stats.ok == false then
					unit_state = "fail"
					-- Also print per-test failure details when unit state is derived from finish() stats
					if type(unit_stats.failures) == "table" then
						for j = 1, #unit_stats.failures do
							core.log_quiet_level(
								"error",
								"[Debug] <%s> %s",
								unit_name,
								tostring(unit_stats.failures[j])
							)
						end
					end
				end
			end
		end

		if unit_state == "ok" then
			unit_passed = unit_passed + 1
		elseif unit_state == "skip" then
			unit_skipped = unit_skipped + 1
		elseif unit_state == "fail" then
			unit_failed = unit_failed + 1
		end
	end

	if unit_failed > 0 then
		local run_msg = string.format(
			--      "Test units: %d (%d ok, %d fail) -> Tests: %d (%d ok, %d fail)",
			"Failed %d of %d tests in %d units",
			test_failed,
			test_total,
			unit_failed
		)
		core.error("[Debug] %s", run_msg)
		if opts.cli == true then
			print(string.format("[Test] RESULT=FAIL units=%d tests=%d failed=%d", unit_total, test_total, test_failed))
		end

		return false
	else
		local run_msg = string.format("Passed %d tests in %d units without errors", test_total, unit_total)
		core.success("[Debug] %s", run_msg)
		if opts.cli == true then
			print(string.format("[Test] RESULT=PASS units=%d tests=%d", unit_total, test_total))
		end

		return true
	end
end

return tests
