import { Logger } from '@refloat/logger'
import { spawnProcess } from './spawn'

const logger = Logger.create('exec')

export interface ExecOptions {
	env?: Record<string, string | undefined>
	cwd?: string
	output?(chunk: Buffer): void
	printOutput?: boolean
}

export async function exec(
	command: string,
	args: string[],
	{ env = process.env, cwd, output, printOutput = false }: ExecOptions = {},
) {
	logger.debug('Running command', {
		command: [command, ...args],
		cwd,
		env,
	})

	return spawnProcess(command, {
		args,
		cwd,
		env,
		onData(data: Buffer) {
			output?.(data)

			if (printOutput) {
				process.stdout.write(data.toString())
			}
		},
	})
}

export class ExecError extends Error {
	constructor(public readonly code: number | null, error: any) {
		super(error?.message ?? String(error ?? 'Unknown error'))
	}
}

exec.run = async function execRun(
	command: string,
	args: string[],
	options: ExecOptions = {},
) {
	const chunks: Buffer[] = []
	const code = await exec(command, args, {
		...options,
		output: (chunk) => {
			chunks.push(chunk)
			options.output?.(chunk)
		},
	})

	const output = Buffer.concat(chunks).toString('utf-8')

	if (code === 0) {
		return output
	}

	throw new ExecError(code, output)
}
