/* eslint-disable @typescript-eslint/no-explicit-any */
/*---------------------------------------------------------
 * Copyright (C) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See LICENSE in the project root for license information.
 *--------------------------------------------------------*/
'use strict';

import path = require('path');
import vscode = require('vscode');
import { isModSupported } from './goModules';
import {
	extractInstanceTestName,
	findAllTestSuiteRuns,
	getBenchmarkFunctions,
	getTestFlags,
	getTestFunctionDebugArgs,
	getTestFunctions,
	getTestTags,
	goTest,
	TestConfig
} from './testUtils';

// lastTestConfig holds a reference to the last executed TestConfig which allows
// the last test to be easily re-executed.
let lastTestConfig: TestConfig;

// lastDebugConfig holds a reference to the last executed DebugConfiguration which allows
// the last test to be easily re-executed and debugged.
let lastDebugConfig: vscode.DebugConfiguration;
let lastDebugWorkspaceFolder: vscode.WorkspaceFolder;

export type TestAtCursorCmd = 'debug' | 'test' | 'benchmark';

class NotFoundError extends Error {}

async function _testAtCursor(goConfig: vscode.WorkspaceConfiguration, cmd: TestAtCursorCmd, args: any) {
	const editor = vscode.window.activeTextEditor;
	if (!editor) {
		throw new NotFoundError('No editor is active.');
	}
	if (!editor.document.fileName.endsWith('_test.go')) {
		throw new NotFoundError('No tests found. Current file is not a test file.');
	}

	const getFunctions = cmd === 'benchmark' ? getBenchmarkFunctions : getTestFunctions;
	const testFunctions = await getFunctions(editor.document, null);
	// We use functionName if it was provided as argument
	// Otherwise find any test function containing the cursor.
	const testFunctionName =
		args && args.functionName
			? args.functionName
			: testFunctions.filter((func) => func.range.contains(editor.selection.start)).map((el) => el.name)[0];
	if (!testFunctionName) {
		throw new NotFoundError('No test function found at cursor.');
	}

	await editor.document.save();

	if (cmd === 'debug') {
		return debugTestAtCursor(editor, testFunctionName, testFunctions, goConfig);
	} else if (cmd === 'benchmark' || cmd === 'test') {
		return runTestAtCursor(editor, testFunctionName, testFunctions, goConfig, cmd, args);
	} else {
		throw new Error(`Unsupported command: ${cmd}`);
	}
}

/**
 * Executes the unit test at the primary cursor using `go test`. Output
 * is sent to the 'Go' channel.
 * @param goConfig Configuration for the Go extension.
 * @param cmd Whether the command is test, benchmark, or debug.
 * @param args
 */
export function testAtCursor(goConfig: vscode.WorkspaceConfiguration, cmd: TestAtCursorCmd, args: any) {
	_testAtCursor(goConfig, cmd, args).catch((err) => {
		if (err instanceof NotFoundError) {
			vscode.window.showInformationMessage(err.message);
		} else {
			console.error(err);
		}
	});
}

/**
 * Executes the unit test at the primary cursor if found, otherwise re-runs the previous test.
 * @param goConfig Configuration for the Go extension.
 * @param cmd Whether the command is test, benchmark, or debug.
 * @param args
 */
export async function testAtCursorOrPrevious(goConfig: vscode.WorkspaceConfiguration, cmd: TestAtCursorCmd, args: any) {
	try {
		await _testAtCursor(goConfig, cmd, args);
	} catch (err) {
		if (err instanceof NotFoundError) {
			const editor = vscode.window.activeTextEditor;
			if (editor) {
				await editor.document.save();
			}
			await testPrevious();
		} else {
			console.error(err);
		}
	}
}

/**
 * Runs the test at cursor.
 */
async function runTestAtCursor(
	editor: vscode.TextEditor,
	testFunctionName: string,
	testFunctions: vscode.DocumentSymbol[],
	goConfig: vscode.WorkspaceConfiguration,
	cmd: TestAtCursorCmd,
	args: any
) {
	const testConfigFns = [testFunctionName];
	if (cmd !== 'benchmark' && extractInstanceTestName(testFunctionName)) {
		testConfigFns.push(...findAllTestSuiteRuns(editor.document, testFunctions).map((t) => t.name));
	}

	const isMod = await isModSupported(editor.document.uri);
	const testConfig: TestConfig = {
		goConfig,
		dir: path.dirname(editor.document.fileName),
		flags: getTestFlags(goConfig, args),
		functions: testConfigFns,
		isBenchmark: cmd === 'benchmark',
		isMod,
		applyCodeCoverage: goConfig.get<boolean>('coverOnSingleTest')
	};
	// Remember this config as the last executed test.
	lastTestConfig = testConfig;
	return goTest(testConfig);
}

