import { test as base } from "@playwright/test";
import type { Page, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo as PlaywrightTestInfo } from "@playwright/test";
import ITestCase from "@business-logic/types/ITestCase";
import { RuleEngine, ValidationOptions } from "@business-logic/types/RuleEngine";
import TestCase from "@business-logic/types/TestCase";
import Soft from "@business-logic/validations/Soft";
import FakerUtils from "@impl/utils/FakerUtils";
import LoggingUtils from "@impl/utils/LoggingUtils";

export type TestFunction = (args: PlaywrightTestArgs & PlaywrightTestOptions & PlaywrightWorkerArgs & PlaywrightWorkerOptions, testInfo: TestInfo) => void | Promise<void>;
export type TestRunnerFunction = (page: Page, testInfo: TestInfo, /*testCase: TestCase*/) => void | Promise<void>;

export interface TestInfo extends PlaywrightTestInfo {
	testCase: TestCase;
}

export const test = base.extend<{ testInfo: TestInfo; }>({
	// Do not use the fixture because it is not extended, and will cause a circular reference error
	// Use ({}, use, testInfo) not ({ testInfo }, use)
	testInfo: async ({}, use, testInfo) => {
		await use(testInfo as TestInfo);
	}
});

export function addSmokeTagToRandomTest(testCases: ITestCase[]) {
	const index = Math.floor(Math.random() * testCases.length);
	testCases.at(index)?.tags.push("@smoke");
}

export function prepareTest(testData: ITestCase, testRunner: TestRunnerFunction, validationOptions: ValidationOptions, ruleEngine: RuleEngine<TestCase>): [string, object, TestFunction] {
	const name = testData.name;
	const attributes = { tag: TestCase.getTags(testData) };
	const testFunction: TestFunction = ({ page }, testInfo) => {
		// Do not instantiate TestCase outside of this function,
		// otherwise it will be instantiated several times for each test case
		Soft.initialize(testInfo, page);
		testInfo.testCase = new TestCase(testData, validationOptions, FakerUtils.getRandomTestID());
		const results = ruleEngine.validate(testInfo.testCase);
		RuleEngine.PrintValidationResults(results, validationOptions);
        console.log(LoggingUtils.logValidate(`TestID: ${testInfo.testCase.testID}`, true));
		return testRunner(page, testInfo, /*testInfo.testCase*/);
	};
	return [name, attributes, testFunction];
}