"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const color_1 = require("@heroku-cli/color");
const command_1 = require("@heroku-cli/command");
const cli_ux_1 = require("cli-ux");
const inquirer_1 = require("inquirer");
const shellescape = require("shell-escape");
const wait_for_domain_1 = require("../../lib/wait-for-domain");
const MULTIPLE_SNI_ENDPOINT_FLAG = 'allow-multiple-sni-endpoints';
class DomainsAdd extends command_1.Command {
    constructor() {
        super(...arguments);
        this.createDomain = async (appName, payload) => {
            cli_ux_1.default.action.start(`Adding ${color_1.color.green(payload.hostname)} to ${color_1.color.app(appName)}`);
            try {
                const response = await this.heroku.post(`/apps/${appName}/domains`, {
                    headers: { Accept: 'application/vnd.heroku+json; version=3.allow_multiple_sni_endpoints' },
                    body: payload,
                });
                return response.body;
            }
            catch (error) {
                // If the error indicates that the app has multiple certs needs the user to specify which one
                // to use, we ask them which cert to use, otherwise we rethrow the error and handle it like usual
                if (error.body.id === 'invalid_params' && error.body.message.includes('sni_endpoint')) {
                    cli_ux_1.default.action.stop('resolving SNI endpoint');
                    const { body: certs } = await this.heroku.get(`/apps/${appName}/sni-endpoints`, {
                        headers: { Accept: 'application/vnd.heroku+json; version=3.allow_multiple_sni_endpoints' },
                    });
                    const certChoices = certs.map((cert) => {
                        const certName = cert.displayName || cert.name;
                        const domainsLength = cert.ssl_cert.cert_domains.length;
                        if (domainsLength) {
                            let domainsList = cert.ssl_cert.cert_domains.slice(0, 4).join(', ');
                            if (domainsLength > 5) {
                                domainsList = `${domainsList} (...and ${domainsLength - 4} more)`;
                            }
                            domainsList = `${certName} -> ${domainsList}`;
                            return {
                                name: domainsList,
                                value: cert.name,
                            };
                        }
                        return {
                            name: certName,
                            value: cert.name,
                        };
                    });
                    const selection = await inquirer_1.prompt([
                        {
                            type: 'list',
                            name: 'cert',
                            message: 'Choose an SNI endpoint to associate with this domain',
                            choices: certChoices,
                        },
                    ]);
                    // eslint-disable-next-line require-atomic-updates
                    payload.sni_endpoint = selection.cert;
                    return this.createDomain(appName, payload);
                }
                throw error;
            }
        };
    }
    async run() {
        const { args, flags } = this.parse(DomainsAdd);
        const { hostname } = args;
        const { body: featureList } = await this.heroku.get(`/apps/${flags.app}/features`);
        const multipleSniEndpointFeature = featureList.find(feature => feature.name === MULTIPLE_SNI_ENDPOINT_FLAG);
        const domainCreatePayload = {
            hostname,
        };
        if (multipleSniEndpointFeature && multipleSniEndpointFeature.enabled) {
            // multiple SNI endpoints is enabled
            if (flags.cert) {
                domainCreatePayload.sni_endpoint = flags.cert;
            }
        }
        try {
            const domain = await this.createDomain(flags.app, domainCreatePayload);
            if (flags.json) {
                cli_ux_1.default.styledJSON(domain);
            }
            else {
                cli_ux_1.default.log(`Configure your app's DNS provider to point to the DNS Target ${color_1.color.green(domain.cname || '')}.
  For help, see https://devcenter.heroku.com/articles/custom-domains`);
                if (domain.status !== 'none') {
                    if (flags.wait) {
                        await wait_for_domain_1.default(flags.app, this.heroku, domain);
                    }
                    else {
                        cli_ux_1.default.log('');
                        cli_ux_1.default.log(`The domain ${color_1.color.green(hostname)} has been enqueued for addition`);
                        const command = `heroku domains:wait ${shellescape([hostname])}`;
                        cli_ux_1.default.log(`Run ${color_1.color.cmd(command)} to wait for completion`);
                    }
                }
            }
        }
        catch (error) {
            cli_ux_1.default.error(error);
        }
        finally {
            cli_ux_1.default.action.stop();
        }
    }
}
exports.default = DomainsAdd;
DomainsAdd.description = 'add a domain to an app';
DomainsAdd.examples = ['heroku domains:add www.example.com'];
DomainsAdd.flags = {
    help: command_1.flags.help({ char: 'h' }),
    app: command_1.flags.app({ required: true }),
    cert: command_1.flags.string({ description: 'the name of the SSL cert you want to use for this domain', char: 'c' }),
    json: command_1.flags.boolean({ description: 'output in json format', char: 'j' }),
    wait: command_1.flags.boolean(),
    remote: command_1.flags.remote(),
};
DomainsAdd.args = [{ name: 'hostname', required: true }];
