/* eslint-disable no-async-promise-executor */
/*---------------------------------------------------------
 * Copyright (C) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------*/

import AdmZip = require('adm-zip');
import assert from 'assert';
import * as config from '../../src/config';
import {
	IToolsManager,
	defaultToolsManager,
	inspectGoToolVersion,
	installTools,
	maybeInstallImportantTools
} from '../../src/goInstallTools';
import { Tool, getRequiredTools, getTool, getToolAtVersion } from '../../src/goTools';
import { getBinPath, getGoVersion, GoVersion, rmdirRecursive } from '../../src/util';
import { correctBinname } from '../../src/utils/pathUtils';
import cp = require('child_process');
import fs = require('fs');
import os = require('os');
import path = require('path');
import sinon = require('sinon');
import url = require('url');
import util = require('util');
import vscode = require('vscode');
import { allToolsInformation } from '../../src/goToolsInformation';
import * as goInstallTools from '../../src/goInstallTools';
import * as utilModule from '../../src/util';
import { getGoConfig } from '../../src/config';
import { MockWorkspaceConfiguration } from './mocks/configuration';

interface installationTestCase {
	name: string;
	versions?: string[];
	wantVersion?: string;
}

suite('Installation Tests', function () {
	// Disable timeout when we are running slow tests.
	let timeout = 60000;
	if (shouldRunSlowTests()) {
		timeout = 0;
	}
	this.timeout(timeout);

	let tmpToolsGopath: string;
	let tmpToolsGopath2: string;
	let sandbox: sinon.SinonSandbox;
	let toolsGopath: string;

	setup(() => {
		// Create a temporary directory in which to install tools.
		tmpToolsGopath = fs.mkdtempSync(path.join(os.tmpdir(), 'install-test'));

		// a temporary directory to be used as the second GOPATH element.
		tmpToolsGopath2 = fs.mkdtempSync(path.join(os.tmpdir(), 'install-test2'));

		toolsGopath = tmpToolsGopath + path.delimiter + tmpToolsGopath2;

		sandbox = sinon.createSandbox();
	});

	teardown(async () => {
		sandbox.restore();

		// Clean up the temporary GOPATH. To delete the module cache, run `go clean -modcache`.
		const goRuntimePath = getBinPath('go');
		for (const p of [tmpToolsGopath, tmpToolsGopath2]) {
			const envForTest = Object.assign({}, process.env);
			envForTest['GOPATH'] = p;
			envForTest['GOMODCACHE'] = path.join(p, 'pkg', 'mod');
			const execFile = util.promisify(cp.execFile);
			try {
				await execFile(goRuntimePath, ['clean', '-x', '-modcache'], {
					env: envForTest
				});
				rmdirRecursive(p);
			} catch (e) {
				console.log(`failed to clean module cache directory: ${e}`);
			}
		}
	});

	// runTest actually executes the logic of the test.
	// If withLocalProxy is true, the test does not require internet.
	// If withGOBIN is true, the test will set GOBIN env var.
	// If withGoVersion is set, the test will run assuming the project requires the version.
	// If goForInstall is set, the test will use the go version for 'go install'.
	// If toolsManager is set, goInstallTools will use it instead of the default tools Manager.
	async function runTest(
		testCases: installationTestCase[],
		withLocalProxy?: boolean,
		withGOBIN?: boolean,
		withGoVersion?: string,
		goVersionForInstall?: GoVersion,
		toolsManager?: goInstallTools.IToolsManager
	) {
		const gobin = withLocalProxy && withGOBIN ? path.join(tmpToolsGopath, 'gobin') : undefined;

		let proxyDir: string | undefined;
		let configStub: sinon.SinonStub;
		if (withLocalProxy) {
			proxyDir = buildFakeProxy(testCases);
			const goConfig = Object.create(vscode.workspace.getConfiguration('go'), {
				toolsEnvVars: {
					value: {
						GOPROXY: url.pathToFileURL(proxyDir),
						GOSUMDB: 'off',
						GOBIN: gobin,
						// Build environment may have GOMODCACHE set. Avoid writing
						// fake data to it.
						GOMODCACHE: path.join(tmpToolsGopath, 'pkg', 'mod')
					}
				},
				gopath: { value: toolsGopath }
			});
			configStub = sandbox.stub(config, 'getGoConfig').returns(goConfig);
		} else {
			const goConfig = Object.create(vscode.workspace.getConfiguration('go'), {
				toolsEnvVars: {
					value: { GOBIN: gobin }
				},
				gopath: { value: toolsGopath }
			});
			configStub = sandbox.stub(config, 'getGoConfig').returns(goConfig);
		}

		const missingTools = testCases.map((tc) => getToolAtVersion(tc.name));
		const goBinary = getBinPath('go');
		const goVersion = withGoVersion
			? /* we want a fake go version, but need the real 'go' binary to run `go install` */
				new GoVersion(goBinary, `go version ${withGoVersion} linux/amd64`)
			: await getGoVersion();

		sandbox.stub(vscode.commands, 'executeCommand').withArgs('go.languageserver.restart');
		sandbox
			.stub(goInstallTools, 'getGoVersionForInstall')
			.returns(Promise.resolve(goVersionForInstall ?? goVersion));

		const opts = toolsManager ? { toolsManager } : undefined;
		const failures = await installTools(missingTools, goVersion, opts);
		assert(!failures || failures.length === 0, `installTools failed: ${JSON.stringify(failures)}`);

		// Confirm that each expected tool has been installed.
		const checks: Promise<void>[] = [];
		const exists = util.promisify(fs.exists);
		for (const tc of testCases) {
			checks.push(
				new Promise<void>(async (resolve) => {
					// Check that the expect tool has been installed to $GOPATH/bin.
					const bin = gobin
						? path.join(gobin, correctBinname(tc.name))
						: path.join(tmpToolsGopath, 'bin', correctBinname(tc.name));
					const ok = await exists(bin);
					if (!ok) {
						assert.fail(`expected ${bin}, not found`);
					}
					// If wantVersion is set, check if wanted version was installed.
					if (tc.wantVersion !== undefined) {
						const { moduleVersion } = await inspectGoToolVersion(bin);
						assert.strictEqual(
							moduleVersion,
							tc.wantVersion,
							`expected ${tc.name}@${tc.wantVersion}, got ${moduleVersion}`
						);
					}
					return resolve();
				})
			);
		}
		await Promise.all(checks);

		if (withLocalProxy) {
			sandbox.assert.calledWith(configStub);
			// proxyDir should be set when withLocalProxy = true
			assert(proxyDir);
			rmdirRecursive(proxyDir);
		}
	}

	test('Install one tool with a local proxy', async function () {
		// TODO(golang/vscode-go#3454): reenable the test for old go.
		const systemGoVersion = await getGoVersion();
		if (systemGoVersion.lt('1.21')) {
			this.skip();
		}
		await runTest(
			[
				{
					name: 'gopls',
					versions: ['v0.1.0', 'v1.0.0', 'v1.0.1-pre.2'],
					wantVersion: config.extensionInfo.isPreview ? 'v1.0.1-pre.2' : 'v1.0.0'
				}
			],
			true
		);
	});

	test('Install multiple tools with a local proxy', async function () {
		// TODO(golang/vscode-go#3454): reenable the test for old go.
		const systemGoVersion = await getGoVersion();
		if (systemGoVersion.lt('1.21')) {
			this.skip();
		}
		await runTest(
			[
				{ name: 'gopls', versions: ['v0.1.0', 'v1.0.0-pre.1', 'v1.0.0'], wantVersion: 'v1.0.0' },
				{ name: 'dlv', versions: ['v1.0.0', 'v1.8.0'], wantVersion: 'v1.8.0' }
			],
			true
		);
	});

	test('Install multiple tools with a local proxy & GOBIN', async function () {
		// TODO(golang/vscode-go#3454): reenable the test for old go.
		const systemGoVersion = await getGoVersion();
		if (systemGoVersion.lt('1.21')) {
			this.skip();
		}
		await runTest(
			[
				{ name: 'gopls', versions: ['v0.1.0', 'v1.0.0-pre.1', 'v1.0.0'], wantVersion: 'v1.0.0' },
				{ name: 'dlv', versions: ['v1.0.0', 'v1.8.0'], wantVersion: 'v1.8.0' }
			],
			true, // LOCAL PROXY
			true // GOBIN
		);
	});

	test('Try to install with old go', async () => {
		const oldGo = new GoVersion(getBinPath('go'), 'go version go1.20 amd64/linux');
		sandbox.stub(goInstallTools, 'getGoVersionForInstall').returns(Promise.resolve(oldGo));
		const failures = await installTools([getToolAtVersion('gopls')], oldGo);
		assert(failures?.length === 1 && failures[0].tool.name === 'gopls' && failures[0].reason.includes('or newer'));
	});

	const gofumptDefault = allToolsInformation.get('gofumpt')!.defaultVersion!;
	test('Install gofumpt with old go', async () => {
		await runTest(
			[{ name: 'gofumpt', versions: ['v0.5.0', 'v0.6.0', gofumptDefault], wantVersion: 'v0.6.0' }],
			true, // LOCAL PROXY
			true, // GOBIN
			'go1.21' // Go Version
		);
	});
	test('Install gofumpt with new go', async () => {
		await runTest(
			[{ name: 'gofumpt', versions: ['v0.4.7', 'v0.5.0', gofumptDefault], wantVersion: gofumptDefault }],
			true, // LOCAL PROXY
			true, // GOBIN
			'go1.25' // Go Version
		);
	});

	test('Install a tool, with go for install', async () => {
		const systemGoVersion = await getGoVersion();
		const wantGoForInstall = new GoVersion(systemGoVersion.binaryPath, 'go version go1.99.0 linux/amd64');
		const tm: IToolsManager = {
			getMissingTools: () => {
				assert.fail('must not be called');
			},
			installTool: (tool, goVersionForInstall, env) => {
				// Assert the go install command is what we expect.
				assert.strictEqual(tool.name, 'gopls');
				assert.strictEqual(goVersionForInstall, wantGoForInstall);
				assert(env['GOTOOLCHAIN'], `go${systemGoVersion.format()}+auto`);
				// runTest checks if the tool build succeeds. So, delegate the remaining
				// build task to the default tools manager's installTool function.
				return defaultToolsManager.installTool(tool, systemGoVersion, env);
			}
		};
		await runTest(
			[{ name: 'gopls', versions: ['v0.1.0', 'v1.0.0'], wantVersion: 'v1.0.0' }],
			true, // LOCAL PROXY
			true, // GOBIN
			'go' + systemGoVersion.format(true), // Go Version
			wantGoForInstall, // Go for install
			tm // stub installTool to
		);
	});

	test('Install all tools via GOPROXY', async () => {
		// Only run this test if we are in CI before a Nightly release.
		if (!shouldRunSlowTests()) {
			return;
		}
		const goVersion = await getGoVersion();

		const tools: string[] = [];
		for (const [name, info] of allToolsInformation) {
			const minGoVersion = info.minimumGoVersion;
			if (!minGoVersion || goVersion.gt(minGoVersion.format())) {
				tools.push(name);
			}
		}
		assert(tools.includes('gopls') && tools.includes('dlv'), `selected tools ${JSON.stringify(tools)}`);
		await runTest(
			tools.map((tool) => {
				return { name: tool };
			})
		);
	});
});

