import { vars } from '@heroku-cli/command';
import cp from 'node:child_process';
import { ux } from '@oclif/core/ux';
import fs from 'fs';
import { promisify } from 'node:util';
const execFile = promisify(cp.execFile);
import debug from 'debug';
const gitDebug = debug('git');
export default class Git {
    async exec(args) {
        gitDebug('exec: git %o', args);
        try {
            const { stdout, stderr } = await execFile('git', args);
            if (stderr)
                process.stderr.write(stderr);
            return stdout.trim();
        }
        catch (error) {
            if (error.code === 'ENOENT') {
                ux.error('Git must be installed to use the Heroku CLI.  See instructions here: https://git-scm.com');
            }
            throw error;
        }
    }
    spawn(args) {
        return new Promise((resolve, reject) => {
            gitDebug('spawn: git %o', args);
            const s = cp.spawn('git', args, { stdio: [0, 1, 2] });
            s.on('error', (err) => {
                if (err.code === 'ENOENT') {
                    ux.error('Git must be installed to use the Heroku CLI.  See instructions here: https://git-scm.com');
                }
                else
                    reject(err);
            });
            s.on('close', resolve);
        });
    }
    remoteFromGitConfig() {
        return this.exec(['config', 'heroku.remote']).catch(() => { });
    }
    httpGitUrl(app) {
        return `https://${vars.httpGitHost}/${app}.git`;
    }
    async remoteUrl(name) {
        const remotes = await this.exec(['remote', '-v']);
        return remotes.split('\n')
            .map(r => r.split('\t'))
            .find(r => r[0] === name)?.[1]
            ?.split(' ')[0] ?? '';
    }
    url(app) {
        return this.httpGitUrl(app);
    }
    async getBranch(symbolicRef) {
        return this.exec(['symbolic-ref', '--short', symbolicRef]);
    }
    async getRef(branch) {
        return this.exec(['rev-parse', branch || 'HEAD']);
    }
    async getCommitTitle(ref) {
        return this.exec(['log', ref || '', '-1', '--pretty=format:%s']);
    }
    async readCommit(commit) {
        const branch = await this.getBranch('HEAD');
        const ref = await this.getRef(commit);
        const message = await this.getCommitTitle(ref);
        return {
            branch,
            message,
            ref,
        };
    }
    inGitRepo() {
        try {
            fs.lstatSync('.git');
            return true;
        }
        catch (error) {
            if (error.code !== 'ENOENT')
                throw error;
        }
    }
    hasGitRemote(remote) {
        return this.remoteUrl(remote)
            // eslint-disable-next-line unicorn/prefer-native-coercion-functions
            .then((remote) => Boolean(remote));
    }
    createRemote(remote, url) {
        return this.hasGitRemote(remote)
            .then(exists => exists ? null : this.exec(['remote', 'add', remote, url]));
    }
}
