import { spawn } from 'child_process'

export interface Options {
	args?: string[]
	env?: Record<string, string | undefined>
	cwd?: string

	onData?(data: Buffer): void
}

export async function spawnProcess(
	command: string,
	{ args = [], env, cwd, onData }: Options,
) {
	const nodePty = tryNodePty()

	if (nodePty) {
		const child = nodePty.spawn(
			'bash',
			['-c', `${command} $@`, '--', ...args],
			{
				name: 'xterm-256color',
				cols: 120,
				rows: 60,
				env: env as Record<string, string>,
				cwd,
			},
		)

		if (onData) {
			child.onData((string) => onData(Buffer.from(string)))
		}

		return new Promise<number>((resolve) =>
			child.onExit(({ exitCode }) => resolve(exitCode)),
		)
	} else {
		let shell = true

		if (process.platform === 'win32') {
			shell = false
			args = ['-c', `${command} $@`, '--', ...args]
			command = 'C:/Program Files/Git/bin/bash.exe'
		}

		const child = spawn(command, args, { cwd, env, shell })

		if (onData) {
			child.stdout.on('data', onData)
			child.stderr.on('data', onData)
		}

		return new Promise<number | null>((resolve, reject) =>
			child.once('close', resolve).once('error', reject),
		)
	}
}

function tryNodePty() {
	try {
		return require('node-pty') as typeof import('node-pty')
	} catch {
		return null
	}
}
