/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable no-async-promise-executor */
/*---------------------------------------------------------
 * Copyright 2021 The Go Authors. All rights reserved.
 * Licensed under the MIT License. See LICENSE in the project root for license information.
 *--------------------------------------------------------*/

import cp = require('child_process');
import { QuickPickItem } from 'vscode';
import { getBinPath } from './util';
import { lsofDarwinCommand, parseLsofProcesses } from './utils/lsofProcessParser';
import { envPath, getCurrentGoRoot } from './utils/pathUtils';
import { parsePsProcesses, psDarwinCommand, psLinuxCommand } from './utils/psProcessParser';
import { parseWmicProcesses, wmicCommand } from './utils/wmicProcessParser';
import vscode = require('vscode');

export async function pickProcess(): Promise<string> {
	const allProcesses = await getAllProcesses();
	const id = await processPicker(allProcesses);
	return id;
}

export async function pickProcessByName(name: string): Promise<string> {
	const allProcesses = await getAllProcesses();
	const matches = allProcesses.filter((item) => item.processName === name);
	if (matches.length === 1) {
		return matches[0].id;
	}
	const id = await processPicker(allProcesses, name);
	return id;
}

export async function pickGoProcess(): Promise<string> {
	const allProcesses = await getGoProcesses();
	const id = await processPicker(allProcesses);
	return id;
}

async function processPicker(processes: AttachItem[], name?: string): Promise<string> {
	return new Promise<string>(async (resolve, reject) => {
		const menu = vscode.window.createQuickPick<AttachItem>();
		if (name) {
			menu.value = name;
		}
		menu.items = processes;
		menu.placeholder = 'Choose a process to attach to';
		menu.matchOnDescription = true;
		menu.matchOnDetail = true;

		menu.onDidAccept(() => {
			if (menu.selectedItems.length !== 1) {
				reject(new Error('No process selected.'));
			}
			const selectedId = menu.selectedItems[0].id;

			menu.dispose();

			resolve(selectedId);
		});

		menu.show();
	});
}

// Modified from:
// https://github.com/microsoft/vscode-python/blob/main/src/client/debugger/extension/attachQuickPick/provider.ts
// - This extension adds a function for identifying the Go processes (getGoProcesses)
export interface AttachItem extends QuickPickItem {
	id: string;
	processName?: string;
	commandLine?: string;
	isGo?: boolean;
	executable?: string;
}

export interface ProcessListCommand {
	command: string;
	args: string[];
}

async function getGoProcesses(): Promise<AttachItem[]> {
	const processes = await getAllProcesses();
	if (process.platform === 'darwin') {
		// The executable paths are not set for darwin.
		// It appears there is no standard way to get the executable
		// path for a running process on darwin os. This implementation
		// may not work for all processes.
		const lsofOutput = await runCommand(lsofDarwinCommand);
		if (lsofOutput.err) {
			// We weren't able to run lsof, return all processes found.
			return processes;
		}
		const darwinExes = parseLsofProcesses(lsofOutput.stdout);
		// Merge the executable path to the processes obtained using ps.
		mergeExecutableAttachItem(processes, darwinExes);
	}

	// Run 'go version' on all executable paths to find 'go' processes
	const goRuntimePath = getBinPath('go');
	if (!goRuntimePath) {
		vscode.window.showErrorMessage(
			`Failed to run "go version" as the "go" binary cannot be found in either GOROOT(${getCurrentGoRoot()}) or PATH(${envPath})`
		);
		return processes;
	}
	const args = ['version'];
	processes.forEach((item) => {
		if (item.executable?.length > 0) {
			args.push(item.executable);
		}
	});

	const { stdout } = await runCommand({ command: goRuntimePath, args });

	// Parse the executable paths from stdout. Ignore stderr, since we expect many to fail.
	const goProcessExecutables: string[] = parseGoVersionOutput(stdout);

	const goProcesses: AttachItem[] = [];
	processes.forEach((item) => {
		if (goProcessExecutables.indexOf(item.executable) >= 0) {
			item.isGo = true;
			goProcesses.push(item);
		}
	});

	return goProcesses;
}

export function parseGoVersionOutput(stdout: string): string[] {
	const goProcessExes: string[] = [];
	const goVersionRegexp = /: go\d+.\d+.\d+$/;

	const lines = stdout.toString().split('\n');
	lines.forEach((line) => {
		const match = line.match(goVersionRegexp);
		if (match?.length > 0) {
			const exe = line.substr(0, line.length - match[0].length);
			goProcessExes.push(exe);
		}
	});
	return goProcessExes;
}

export const compareByProcessId = (a: AttachItem, b: AttachItem) => {
	return parseInt(a.id, 10) - parseInt(b.id, 10);
};

export function mergeExecutableAttachItem(processes: AttachItem[], addlAttachItemInfo: AttachItem[]) {
	processes.sort(compareByProcessId);
	addlAttachItemInfo.sort(compareByProcessId);
	let aIdx = 0;
	let pIdx = 0;
	while (aIdx < addlAttachItemInfo.length && pIdx < processes.length) {
		const aAttachItem = addlAttachItemInfo[aIdx];
		const pAttachItem = processes[pIdx];
		if (aAttachItem.id === pAttachItem.id) {
			pAttachItem.executable = aAttachItem.executable;
			aIdx++;
			pIdx++;
			continue;
		}

		if (compareByProcessId(pAttachItem, aAttachItem) > 0) {
			aIdx++;
		} else {
			pIdx++;
		}
	}
}

async function getAllProcesses(): Promise<AttachItem[]> {
	let processCmd: ProcessListCommand;
	switch (process.platform) {
		case 'win32':
			processCmd = wmicCommand;
			break;
		case 'darwin':
			processCmd = psDarwinCommand;
			break;
		case 'linux':
			processCmd = psLinuxCommand;
			break;
		default:
			// Other operating systems are not supported.
			throw new Error(
				`'pickProcess' and 'pickGoProcess' are not supported for ${process.platform}. Set process id in launch.json instead.`
			);
	}

	const { stdout } = await runCommand(processCmd);

	return process.platform === 'win32' ? parseWmicProcesses(stdout) : parsePsProcesses(stdout);
}

async function runCommand(
	processCmd: ProcessListCommand
): Promise<{ err: cp.ExecException; stdout: string; stderr: string }> {
	return await new Promise<{ err: cp.ExecException; stdout: string; stderr: string }>((resolve) => {
		cp.execFile(processCmd.command, processCmd.args, (err, stdout, stderr) => {
			resolve({ err, stdout, stderr });
		});
	});
}
