import { execFile } from 'child_process';
import * as path from 'path';
import { promisify } from 'util';

const execFileAsync = promisify(execFile);
const MAX_PROCESS_NAMES = 512;

export async function listRunningProcessNames(): Promise<string[]> {
  if (process.platform === 'win32') {
    return normalizeProcessNames(await listWindowsProcessNames());
  }

  if (process.platform === 'linux') {
    return normalizeProcessNames(await listLinuxProcessNames());
  }

  return [];
}

async function listLinuxProcessNames(): Promise<string[]> {
  const { stdout } = await execFileAsync('ps', ['-eo', 'comm='], {
    maxBuffer: 1024 * 1024,
    timeout: 5_000
  });

  return stdout.split('\n');
}

async function listWindowsProcessNames(): Promise<string[]> {
  const { stdout } = await execFileAsync('tasklist', [
    '/FO',
    'CSV',
    '/NH'
  ], {
    maxBuffer: 1024 * 1024,
    timeout: 5_000,
    windowsHide: true
  });

  return stdout
    .split(/\r?\n/)
    .map((line) => parseCsvFirstColumn(line));
}

function parseCsvFirstColumn(line: string): string {
  const trimmed = line.trim();

  if (!trimmed) {
    return '';
  }

  if (!trimmed.startsWith('"')) {
    return trimmed.split(',')[0] ?? '';
  }

  const endQuoteIndex = trimmed.indexOf('"', 1);

  return endQuoteIndex > 1 ? trimmed.slice(1, endQuoteIndex) : '';
}

function normalizeProcessNames(names: string[]): string[] {
  const normalized = new Set<string>();

  for (const rawName of names) {
    const name = normalizeProcessName(rawName);

    if (name) {
      normalized.add(name);
    }
  }

  return Array.from(normalized)
    .sort()
    .slice(0, MAX_PROCESS_NAMES);
}

function normalizeProcessName(rawName: string): string {
  const baseName = path.basename(rawName.trim()).trim();

  if (!baseName || baseName.length > 96) {
    return '';
  }

  return baseName;
}
