import { fileURLToPath } from "node:url";
import { ErrorsPrinter } from "@japa/errors-printer";
import { inspect } from "node:util";
import string from "@poppinss/string";
import timekeeper from "timekeeper";
import useColors from "@poppinss/colors";
import supportsColor from "supports-color";
import { parse } from "error-stack-parser-es";
import { Emitter, Group, Refiner, Runner, Suite, Test, TestContext } from "@japa/core";
import { AssertionError } from "node:assert";
var BaseReporter = class {
	runner;
	currentFileName;
	currentSuiteName;
	currentGroupName;
	options;
	constructor(options = {}) {
		this.options = Object.assign({ stackLinesCount: 2 }, options);
	}
	printAggregates(summary) {
		const tests = [];
		if (summary.aggregates.passed) tests.push(colors.green(`${summary.aggregates.passed} passed`));
		if (summary.aggregates.failed) tests.push(colors.red(`${summary.aggregates.failed} failed`));
		if (summary.aggregates.todo) tests.push(colors.cyan(`${summary.aggregates.todo} todo`));
		if (summary.aggregates.skipped) tests.push(colors.yellow(`${summary.aggregates.skipped} skipped`));
		if (summary.aggregates.regression) tests.push(colors.magenta(`${summary.aggregates.regression} regression`));
		this.runner.summaryBuilder.use(() => {
			return [{
				key: colors.dim("Tests"),
				value: `${tests.join(", ")} ${colors.dim(`(${summary.aggregates.total})`)}`
			}, {
				key: colors.dim("Time"),
				value: colors.dim(string.milliseconds.format(summary.duration))
			}];
		});
		console.log(this.runner.summaryBuilder.build().join("\n"));
	}
	aggregateErrors(summary) {
		const errorsList = [];
		summary.failureTree.forEach((suite) => {
			suite.errors.forEach((error) => errorsList.push({
				title: suite.name,
				...error
			}));
			suite.children.forEach((testOrGroup) => {
				if (testOrGroup.type === "test") {
					testOrGroup.errors.forEach((error) => {
						errorsList.push({
							title: `${suite.name} / ${testOrGroup.title}`,
							...error
						});
					});
					return;
				}
				testOrGroup.errors.forEach((error) => {
					errorsList.push({
						title: testOrGroup.name,
						...error
					});
				});
				testOrGroup.children.forEach((test) => {
					test.errors.forEach((error) => {
						errorsList.push({
							title: `${testOrGroup.name} / ${test.title}`,
							...error
						});
					});
				});
			});
		});
		return errorsList;
	}
	async printErrors(summary) {
		if (!summary.failureTree.length) return;
		const errorPrinter = new ErrorsPrinter({ framesMaxLimit: this.options.framesMaxLimit });
		errorPrinter.printSectionHeader("ERRORS");
		await errorPrinter.printErrors(this.aggregateErrors(summary));
	}
	onTestStart(_) {}
	onTestEnd(_) {}
	onGroupStart(_) {}
	onGroupEnd(_) {}
	onSuiteStart(_) {}
	onSuiteEnd(_) {}
	async start(_) {}
	async end(_) {}
	async printSummary(summary) {
		await this.printErrors(summary);
		console.log("");
		if (summary.aggregates.total === 0 && !summary.hasError) {
			console.log(colors.bgYellow().black(" NO TESTS EXECUTED "));
			return;
		}
		if (summary.hasError) console.log(colors.bgRed().black(" FAILED "));
		else console.log(colors.bgGreen().black(" PASSED "));
		console.log("");
		this.printAggregates(summary);
	}
	boot(runner, emitter) {
		this.runner = runner;
		emitter.on("test:start", (payload) => {
			this.currentFileName = payload.meta.fileName;
			this.onTestStart(payload);
		});
		emitter.on("test:end", (payload) => {
			this.onTestEnd(payload);
		});
		emitter.on("group:start", (payload) => {
			this.currentGroupName = payload.title;
			this.currentFileName = payload.meta.fileName;
			this.onGroupStart(payload);
		});
		emitter.on("group:end", (payload) => {
			this.currentGroupName = void 0;
			this.onGroupEnd(payload);
		});
		emitter.on("suite:start", (payload) => {
			this.currentSuiteName = payload.name;
			this.onSuiteStart(payload);
		});
		emitter.on("suite:end", (payload) => {
			this.currentSuiteName = void 0;
			this.onSuiteEnd(payload);
		});
		emitter.on("runner:start", async (payload) => {
			await this.start(payload);
		});
		emitter.on("runner:end", async (payload) => {
			await this.end(payload);
		});
	}
};
var TestContext$1 = class extends TestContext {
	constructor(test) {
		super();
		this.test = test;
		this.cleanup = (cleanupCallback) => {
			test.cleanup(cleanupCallback);
		};
	}
};
var Test$1 = class extends Test {
	static executedCallbacks = [];
	static executingCallbacks = [];
	throws(message, errorConstructor) {
		const errorInPoint = new AssertionError({});
		const existingExecutor = this.options.executor;
		if (!existingExecutor) throw new Error("Cannot use \"test.throws\" method without a test callback");
		this.options.executor = async (...args) => {
			let raisedException;
			try {
				await existingExecutor(...args);
			} catch (error) {
				raisedException = error;
			}
			if (!raisedException) {
				errorInPoint.message = "Expected test to throw an exception";
				throw errorInPoint;
			}
			if (errorConstructor && !(raisedException instanceof errorConstructor)) {
				errorInPoint.message = `Expected test to throw "${inspect(errorConstructor)}"`;
				throw errorInPoint;
			}
			const exceptionMessage = raisedException.message;
			if (!exceptionMessage || typeof exceptionMessage !== "string") {
				errorInPoint.message = "Expected test to throw an exception with message property";
				throw errorInPoint;
			}
			if (typeof message === "string") {
				if (exceptionMessage !== message) {
					errorInPoint.message = `Expected test to throw "${message}". Instead received "${raisedException.message}"`;
					errorInPoint.actual = raisedException.message;
					errorInPoint.expected = message;
					throw errorInPoint;
				}
				return;
			}
			if (!message.test(exceptionMessage)) {
				errorInPoint.message = `Expected test error to match "${message}" regular expression`;
				throw errorInPoint;
			}
		};
		return this;
	}
};
var Group$1 = class extends Group {};
var Suite$1 = class extends Suite {};
var Runner$1 = class extends Runner {};
const colors = supportsColor.stdout ? useColors.ansi() : useColors.silent();
const icons = process.platform === "win32" && !process.env.WT_SESSION ? {
	tick: "√",
	cross: "×",
	bullet: "*",
	nodejs: "♦",
	pointer: ">",
	info: "i",
	warning: "‼",
	branch: " -",
	squareSmallFilled: "[█]"
} : {
	tick: "✔",
	cross: "✖",
	bullet: "●",
	nodejs: "⬢",
	pointer: "❯",
	info: "ℹ",
	warning: "⚠",
	branch: "└──",
	squareSmallFilled: "◼"
};
function formatPinnedTest(test) {
	let fileName = "";
	let line = 0;
	let column = 0;
	try {
		test.options.meta.abort("Finding pinned test location");
	} catch (error) {
		const frame = parse(error).find((f) => f.fileName && f.lineNumber !== void 0 && f.columnNumber !== void 0 && !f.fileName.includes("node:") && !f.fileName.includes("ext:") && !f.fileName.includes("node_modules/"));
		if (frame) {
			fileName = frame.fileName.startsWith("file:") ? string.toUnixSlash(fileURLToPath(frame.fileName)) : string.toUnixSlash(frame.fileName);
			line = frame.lineNumber;
			column = frame.columnNumber;
		}
	}
	return `${colors.yellow(` ⁃ ${test.title}`)}\n${colors.dim(`   ${fileName}:${line}:${column}`)}`;
}
function printPinnedTests(runner) {
	let pinnedTests = [];
	runner.suites.forEach((suite) => {
		suite.stack.forEach((testOrGroup) => {
			if (testOrGroup instanceof Group$1) testOrGroup.tests.forEach(($test) => {
				if ($test.isPinned) pinnedTests.push(formatPinnedTest($test));
			});
			else if (testOrGroup.isPinned) pinnedTests.push(formatPinnedTest(testOrGroup));
		});
	});
	if (pinnedTests.length) {
		console.log(colors.bgYellow().black(` ${pinnedTests.length} pinned test(s) found `));
		pinnedTests.forEach((row) => console.log(row));
	} else console.log(colors.bgYellow().black(` No pinned tests found `));
}
const dateTimeDoubles = {
	reset() {
		timekeeper.reset();
	},
	travelTo(durationOrDate) {
		if (durationOrDate instanceof Date) timekeeper.travel(durationOrDate);
		else {
			const travelToDate = /* @__PURE__ */ new Date();
			travelToDate.setMilliseconds(travelToDate.getMilliseconds() + string.milliseconds.parse(durationOrDate));
			timekeeper.travel(travelToDate);
		}
	},
	freeze(date) {
		timekeeper.freeze(date);
	}
};
export { Emitter as a, Runner$1 as c, TestContext$1 as d, BaseReporter as f, printPinnedTests as i, Suite$1 as l, dateTimeDoubles as n, Group$1 as o, icons as r, Refiner as s, colors as t, Test$1 as u };