// buildFakeProxy creates a fake file-based proxy used for testing. The code is
// mostly adapted from golang.org/x/tools/internal/proxydir/proxydir.go.
function buildFakeProxy(testCases: installationTestCase[]) {
	const proxyDir = fs.mkdtempSync(path.join(os.tmpdir(), 'proxydir'));
	for (const tc of testCases) {
		const tool: Tool = getTool(tc.name)!;
		const module = tool.modulePath;
		const pathInModule =
			tool.modulePath === tool.importPath ? '' : tool.importPath.slice(tool.modulePath.length + 1) + '/';
		const versions = tc.versions ?? ['v1.0.0']; // hardcoded for now
		const dir = path.join(proxyDir, module, '@v');
		fs.mkdirSync(dir, { recursive: true });

		// Write the list file.
		fs.writeFileSync(path.join(dir, 'list'), `${versions.join('\n')}\n`);

		versions.map((version) => {
			if (!version.match(/^v\d+\.\d+\.\d+/)) {
				// for tools that retrieve the versions from a revision (commit hash)
				const resolvedVersion = tool.latestVersion?.toString() || '1.0.0';
				const infoPath = path.join(dir, `${version}.info`);
				version = `v${resolvedVersion}`;
				fs.writeFileSync(infoPath, `{ "Version": "${version}", "Time": "2020-04-07T14:45:07Z" } `);
			}

			// Write the go.mod file.
			fs.writeFileSync(path.join(dir, `${version}.mod`), `module ${module}\n`);
			// Write the info file.
			fs.writeFileSync(
				path.join(dir, `${version}.info`),
				`{ "Version": "${version}", "Time": "2020-04-07T14:45:07Z" } `
			);

			// Write the zip file.
			const zip = new AdmZip();
			const content = 'package main; func main() {};';
			zip.addFile(`${module}@${version}/${pathInModule}main.go`, Buffer.alloc(content.length, content));
			zip.writeZip(path.join(dir, `${version}.zip`));
		});
	}
	return proxyDir;
}