/**
 * Executes the sub unit test at the primary cursor using `go test`. Output
 * is sent to the 'Go' channel.
 *
 * @param goConfig Configuration for the Go extension.
 */
export async function subTestAtCursor(goConfig: vscode.WorkspaceConfiguration, args: any) {
	const editor = vscode.window.activeTextEditor;
	if (!editor) {
		vscode.window.showInformationMessage('No editor is active.');
		return;
	}
	if (!editor.document.fileName.endsWith('_test.go')) {
		vscode.window.showInformationMessage('No tests found. Current file is not a test file.');
		return;
	}

	await editor.document.save();
	try {
		const testFunctions = await getTestFunctions(editor.document, null);
		// We use functionName if it was provided as argument
		// Otherwise find any test function containing the cursor.
		const currentTestFunctions = testFunctions.filter((func) => func.range.contains(editor.selection.start));
		const testFunctionName =
			args && args.functionName ? args.functionName : currentTestFunctions.map((el) => el.name)[0];

		if (!testFunctionName || currentTestFunctions.length === 0) {
			vscode.window.showInformationMessage('No test function found at cursor.');
			return;
		}

		const testFunction = currentTestFunctions[0];
		const simpleRunRegex = /t.Run\("([^"]+)",/;
		const runRegex = /t.Run\(/;
		let lineText: string;
		let runMatch: RegExpMatchArray | null;
		let simpleMatch: RegExpMatchArray | null;
		for (let i = editor.selection.start.line; i >= testFunction.range.start.line; i--) {
			lineText = editor.document.lineAt(i).text;
			simpleMatch = lineText.match(simpleRunRegex);
			runMatch = lineText.match(runRegex);
			if (simpleMatch || (runMatch && !simpleMatch)) {
				break;
			}
		}

		let subtest: string;
		if (!simpleMatch) {
			const input = await vscode.window.showInputBox({
				prompt: 'Enter sub test name'
			});
			if (input) {
				subtest = input;
			} else {
				vscode.window.showInformationMessage('No subtest function with a simple subtest name found at cursor.');
				return;
			}
		} else {
			subtest = simpleMatch[1];
		}

		const subTestName = testFunctionName + '/' + subtest;

		return await runTestAtCursor(editor, subTestName, testFunctions, goConfig, 'test', args);
	} catch (err) {
		vscode.window.showInformationMessage('Unable to run subtest: ' + err.toString());
		console.error(err);
	}
}

/**
 * Debugs the test at cursor.
 * @param editorOrDocument The text document (or editor) that defines the test.
 * @param testFunctionName The name of the test function.
 * @param testFunctions All test function symbols defined by the document.
 * @param goConfig Go configuration, i.e. flags, tags, environment, etc.
 * @param sessionID If specified, `sessionID` is added to the debug
 * configuration and can be used to identify the debug session.
 * @returns Whether the debug session was successfully started.
 */
export async function debugTestAtCursor(
	editorOrDocument: vscode.TextEditor | vscode.TextDocument,
	testFunctionName: string,
	testFunctions: vscode.DocumentSymbol[],
	goConfig: vscode.WorkspaceConfiguration,
	sessionID?: string
) {
	const doc = 'document' in editorOrDocument ? editorOrDocument.document : editorOrDocument;
	const args = getTestFunctionDebugArgs(doc, testFunctionName, testFunctions);
	const tags = getTestTags(goConfig);
	const buildFlags = tags ? ['-tags', tags] : [];
	const flagsFromConfig = getTestFlags(goConfig);
	let foundArgsFlag = false;
	flagsFromConfig.forEach((x) => {
		if (foundArgsFlag) {
			args.push(x);
			return;
		}
		if (x === '-args') {
			foundArgsFlag = true;
			return;
		}
		buildFlags.push(x);
	});
	const workspaceFolder = vscode.workspace.getWorkspaceFolder(doc.uri);
	const debugConfig: vscode.DebugConfiguration = {
		name: 'Debug Test',
		type: 'go',
		request: 'launch',
		mode: 'test',
		program: path.dirname(doc.fileName),
		env: goConfig.get('testEnvVars', {}),
		envFile: goConfig.get('testEnvFile'),
		args,
		buildFlags: buildFlags.join(' '),
		sessionID
	};
	lastDebugConfig = debugConfig;
	lastDebugWorkspaceFolder = workspaceFolder;
	return await vscode.debug.startDebugging(workspaceFolder, debugConfig);
}

