import { color, hux } from '@heroku/heroku-cli-util';
import { Command, flags } from '@heroku-cli/command';
import { Args, ux } from '@oclif/core';
import fs from 'fs-extra';
import { spawn } from 'node:child_process';
import os from 'node:os';
import path from 'node:path';
import { lazyModuleLoader } from '../../lib/lazy-module-loader.js';
function sshKeygen(file, quiet) {
    return new Promise((resolve, reject) => {
        spawn('ssh-keygen', ['-o', '-t', 'rsa', '-N', '', '-f', file], { stdio: quiet ? 'ignore' : 'inherit' })
            .on('close', (code) => code === 0 ? resolve(null) : reject(code));
    });
}
export default class Add extends Command {
    static args = {
        key: Args.string({ description: 'absolute path to the key located on disk. If omitted, we use the default rsa key.' }),
    };
    static description = `
    add an SSH key for a user
    if no KEY is specified, will try to find ~/.ssh/id_rsa.pub
  `;
    static example = `
${color.command('heroku keys:add')}
Could not find an existing public key.
Would you like to generate one? [Yn] y
Generating new SSH public key.
Uploading SSH public key /.ssh/id_rsa.pub... done

${color.command('heroku keys:add /my/key.pub')}
Uploading SSH public key /my/key.pub... done`;
    static flags = {
        quiet: flags.boolean({ hidden: true }),
        yes: flags.boolean({ char: 'y', description: 'automatically answer yes for all prompts' }),
    };
    async run() {
        const inquirer = await lazyModuleLoader.loadInquirer();
        const { args, flags } = await this.parse(Add);
        const sshdir = path.join(os.homedir(), '.ssh');
        async function confirmPrompt(message) {
            if (process.stdin.isTTY) {
                return inquirer.prompt([{
                        message,
                        name: 'yes',
                        type: 'confirm',
                    }]);
            }
            const data = await hux.prompt(message + ' [Y/n]');
            return { yes: /^y(es)?/i.test(data) };
        }
        const generate = async function () {
            await fs.ensureDir(sshdir, { mode: 0o700 });
            await sshKeygen(path.join(sshdir, 'id_rsa'), flags.quiet);
        };
        const findKey = async function () {
            const defaultKeyPath = path.join(sshdir, 'id_rsa.pub');
            const defaultKeyExists = await fs.pathExists(defaultKeyPath);
            const keys = (await fs.readdir(sshdir))
                .map(k => path.join(sshdir, k))
                .filter(k => path.extname(k) === '.pub');
            if (!defaultKeyExists && keys.length === 0) {
                ux.warn('Could not find an existing SSH key at ' + path.join('~', '.ssh', 'id_rsa.pub'));
                if (!flags.yes) {
                    const resp = await confirmPrompt('Would you like to generate a new one?');
                    if (!resp.yes)
                        return;
                }
                await generate();
                return defaultKeyPath;
            }
            if (keys.length === 1) {
                const key = keys[0];
                ux.stdout(`Found an SSH public key at ${color.cyan(key)}`);
                if (!flags.yes) {
                    const resp = await confirmPrompt('Would you like to upload it to Heroku?');
                    if (!resp.yes)
                        return;
                }
                return key;
            }
            const resp = await inquirer.prompt([{
                    choices: keys,
                    message: 'Which SSH key would you like to upload?',
                    name: 'key',
                    type: 'list',
                }]);
            return resp.key;
        };
        let { key } = args;
        if (!key)
            key = await findKey();
        if (!key)
            throw new Error('No key to upload');
        ux.action.start(`Uploading ${color.cyan(key)} SSH key`);
        const publicKey = await fs.readFile(key, { encoding: 'utf8' });
        await this.heroku.post('/account/keys', {
            body: {
                public_key: publicKey,
            },
        });
        ux.action.stop();
    }
}