// Check if VSCODEGO_BEFORE_RELEASE_TESTS is set to true. This environment
// variable is set by the CI system that releases the Nightly extension,
// allowing us to opt-in to more rigorous testing only before releases.
function shouldRunSlowTests(): boolean {
	return !!process.env['VSCODEGO_BEFORE_RELEASE_TESTS'];
}

suite('getRequiredTools', () => {
	const testCases: {
		name: string;
		goConfig: Map<string, any>;
		expectedTools: string[];
	}[] = [
		{
			name: 'include gopls when {"go.useLanguageServer": true}',
			goConfig: new Map<string, any>([['useLanguageServer', true]]),
			// exclude third party tool that is replaced by gopls
			expectedTools: ['gopls', 'dlv', 'impl', 'goplay']
		},
		{
			name: 'exclude gopls when {"go.useLanguageServer": false}',
			goConfig: new Map<string, any>([['useLanguageServer', false]]),
			expectedTools: [
				'dlv',
				'impl',
				'goplay',
				// include third party tool that is replaced by gopls
				'gotests'
			]
		},
		{
			name: 'include golangci-lint specified in "go.lintTool"',
			goConfig: new Map<string, any>([
				['useLanguageServer', true],
				['lintTool', 'golangci-lint']
			]),
			expectedTools: ['golangci-lint', 'gopls', 'dlv', 'impl', 'goplay']
		}
	];

	for (const tc of testCases) {
		test(tc.name, async () => {
			const configured = getRequiredTools(new MockWorkspaceConfiguration(getGoConfig(), tc.goConfig));
			const got = configured.map((tool) => tool.name) ?? [];
			assert.deepStrictEqual(got.sort(), tc.expectedTools.sort());
		});
	}
});