/**
 * Runs all tests in the package of the source of the active editor.
 *
 * @param goConfig Configuration for the Go extension.
 */
export async function testCurrentPackage(goConfig: vscode.WorkspaceConfiguration, isBenchmark: boolean, args: any) {
	const editor = vscode.window.activeTextEditor;
	if (!editor) {
		vscode.window.showInformationMessage('No editor is active.');
		return;
	}

	const isMod = await isModSupported(editor.document.uri);
	const testConfig: TestConfig = {
		goConfig,
		dir: path.dirname(editor.document.fileName),
		flags: getTestFlags(goConfig, args),
		isBenchmark,
		isMod,
		applyCodeCoverage: goConfig.get<boolean>('coverOnTestPackage')
	};
	// Remember this config as the last executed test.
	lastTestConfig = testConfig;
	return goTest(testConfig);
}

/**
 * Runs all tests from all directories in the workspace.
 *
 * @param goConfig Configuration for the Go extension.
 */
export function testWorkspace(goConfig: vscode.WorkspaceConfiguration, args: any) {
	if (!vscode.workspace.workspaceFolders.length) {
		vscode.window.showInformationMessage('No workspace is open to run tests.');
		return;
	}
	let workspaceUri = vscode.workspace.workspaceFolders[0].uri;
	if (
		vscode.window.activeTextEditor &&
		vscode.workspace.getWorkspaceFolder(vscode.window.activeTextEditor.document.uri)
	) {
		workspaceUri = vscode.workspace.getWorkspaceFolder(vscode.window.activeTextEditor.document.uri).uri;
	}

	const testConfig: TestConfig = {
		goConfig,
		dir: workspaceUri.fsPath,
		flags: getTestFlags(goConfig, args),
		includeSubDirectories: true
	};
	// Remember this config as the last executed test.
	lastTestConfig = testConfig;

	isModSupported(workspaceUri, true).then((isMod) => {
		testConfig.isMod = isMod;
		goTest(testConfig).then(null, (err) => {
			console.error(err);
		});
	});
}

/**
 * Runs all tests in the source of the active editor.
 *
 * @param goConfig Configuration for the Go extension.
 * @param isBenchmark Boolean flag indicating if these are benchmark tests or not.
 */
export async function testCurrentFile(
	goConfig: vscode.WorkspaceConfiguration,
	isBenchmark: boolean,
	args: string[]
): Promise<boolean> {
	const editor = vscode.window.activeTextEditor;
	if (!editor) {
		vscode.window.showInformationMessage('No editor is active.');
		return;
	}
	if (!editor.document.fileName.endsWith('_test.go')) {
		vscode.window.showInformationMessage('No tests found. Current file is not a test file.');
		return;
	}

	const getFunctions = isBenchmark ? getBenchmarkFunctions : getTestFunctions;
	const isMod = await isModSupported(editor.document.uri);

	return editor.document
		.save()
		.then(() => {
			return getFunctions(editor.document, null).then((testFunctions) => {
				const testConfig: TestConfig = {
					goConfig,
					dir: path.dirname(editor.document.fileName),
					flags: getTestFlags(goConfig, args),
					functions: testFunctions.map((sym) => sym.name),
					isBenchmark,
					isMod,
					applyCodeCoverage: goConfig.get<boolean>('coverOnSingleTestFile')
				};
				// Remember this config as the last executed test.
				lastTestConfig = testConfig;
				return goTest(testConfig);
			});
		})
		.then(null, (err) => {
			console.error(err);
			return Promise.resolve(false);
		});
}

/**
 * Runs the previously executed test.
 */
export function testPrevious() {
	if (!lastTestConfig) {
		vscode.window.showInformationMessage('No test has been recently executed.');
		return;
	}
	goTest(lastTestConfig).then(null, (err) => {
		console.error(err);
	});
}

/**
 * Runs the previously executed test.
 */
export function debugPrevious() {
	if (!lastDebugConfig) {
		vscode.window.showInformationMessage('No test has been recently debugged.');
		return;
	}
	return vscode.debug.startDebugging(lastDebugWorkspaceFolder, lastDebugConfig);
}
