"use strict";
/*
 * Copyright 2021 NEM
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.networkToPreset = exports.ImportType = exports.Network = exports.assemblies = void 0;
const command_1 = require("@oclif/command");
const fs_1 = require("fs");
const inquirer_1 = require("inquirer");
const symbol_hd_wallets_1 = require("symbol-hd-wallets");
const symbol_sdk_1 = require("symbol-sdk");
const model_1 = require("../model");
const service_1 = require("../service");
exports.assemblies = {
    [service_1.Preset.bootstrap]: [
        { value: '', description: 'Default: A network with 2 peers, a api, a broker, a mongo db, and a Rest Gateway' },
        { value: 'full', description: 'Full: A complete network with a private Explorer, Faucet and Wallet' },
        { value: 'light', description: 'Light: A light network with a dual, a mongo dn and a rest gateway' },
    ],
    [service_1.Preset.mainnet]: [
        { value: 'dual', description: 'Dual Node' },
        { value: 'peer', description: 'Peer Node' },
        { value: 'api', description: 'Api  Node' },
    ],
    [service_1.Preset.testnet]: [
        { value: 'dual', description: 'Dual Node' },
        { value: 'peer', description: 'Peer Node' },
        { value: 'api', description: 'Api  Node' },
    ],
};
var Network;
(function (Network) {
    Network["mainnet"] = "mainnet";
    Network["testnet"] = "testnet";
    Network["privateNetwork"] = "privateNetwork";
})(Network = exports.Network || (exports.Network = {}));
var ImportType;
(function (ImportType) {
    ImportType["PRIVATE_KEYS"] = "privateKeys";
    ImportType["OPTIN_PAPER_WALLET"] = "optinPaperWallet";
    ImportType["SYMBOL_PAPER_WALLET"] = "symbolPaperWallet";
})(ImportType = exports.ImportType || (exports.ImportType = {}));
exports.networkToPreset = {
    [Network.privateNetwork]: service_1.Preset.bootstrap,
    [Network.mainnet]: service_1.Preset.mainnet,
    [Network.testnet]: service_1.Preset.testnet,
};
class Wizard extends command_1.Command {
    async run() {
        const flags = this.parse(Wizard).flags;
        return Wizard.execute(this.config.root, flags);
    }
    static async execute(root, flags) {
        var _a;
        service_1.BootstrapUtils.showBanner();
        console.log('Welcome to the Symbol Bootstrap wizard! This command will:');
        console.log(' - Guide you through the configuration process.');
        console.log(' - Import Paper Wallet seeds.');
        console.log(` - Create a custom preset and show you the way to launch your node!`);
        console.log();
        const target = flags.target;
        const customPresetFile = flags.customPreset;
        if (fs_1.existsSync(customPresetFile)) {
            throw new Error(`${customPresetFile} already exist!!! You should move the file somewhere else before overwriting it!`);
        }
        if (fs_1.existsSync(target)) {
            throw new Error('There is currently a ./target folder here!!!! Have you executed bootstrap already? You should move the folder somewhere else before overwriting it!');
        }
        const network = await Wizard.resolveNetwork(flags.network);
        const preset = exports.networkToPreset[network];
        const assembly = await Wizard.resolveAssembly(preset);
        if (network == Network.privateNetwork) {
            console.log('For a private network, just run: ');
            console.log('');
            console.log(`$ symbol-bootstrap start -b ${preset}${assembly ? ` -a ${assembly}` : ''}`);
            return;
        }
        if (!flags.skipPull) {
            const service = await new service_1.BootstrapService();
            console.log();
            console.log('Pulling catapult tools image before asking to go offline...');
            console.log();
            service_1.ConfigLoader.presetInfoLogged = true;
            await service_1.BootstrapUtils.pullImage(service.resolveConfigPreset(Object.assign(Object.assign({}, service_1.ConfigService.defaultParams), { preset: preset, assembly: assembly, target: target })).symbolServerToolsImage);
        }
        console.log();
        console.log();
        if (!flags.ready &&
            !(await inquirer_1.prompt([
                {
                    name: 'offlineNow',
                    message: `Symbol Bootstrap is about to start working with sensitive information (private keys or mnemonic phrases) so it is highly recommended that you disconnect from the network before continuing. Say YES if you are offline or if you don't care.`,
                    type: 'confirm',
                    default: true,
                },
            ])).offlineNow) {
            console.log('Come back when you are offline...');
            return;
        }
        console.log();
        console.log('Symbol bootstrap needs to provide the node with a number of key pairs (Read more at https://docs.symbolplatform.com/concepts/cryptography.html#symbol-keys).');
        console.log(`If you don't know what a key is used for, let Symbol Bootstrap generate a new one for you.`);
        const password = await service_1.CommandUtils.resolvePassword(flags.password, flags.noPassword, service_1.CommandUtils.passwordPromptDefaultMessage, false);
        const rewardProgram = assembly === 'dual' ? await Wizard.resolveRewardProgram() : undefined;
        const networkType = network === Network.mainnet ? symbol_sdk_1.NetworkType.MAIN_NET : symbol_sdk_1.NetworkType.TEST_NET;
        const accounts = await Wizard.resolveAccounts(networkType, rewardProgram);
        console.log();
        console.log(`These are your node's accounts:`);
        Wizard.logAccount(accounts.main, service_1.KeyName.Main, false);
        Wizard.logAccount(accounts.vrf, service_1.KeyName.VRF, false);
        Wizard.logAccount(accounts.remote, service_1.KeyName.Remote, false);
        Wizard.logAccount(accounts.transport, service_1.KeyName.Transport, false);
        Wizard.logAccount(accounts.agent, service_1.KeyName.Agent, false);
        console.log();
        console.log();
        const symbolHostRequired = !!rewardProgram;
        const host = await Wizard.resolveHost(`Enter the public hostname or IP of your future node. ${symbolHostRequired ? 'This value is required when you are in a reward program!' : ''}`, symbolHostRequired);
        const friendlyName = await Wizard.resolveFriendlyName(host || accounts.main.publicKey.substr(0, 7));
        const privateKeySecurityMode = await Wizard.resolvePrivateKeySecurityMode();
        const voting = await Wizard.isVoting();
        const presetContent = {
            assembly: assembly,
            preset: preset,
            privateKeySecurityMode: privateKeySecurityMode,
            nodes: [
                {
                    host: host,
                    voting: voting,
                    friendlyName: friendlyName,
                    rewardProgram: rewardProgram,
                    mainPrivateKey: accounts.main.privateKey,
                    vrfPrivateKey: accounts.vrf.privateKey,
                    remotePrivateKey: accounts.remote.privateKey,
                    transportPrivateKey: accounts.transport.privateKey,
                    agentPrivateKey: (_a = accounts.agent) === null || _a === void 0 ? void 0 : _a.privateKey,
                },
            ],
        };
        const defaultParams = service_1.ConfigService.defaultParams;
        await service_1.BootstrapUtils.writeYaml(customPresetFile, presetContent, password);
        console.log();
        console.log();
        console.log(`The Symbol Bootstrap preset file '${customPresetFile}' has been created!!!. Keep this safe!`);
        console.log();
        console.log(`To decrypt the node's private key, run: `);
        console.log();
        console.log(`$ symbol-bootstrap decrypt --source ${customPresetFile} --destination plain-custom-preset.yml`);
        console.log();
        console.log('Remember to delete the plain-custom-preset.yml file after used!!!');
        console.log(`You can edit this file to further customize it. Read more https://github.com/nemtech/symbol-bootstrap/blob/main/docs/presetGuides.md`);
        console.log();
        console.log(`Once you have finished the custom preset customization, You can use the 'start' to run the node in this machine:`);
        console.log();
        console.log(`$ symbol-bootstrap start -p ${network} -a ${assembly} -c ${customPresetFile} ${target !== defaultParams.target ? `-t ${target}` : ''}`);
        console.log();
        console.log(`Alternatively, to create a zip file that can be deployed in your node machine you can use the 'pack' command:`);
        console.log();
        console.log(`$ symbol-bootstrap pack -p ${network} -a ${assembly} -c ${customPresetFile} ${target !== defaultParams.target ? `-t ${target}` : ''}`);
        console.log();
        console.log(`Once the target folder is created, Bootstrap will use the protected and encrypted addresses.yml, and preset.yml in inside the target folder.`);
        console.log('To upgrade your node version or configuration, use the --upgrade parameter in config, compose, start and/or pack. Remember to backup the node`s target folder!');
        console.log('Hint: You can change the configuration of an already created node by proving a new custom preset. This is an experimental feature, backup the target folder before!');
        console.log();
        console.log('To complete the registration, you need to link your keys (online):');
        console.log();
        console.log(`$ symbol-bootstrap link --useKnownRestGateways -c ${customPresetFile}`);
        if (rewardProgram == service_1.RewardProgram.SuperNode) {
            console.log();
            console.log('To enroll to the supernode program, run (online):');
            console.log();
            console.log(`$ symbol-bootstrap enrollRewardProgram  --useKnownRestGateways -c ${customPresetFile}`);
        }
        console.log();
    }
    static logAccount(account, keyName, showPrivateKeys) {
        if (account === undefined) {
            return account;
        }
        const privateKeyText = showPrivateKeys && account instanceof symbol_sdk_1.Account ? `\n\tPrivate Key: ${account.privateKey}` : '';
        console.log(` - ${keyName}:\n\tAddress:     ${account.address.pretty()}\n\tPublic Key:  ${account.publicKey}${privateKeyText}`);
        return account;
    }
    static async resolveAccounts(networkType, rewardProgram) {
        while (true) {
            const importMode = await Wizard.resolveImportMode();
            if (importMode === ImportType.OPTIN_PAPER_WALLET) {
                {
                    const derivedAccount = await Wizard.resolveDerivedAccount(networkType, true);
                    if (derivedAccount) {
                        return await Wizard.resolveAllAccount(networkType, derivedAccount, rewardProgram);
                    }
                }
            }
            else if (importMode === ImportType.SYMBOL_PAPER_WALLET) {
                {
                    const derivedAccount = await Wizard.resolveDerivedAccount(networkType, false);
                    if (derivedAccount) {
                        return await Wizard.resolveAllAccount(networkType, derivedAccount, rewardProgram);
                    }
                }
            }
            else if (importMode === ImportType.PRIVATE_KEYS) {
                {
                    return await Wizard.resolveAllAccount(networkType, undefined, rewardProgram);
                }
            }
        }
    }
    static async resolveAllAccount(networkType, derivedAccount, rewardProgram) {
        console.log();
        return {
            seeded: true,
            main: derivedAccount
                ? derivedAccount.account
                : await this.resolveAccountFromSelection(networkType, derivedAccount, service_1.KeyName.Main, 0, 'It holds the tokens required to give the node its importance.'),
            transport: await this.resolveAccountFromSelection(networkType, derivedAccount, service_1.KeyName.Transport, 1, 'It is used by nodes for secure transport over TLS.'),
            vrf: await this.resolveAccountFromSelection(networkType, derivedAccount, service_1.KeyName.VRF, 2, 'It is required for harvesting.'),
            remote: await this.resolveAccountFromSelection(networkType, derivedAccount, service_1.KeyName.Remote, 3, 'It is used to harvest and collect the rewards on behalf of the main account in remote harvesting.'),
            agent: rewardProgram
                ? await this.resolveAccountFromSelection(networkType, derivedAccount, service_1.KeyName.Remote, 4, 'It is used to create TLS certificates request for the Controller to Agent communication.')
                : undefined,
        };
    }
    static async resolveAccountFromSelection(networkType, derivedAccount, keyName, changeIndex, keyDescription) {
        console.log(`${keyName} Key Pair: ${keyDescription}`);
        while (true) {
            const keyCreationChoices = [];
            keyCreationChoices.push({ name: 'Generating a new account', value: 'generate' });
            keyCreationChoices.push({ name: 'Entering a private key', value: 'manual' });
            if (derivedAccount && !derivedAccount.optinMode) {
                keyCreationChoices.push({ name: 'Deriving it from Symbol Paper Wallet seed', value: 'seed' });
            }
            const { keyCreationMode } = await inquirer_1.prompt([
                {
                    name: 'keyCreationMode',
                    message: `How do you want to create the ${keyName} account:`,
                    type: 'list',
                    default: keyCreationChoices[0].name,
                    choices: keyCreationChoices,
                },
            ]);
            const log = (account, message) => {
                console.log();
                console.log(`Using account ${account.address.pretty()} for ${keyName} key. ${message}`);
                console.log();
                return account;
            };
            if (keyCreationMode == 'generate') {
                return log(symbol_sdk_1.Account.generateNewAccount(networkType), 'It will be stored in your custom preset. Keep file safe!');
            }
            if (keyCreationMode == 'seed' && derivedAccount) {
                const seedAccount = Wizard.toAccountFromMnemonicPhrase(derivedAccount.mnemonicPassPhrase, networkType, derivedAccount.optinMode, derivedAccount.accountIndex, changeIndex);
                return log(symbol_sdk_1.Account.createFromPrivateKey(seedAccount.privateKey, networkType), 'It will be stored in your custom preset. Can be derived from the paper wallet if lost!');
            }
            // manual
            const account = await Wizard.resolveAccount(networkType, keyName);
            if (account) {
                return log(account, 'It will be stored in your custom preset. You can recreate the account by providing the private key again!');
            }
        }
    }
    static async resolveAccount(networkType, keyName) {
        while (true) {
            const { privateKey } = await inquirer_1.prompt([
                {
                    name: 'privateKey',
                    message: `Enter the 64 HEX private key of the ${keyName} account (or press enter to select the option again).`,
                    type: 'password',
                    mask: '*',
                    validate: (value) => {
                        if (!value) {
                            return true;
                        }
                        return service_1.CommandUtils.isValidPrivateKey(value);
                    },
                },
            ]);
            if (!privateKey) {
                return undefined;
            }
            else {
                const enteredAccount = symbol_sdk_1.Account.createFromPrivateKey(privateKey, networkType);
                const { ok } = await inquirer_1.prompt([
                    {
                        name: 'ok',
                        message: `Is this the expected address ${enteredAccount.address.pretty()} to used as ${keyName} account? `,
                        type: 'confirm',
                        default: false,
                    },
                ]);
                if (ok) {
                    return enteredAccount;
                }
            }
        }
    }
    static async resolveNetwork(providedNetwork) {
        if (!providedNetwork) {
            console.log('Select type node or network you want to run:\n');
            const responses = await inquirer_1.prompt([
                {
                    name: 'network',
                    message: 'Select a network:',
                    type: 'list',
                    default: Network.mainnet,
                    choices: [
                        { name: 'Mainnet Node', value: Network.mainnet },
                        { name: 'Testnet Node', value: Network.testnet },
                        { name: 'Private Network', value: Network.privateNetwork },
                    ],
                },
            ]);
            return responses.network;
        }
        return providedNetwork;
    }
    static async resolvePrivateKeySecurityMode() {
        const { mode } = await inquirer_1.prompt([
            {
                name: 'mode',
                message: 'Select the type of security you want to use:',
                type: 'list',
                default: model_1.PrivateKeySecurityMode.PROMPT_MAIN_TRANSPORT,
                choices: [
                    {
                        name: 'PROMPT_MAIN: Bootstrap may ask for the Main private key when doing certificates upgrades. Other keys are encrypted. Recommended for Supernodes.',
                        value: model_1.PrivateKeySecurityMode.PROMPT_MAIN,
                    },
                    {
                        name: 'PROMPT_MAIN_TRANSPORT: Bootstrap may ask for the Main and Transport private keys when regenerating certificates and agent configuration. Other keys are encrypted. Recommended for regular nodes',
                        value: model_1.PrivateKeySecurityMode.PROMPT_MAIN_TRANSPORT,
                    },
                    { name: 'ENCRYPT: All keys are encrypted, only password would be asked', value: model_1.PrivateKeySecurityMode.ENCRYPT },
                ],
            },
        ]);
        return mode;
    }
    static async resolveAssembly(preset) {
        console.log('Select the assembly to be created:\n');
        const responses = await inquirer_1.prompt([
            {
                name: 'assembly',
                message: 'Select an assembly:',
                type: 'list',
                default: exports.assemblies[preset][0].value,
                choices: exports.assemblies[preset].map(({ value, description }) => ({
                    value: value,
                    name: description,
                })),
            },
        ]);
        return responses.assembly;
    }
    static async resolveImportMode() {
        const responses = await inquirer_1.prompt([
            {
                name: 'mode',
                message: 'How do you want to import your accounts?',
                type: 'list',
                default: ImportType.PRIVATE_KEYS,
                choices: [
                    {
                        value: ImportType.PRIVATE_KEYS,
                        name: 'Private Keys: The private Keys will be generated or entered.',
                    },
                    {
                        value: ImportType.OPTIN_PAPER_WALLET,
                        name: 'OptIn Paper Wallet (Pre-Launch): Only the main private key can be restored. Other keys will be generated.',
                    },
                    {
                        value: ImportType.SYMBOL_PAPER_WALLET,
                        name: 'Symbol Paper Wallet (Post-Launch): The main and secondary keys can be restored from the paper.',
                    },
                ],
            },
        ]);
        return responses.mode;
    }
    static async isVoting() {
        console.log('Select whether your Symbol node should be a Voting node. Note: A Voting node requires the main account to hold at least 3 million XYMs. ');
        console.log('If your node does not have enough XYMs its Voting key may not be included. ');
        const { voting } = await inquirer_1.prompt([
            {
                name: 'voting',
                message: 'Are you creating a Voting node?',
                type: 'confirm',
                default: false,
            },
        ]);
        return voting;
    }
    static getNetworkIdFlag() {
        return command_1.flags.string({
            description: 'The node or network you want to create',
            options: [Network.mainnet, Network.testnet, Network.privateNetwork],
        });
    }
    static getCustomPresetFile() {
        return command_1.flags.string({ char: 'c', description: 'The custom preset to be created.', default: 'custom-preset.yml' });
    }
    static isValidPhrase(input) {
        if (!input) {
            return true;
        }
        const words = input.trim().split(' ').length;
        return words === 24 ? true : `Invalid phrase. It must have 24 words but got ${words}.`;
    }
    static async resolveDerivedAccount(networkType, optinMode) {
        try {
            console.log('To generate the keys, enter the 24 words of the mnemonic phrase created when you opted in.\nYou can find them in the Paper Wallet. They will not be stored anywhere by this tool.\n');
            let lastEnteredPhrase = '';
            while (true) {
                const phraseResponse = await inquirer_1.prompt([
                    {
                        name: 'value',
                        message: `Enter the mnemonic phrase for you Main account (or press enter to select the option again).`,
                        type: 'input',
                        default: lastEnteredPhrase || undefined,
                        validate: (input) => Wizard.isValidPhrase(input),
                    },
                ]);
                if (!phraseResponse.value) {
                    return undefined;
                }
                lastEnteredPhrase = phraseResponse.value.trim();
                const mnemonicPassPhrase = new symbol_hd_wallets_1.MnemonicPassPhrase(lastEnteredPhrase);
                const derivedAccounts = Wizard.findDerivedAccounts(mnemonicPassPhrase, networkType, optinMode, undefined, 0);
                const choices = derivedAccounts.map((derivedAccounts) => ({
                    value: derivedAccounts.account.address.plain(),
                    name: derivedAccounts.account.address.pretty(),
                }));
                choices.push({
                    value: 'none',
                    name: 'None of the above. Re-enter phrase',
                });
                const accountResponse = await inquirer_1.prompt([
                    {
                        name: 'accountAddress',
                        message: 'Select an account:',
                        type: 'list',
                        default: choices[0].value,
                        choices: choices,
                    },
                ]);
                const derivedAccount = derivedAccounts.find((derivedAccount) => derivedAccount.account.address.plain() == accountResponse.accountAddress);
                if (derivedAccount) {
                    return derivedAccount;
                }
            }
        }
        catch (e) {
            throw new Error(`Symbol account cannot be created from phrase: ${e.message}`);
        }
    }
    static findDerivedAccounts(mnemonicPassPhrase, networkType, optinMode, expectedAccountIndex, expectedChangeIndex) {
        const accountIndexes = expectedAccountIndex === undefined ? Array.from(Array(20).keys()) : [expectedAccountIndex];
        const changeIndexes = expectedChangeIndex === undefined ? Array.from(Array(20).keys()) : [expectedChangeIndex];
        const derivedAccounts = [];
        for (const accountIndex of accountIndexes) {
            for (const changeIndex of changeIndexes) {
                const account = Wizard.toAccountFromMnemonicPhrase(mnemonicPassPhrase, networkType, optinMode, accountIndex, changeIndex);
                derivedAccounts.push({ networkType, optinMode, account, accountIndex, changeIndex, mnemonicPassPhrase });
            }
        }
        return derivedAccounts;
    }
    static toAccountFromMnemonicPhrase(mnemonicPassPhrase, networkType, optinMode, accountIndex, changeIndex) {
        const coinIndex = networkType === symbol_sdk_1.NetworkType.MAIN_NET ? '4343' : '1';
        const mnemonicSeed = mnemonicPassPhrase.toSeed().toString('hex');
        const seedNetwork = optinMode ? symbol_hd_wallets_1.Network.BITCOIN : symbol_hd_wallets_1.Network.SYMBOL;
        const extendedKey = symbol_hd_wallets_1.ExtendedKey.createFromSeed(mnemonicSeed, seedNetwork);
        const wallet = new symbol_hd_wallets_1.Wallet(extendedKey);
        const path = `m/44'/${coinIndex}'/${accountIndex}'/${changeIndex}'/0'`;
        const privateKey = wallet.getChildAccountPrivateKey(path);
        return symbol_sdk_1.Account.createFromPrivateKey(privateKey, networkType);
    }
    static async resolveRewardProgram() {
        const { value } = await inquirer_1.prompt([
            {
                name: 'value',
                message: 'Select your Symbol Reward Program:',
                type: 'list',
                default: 'None',
                choices: [
                    { name: 'None. Just a standard node.', value: 'None' },
                    { name: service_1.RewardProgram.SuperNode, value: service_1.RewardProgram.SuperNode },
                    {
                        name: service_1.RewardProgram.EarlyAdoption + ' (only if you have pre-enrolled using the Nis1 Transfer transaction)',
                        value: service_1.RewardProgram.EarlyAdoption,
                    },
                    {
                        name: service_1.RewardProgram.Ecosystem + ' (only if you have pre-enrolled using the Nis1 Transfer transaction)',
                        value: service_1.RewardProgram.Ecosystem,
                    },
                ],
            },
        ]);
        if (value === 'None') {
            return undefined;
        }
        return value;
    }
    static async resolveHost(message, required) {
        const { host } = await inquirer_1.prompt([
            {
                name: 'host',
                message: message,
                type: 'input',
                validate: (value) => {
                    if (!required && !value) {
                        return true;
                    }
                    return Wizard.isValidHost(value);
                },
            },
        ]);
        return host || undefined;
    }
    static isValidHost(input) {
        if (input.trim() == '') {
            return 'Host is required.';
        }
        if (input.length > 50) {
            return `Input (${input.length}) is larger than 50`;
        }
        const valid = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(input);
        return valid ? true : `It's not a valid IP or hostname`;
    }
    static isValidFriendlyName(input) {
        if (input.trim() == '') {
            return 'Friendly name is required.';
        }
        if (input.length > 30) {
            return `Input (${input.length}) is larger than 30`;
        }
        return true;
    }
    static async resolveFriendlyName(defaultFriendlyName) {
        const { friendlyName } = await inquirer_1.prompt([
            {
                name: 'friendlyName',
                message: `Enter the friendly name of your node.`,
                type: 'input',
                default: defaultFriendlyName,
                validate: Wizard.isValidFriendlyName,
            },
        ]);
        return friendlyName;
    }
}
exports.default = Wizard;
Wizard.description = 'An utility command that will help you configuring node!';
Wizard.examples = [`$ symbol-bootstrap wizard`];
Wizard.flags = {
    help: service_1.CommandUtils.helpFlag,
    target: service_1.CommandUtils.targetFlag,
    password: service_1.CommandUtils.passwordFlag,
    noPassword: service_1.CommandUtils.noPasswordFlag,
    network: Wizard.getNetworkIdFlag(),
    customPreset: Wizard.getCustomPresetFile(),
    ready: command_1.flags.boolean({
        description: 'If --ready is provided, the command will not ask offline confirmation.',
    }),
};