function fakeGoVersion(versionStr: string) {
	return new GoVersion('/path/to/go', versionStr);
}

suite('listOutdatedTools', () => {
	let sandbox: sinon.SinonSandbox;
	setup(() => {
		sandbox = sinon.createSandbox();
	});
	teardown(() => sandbox.restore());

	// goVersion: go toolchain's version
	// tools: toolname -> go toolchain version used to compile the tool
	async function runTest(goVersion: string | undefined, tools: { [key: string]: string | undefined }) {
		const binPathStub = sandbox.stub(utilModule, 'getBinPath');
		const versionStub = sandbox.stub(goInstallTools, 'inspectGoToolVersion');
		for (const tool in tools) {
			binPathStub.withArgs(tool).returns(`/bin/${tool}`);
			versionStub.withArgs(`/bin/${tool}`).returns(Promise.resolve({ goVersion: tools[tool] }));
		}

		const toolsToCheck = Object.keys(tools).map((tool) => getToolAtVersion(tool));

		const configuredGoVersion = goVersion ? fakeGoVersion(goVersion) : undefined;
		const toolsToUpdate = await goInstallTools.listOutdatedTools(configuredGoVersion, toolsToCheck);
		return toolsToUpdate.map((tool) => tool.name).filter((tool) => !!tool);
	}

	test('minor version difference requires updates', async () => {
		const x = await runTest('go version go1.23.0 linux/amd64', {
			gopls: 'go1.22.2',
			dlv: 'go1.21.0',
			staticcheck: 'go1.23.0',
			gotests: 'go1.24.1'
		});
		assert.deepStrictEqual(x, ['gopls', 'dlv']);
	});
	test('patch version difference does not require updates', async () => {
		const x = await runTest('go version go1.23.1 linux/amd64', {
			gopls: 'go1.23.0', // 1.16 < 1.16.1
			dlv: 'go1.23.1', // 1.16.1 == 1.16.1
			staticcheck: 'go1.23.2', // 1.16.2 > 1.16.1
			gotests: 'go1.23rc1' // go1.23rc1 != go1.23.0
		});
		assert.deepStrictEqual(x, ['gotests']);
	});
	test('go is rc version', async () => {
		const x = await runTest('go version go1.23rc2 linux/amd64', {
			gopls: 'go1.22.3', // go1.22.3 < go1.23rc2
			dlv: 'go1.23rc1', // go1.23rc1 < go1.23rc2
			staticcheck: 'go1.23rc2', // same
			gotests: 'go1.23.0' // go1.23rc2 < go1.23.0
		});
		assert.deepStrictEqual(x, ['gopls', 'dlv']);
	});
	test('go is dev version - skip version check', async () => {
		const x = await runTest('go version devel go1.24-41f485b9a7 linux/amd64', {
			gopls: 'go1.13.1',
			dlv: 'go1.24rc1',
			staticcheck: 'go1.23.0',
			gotests: 'go1.24.0'
		});
		assert.deepStrictEqual(x, []);
	});
	test('go is unknown version - skip version check', async () => {
		const x = await runTest('', {
			gopls: 'go1.23.1'
		});
		assert.deepStrictEqual(x, []);
	});
	test('tools are unknown versions', async () => {
		const x = await runTest('go version go1.22.0 linux/amd64', {
			gopls: undefined, // this can be because gopls was compiled with go1.18 or it's too old.
			dlv: 'go1.20'
		});
		assert.deepStrictEqual(x, ['gopls', 'dlv']);
	});
});

