#include "testlib.h"

RENDER(Request& context)
{
	if(!test_demo_request_allowed(context))
	{
		site_tests_restricted(context, "Tasks", "spawn and inspect background worker processes");
		return;
	}

	u64 passed = 0;
	u64 failed = 0;
	u64 skipped = 0;

	auto check = [&](String name, bool ok, String detail)
	{
		site_tests_case(name, ok ? "pass" : "fail", detail);
		if(ok)
			passed++;
		else
			failed++;
	};

	String mode = first(context.get["mode"], "run");
	if(mode == "late")
	{
		String late_file = "/tmp/uce-site-tests-late-task.txt";
		file_unlink(late_file);
		pid_t late_pid = task("site-tests-late-callback", [late_file]() {
			sleep(2);
			DValue perf = request_perf();
			file_put_contents(late_file, "late callback ran pid=" + std::to_string((u64)perf["worker_pid"].to_s64()) + " type=" + perf["worker_pid"].get_type_name());
		}, 10);
		site_tests_page_start("Tasks", "Schedules a delayed task callback and returns before the callback runs.");
		check("late task scheduled", late_pid != 0, "started=" + std::to_string(late_pid));
		site_tests_summary(passed, failed, skipped, "The CLI runner verifies this callback after the spawning request has returned.");
		site_tests_page_end();
		return;
	}
	pid_t repeat_existing = task_pid("site-tests-repeat");
	if(mode == "stop" && repeat_existing != 0)
		task_kill(repeat_existing, 15);

	pid_t short_pid = 0;
	pid_t repeat_pid = 0;
	if(mode != "stop")
	{
		short_pid = task("site-tests-short", []() {
			sleep(5);
		});

		repeat_pid = task_repeat("site-tests-repeat", 1.0, []() {
			file_put_contents("/tmp/uce-site-tests-repeat.txt", time_format_utc("%Y-%m-%d %H:%M:%S"));
		}, 4);
	}

	pid_t timeout_pid = 0;
	pid_t unsafe_key_pid = 0;
	if(mode != "stop")
	{
		timeout_pid = task("site-tests-timeout", []() {
			sleep(5);
		}, 1);
		unsafe_key_pid = task("site-tests/../unsafe key", []() {
			sleep(5);
		});
		sleep(2);
	}

	pid_t seen_short_pid = task_pid("site-tests-short");
	pid_t seen_repeat_pid = task_pid("site-tests-repeat");
	pid_t seen_timeout_pid = task_pid("site-tests-timeout");
	pid_t seen_unsafe_key_pid = task_pid("site-tests/../unsafe key");
	int short_alive = seen_short_pid == 0 ? -1 : task_kill(seen_short_pid, 0);
	int repeat_alive = seen_repeat_pid == 0 ? -1 : task_kill(seen_repeat_pid, 0);

	site_tests_page_start("Tasks", "Local-only checks for one-shot and repeating background task helpers.");

	if(mode == "stop")
	{
		site_tests_case("repeat worker stop request", "skip", "stop mode requested; no new tasks were started on this request");
		skipped++;
	}
	else
	{
		check("task()", short_pid != 0 && seen_short_pid != 0, "started=" + std::to_string(short_pid) + " seen=" + std::to_string(seen_short_pid));
		check("task_pid() + task_kill(pid, 0)", short_alive == 0, "kill(0) result=" + std::to_string(short_alive));
		check("task_repeat()", repeat_pid != 0 && seen_repeat_pid != 0, "started=" + std::to_string(repeat_pid) + " seen=" + std::to_string(seen_repeat_pid));
		check("repeat worker liveness", repeat_alive == 0, "kill(0) result=" + std::to_string(repeat_alive));
		check("task() timeout", timeout_pid != 0 && seen_timeout_pid == 0, "started=" + std::to_string(timeout_pid) + " seen_after_timeout=" + std::to_string(seen_timeout_pid));
		check("task key normalization", unsafe_key_pid != 0 && seen_unsafe_key_pid != 0, "started=" + std::to_string(unsafe_key_pid) + " seen=" + std::to_string(seen_unsafe_key_pid));
		check("task_kill() rejects negative pid", task_kill(-1, 0) == -1, "kill(-1, 0) rejected");
	}

	?><div class="tests-section">
		<a class="button" href="?">Run Task Checks</a>
		<a class="button" href="?mode=stop">Stop Repeat Worker</a>
	</div><?

	site_tests_summary(passed, failed, skipped, "The repeat worker writes its heartbeat to /tmp/uce-site-tests-repeat.txt and is bounded by a short timeout.");
	site_tests_page_end();
}