suite('maybeInstallImportantTools tests', () => {
	let sandbox: sinon.SinonSandbox;

	setup(() => {
		sandbox = sinon.createSandbox();
	});

	teardown(async () => sandbox.restore());

	// runTest actually executes the logic of the test using a fake proxy.
	async function runTest(
		toolsManager: goInstallTools.IToolsManager,
		alternateToolsCfg: { [key: string]: string } = {},
		wantMissingTools: string[] = []
	) {
		// maybeInstallImportantTools shouldn't trigger gopls restart.
		// The caller ('activate') will explicitly start it.
		sandbox
			.stub(vscode.commands, 'executeCommand')
			.withArgs('go.languageserver.restart')
			.throws(new Error('gopls shouldn not be restarted'));

		try {
			const statusBarItem = await maybeInstallImportantTools(alternateToolsCfg, toolsManager);
			assert.strictEqual(statusBarItem.busy, false);
			assert.strictEqual(
				statusBarItem.severity,
				wantMissingTools && wantMissingTools.length > 0
					? vscode.LanguageStatusSeverity.Error
					: vscode.LanguageStatusSeverity.Information,
				statusBarItem.text
			);
			if (wantMissingTools && wantMissingTools.length > 0) {
				assert.strictEqual(statusBarItem.command?.title, 'Install missing tools');
				for (const tool of wantMissingTools) {
					assert(statusBarItem.detail!.includes(tool), statusBarItem.detail + ' does not contain ' + tool);
				}
			} else {
				assert.strictEqual(statusBarItem.command?.title, 'Update');
				assert.strictEqual(statusBarItem.detail, 'no missing tools');
			}
		} catch (e) {
			assert.fail(`maybeInstallImportantTools failed: ${e}`);
		}
	}

	test('Successfully install gopls & linter', async () => {
		await runTest(
			mockToolsManager(['gopls', 'staticcheck']),
			{}, // emtpry alternateTools.
			[] // no missing tools after run.
		);
	});

	test('Do not install alternate tools', async () => {
		await runTest(mockToolsManager(['gopls', 'staticcheck']), { gopls: 'fork.example.com/gopls' }, ['gopls']);
	});

	test('Recover when installation fails', async () => {
		const tm = mockToolsManager(['gopls', 'staticcheck']);
		tm.installTool = () => {
			return Promise.resolve('failed');
		};
		await runTest(tm, {}, ['gopls', 'staticcheck']);
	});

	test('Recover when installation crashes', async () => {
		const tm = mockToolsManager(['gopls', 'staticcheck']);
		tm.installTool = () => {
			throw new Error('crash');
		};
		await runTest(tm, {}, ['gopls', 'staticcheck']);
	});

	/**
	 * Creates a mock IToolsManager for testing purposes. Both method can be
	 * overwritten in test to control the manager behavior.
	 *
	 * @param requiredTools An array of tool names that this mock manager
	 * should treat as its universe of known tools for the test.
	 * @returns A mock object that implements the IToolsManager interface.
	 */
	function mockToolsManager(requiredTools: string[] = []) {
		const installed: string[] = [];

		const toolsManager: goInstallTools.IToolsManager = {
			getMissingTools: function (matcher: (tool: Tool) => boolean): Promise<Tool[]> {
				let tools: Tool[] = requiredTools.map((t) => {
					return allToolsInformation.get(t)!;
				});
				// apply user's filter;
				tools = matcher ? tools.filter(matcher) : tools;
				// remove tools that are installed.
				tools = tools.filter((tool) => !installed.includes(tool.name));
				return Promise.resolve(tools);
			},
			installTool: function (tool: Tool): Promise<string | undefined> {
				installed.push(tool.name);
				return Promise.resolve(undefined); // no error.
			}
		};

		return toolsManager;
	}
});
