// SPDX-License-Identifier: Apache-2.0
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var DefaultQuickStartCommand_1;
import { SoloError } from '../../core/errors/solo-error.js';
import * as constants from '../../core/constants.js';
import { BaseCommand } from '../base.js';
import { Flags as flags, Flags } from '../flags.js';
import { CommandBuilder, CommandGroup, Subcommand } from '../../core/command-path-builders/command-builder.js';
import { inject, injectable } from 'tsyringe-neo';
import { v4 as uuid4 } from 'uuid';
import { NamespaceName } from '../../types/namespace/namespace-name.js';
import { StringEx } from '../../business/utils/string-ex.js';
import { ArgumentProcessor } from '../../argument-processor.js';
import * as version from '../../../version.js';
import { ClusterCommandHandlers } from '../cluster/handlers.js';
import { DeploymentCommand } from '../deployment.js';
import { NodeCommandHandlers } from '../node/handlers.js';
import { InitCommand } from '../init/init.js';
import { NetworkCommand } from '../network.js';
import { MirrorNodeCommand } from '../mirror-node.js';
import { ExplorerCommand } from '../explorer.js';
import { RelayCommand } from '../relay.js';
import { patchInject } from '../../core/dependency-injection/container-helper.js';
import { InjectTokens } from '../../core/dependency-injection/inject-tokens.js';
import { PREDEFINED_ACCOUNT_GROUPS, predefinedEcdsaAccounts, predefinedEcdsaAccountsWithAlias, predefinedEd25519Accounts, } from './predefined-accounts.js';
import { AccountId, HbarUnit } from '@hiero-ledger/sdk';
import * as helpers from '../../core/helpers.js';
import { Duration } from '../../core/time/duration.js';
import { resolveNamespaceFromDeployment } from '../../core/resolvers.js';
import fs from 'node:fs';
let DefaultQuickStartCommand = class DefaultQuickStartCommand extends BaseCommand {
    static { DefaultQuickStartCommand_1 = this; }
    accountManager;
    static COMMAND_NAME = 'quick-start';
    static SINGLE_ADD_CONFIGS_NAME = 'singleAddConfigs';
    static SINGLE_DESTROY_CONFIGS_NAME = 'singleDestroyConfigs';
    static SINGLE_ADD_FLAGS_LIST = {
        required: [],
        optional: [
            flags.cacheDir,
            flags.clusterRef,
            flags.clusterSetupNamespace,
            flags.context,
            flags.deployment,
            flags.devMode,
            flags.namespace,
            flags.numberOfConsensusNodes,
            flags.predefinedAccounts,
            flags.quiet,
            // TODO add flag for consensus node version
        ],
    };
    static SINGLE_DESTROY_FLAGS_LIST = {
        required: [],
        optional: [
            flags.cacheDir,
            flags.clusterRef,
            flags.context,
            flags.deployment,
            flags.namespace,
            flags.quiet,
            flags.force,
            flags.devMode,
        ],
    };
    constructor(accountManager) {
        super();
        this.accountManager = accountManager;
        this.accountManager = patchInject(accountManager, InjectTokens.AccountManager, this.constructor.name);
    }
    newArgv() {
        return ['${PATH}/node', '${SOLO_ROOT}/solo.ts'];
    }
    optionFromFlag(flag) {
        return `--${flag.name}`;
    }
    argvPushGlobalFlags(argv, cacheDirectory = StringEx.EMPTY) {
        argv.push(this.optionFromFlag(Flags.devMode), this.optionFromFlag(Flags.quiet));
        if (cacheDirectory) {
            argv.push(this.optionFromFlag(Flags.cacheDir), cacheDirectory);
        }
        return argv;
    }
    invokeSoloCommand(title, commandName, callback) {
        return {
            title,
            task: async (_, taskListWrapper) => {
                return this.subTaskSoloCommand(commandName, this.taskList, taskListWrapper, callback);
            },
        };
    }
    async subTaskSoloCommand(commandName, taskList, taskListWrapper, callback) {
        taskList.parentTaskListMap.set(commandName, { taskListWrapper });
        const newArgv = callback();
        await ArgumentProcessor.process(newArgv);
        return this.taskList.parentTaskListMap.get(commandName).children;
    }
    async deploy(argv) {
        let config = null;
        const tasks = this.taskList.newQuickStartSingleDeployTaskList([
            {
                title: 'Initialize',
                task: async (context_, task) => {
                    this.configManager.update(argv);
                    flags.disablePrompts(DefaultQuickStartCommand_1.SINGLE_ADD_FLAGS_LIST.optional);
                    const allFlags = [
                        ...DefaultQuickStartCommand_1.SINGLE_ADD_FLAGS_LIST.required,
                        ...DefaultQuickStartCommand_1.SINGLE_ADD_FLAGS_LIST.optional,
                    ];
                    await this.configManager.executePrompt(task, allFlags);
                    context_.config = this.configManager.getConfig(DefaultQuickStartCommand_1.SINGLE_ADD_CONFIGS_NAME, allFlags);
                    config = context_.config;
                    const uniquePostfix = uuid4().slice(-8);
                    context_.config.clusterRef = context_.config.clusterRef || `solo-${uniquePostfix}`;
                    context_.config.context = context_.config.context || this.k8Factory.default().contexts().readCurrent();
                    context_.config.deployment = context_.config.deployment || `solo-deployment-${uniquePostfix}`;
                    context_.config.namespace = context_.config.namespace || NamespaceName.of(`solo-${uniquePostfix}`);
                    context_.config.numberOfConsensusNodes = context_.config.numberOfConsensusNodes || 1;
                    context_.createdAccounts = [];
                    return;
                },
            },
            this.invokeSoloCommand('solo init', InitCommand.INIT_COMMAND_NAME, () => {
                const argv = this.newArgv();
                argv.push('init');
                return this.argvPushGlobalFlags(argv, config.cacheDir);
            }),
            this.invokeSoloCommand('solo cluster-ref connect', ClusterCommandHandlers.CONNECT_COMMAND, () => {
                const argv = this.newArgv();
                argv.push('cluster-ref', 'connect', this.optionFromFlag(Flags.clusterRef), config.clusterRef, this.optionFromFlag(Flags.context), config.context);
                return this.argvPushGlobalFlags(argv);
            }),
            this.invokeSoloCommand('solo deployment create', DeploymentCommand.CREATE_COMMAND, () => {
                const argv = this.newArgv();
                argv.push('deployment', 'create', this.optionFromFlag(Flags.deployment), config.deployment, this.optionFromFlag(Flags.namespace), config.namespace.name);
                return this.argvPushGlobalFlags(argv);
            }),
            this.invokeSoloCommand('solo deployment add-cluster', DeploymentCommand.ADD_COMMAND, () => {
                const argv = this.newArgv();
                argv.push('deployment', 'add-cluster', this.optionFromFlag(Flags.deployment), config.deployment, this.optionFromFlag(Flags.clusterRef), config.clusterRef, this.optionFromFlag(Flags.numberOfConsensusNodes), config.numberOfConsensusNodes.toString());
                return this.argvPushGlobalFlags(argv);
            }),
            this.invokeSoloCommand('solo cluster-ref setup', ClusterCommandHandlers.SETUP_COMMAND, () => {
                const argv = this.newArgv();
                argv.push('cluster-ref', 'setup', this.optionFromFlag(Flags.clusterRef), config.clusterRef);
                return this.argvPushGlobalFlags(argv);
            }),
            this.invokeSoloCommand('solo node keys', NodeCommandHandlers.KEYS_COMMAND, () => {
                const argv = this.newArgv();
                argv.push('node', 'keys', this.optionFromFlag(Flags.deployment), config.deployment, this.optionFromFlag(Flags.generateGossipKeys), 'true', this.optionFromFlag(Flags.generateTlsKeys));
                return this.argvPushGlobalFlags(argv, config.cacheDir);
            }),
            this.invokeSoloCommand('solo network deploy', NetworkCommand.DEPLOY_COMMAND, () => {
                const argv = this.newArgv();
                argv.push('network', 'deploy', this.optionFromFlag(Flags.deployment), config.deployment);
                return this.argvPushGlobalFlags(argv, config.cacheDir);
            }),
            this.invokeSoloCommand('solo node setup', NodeCommandHandlers.SETUP_COMMAND, () => {
                const argv = this.newArgv();
                argv.push('node', 'setup', this.optionFromFlag(Flags.deployment), config.deployment);
                return this.argvPushGlobalFlags(argv, config.cacheDir);
            }),
            this.invokeSoloCommand('solo node start', NodeCommandHandlers.START_COMMAND, () => {
                const argv = this.newArgv();
                argv.push('node', 'start', this.optionFromFlag(Flags.deployment), config.deployment);
                return this.argvPushGlobalFlags(argv);
            }),
            this.invokeSoloCommand('solo mirror-node deploy', MirrorNodeCommand.DEPLOY_COMMAND, () => {
                const argv = this.newArgv();
                argv.push('mirror-node', 'deploy', this.optionFromFlag(Flags.deployment), config.deployment, this.optionFromFlag(Flags.clusterRef), config.clusterRef, this.optionFromFlag(Flags.pinger), this.optionFromFlag(Flags.enableIngress));
                return this.argvPushGlobalFlags(argv, config.cacheDir);
            }),
            this.invokeSoloCommand('solo explorer deploy', ExplorerCommand.DEPLOY_COMMAND, () => {
                const argv = this.newArgv();
                argv.push('explorer', 'deploy', this.optionFromFlag(Flags.deployment), config.deployment, this.optionFromFlag(Flags.clusterRef), config.clusterRef);
                return this.argvPushGlobalFlags(argv, config.cacheDir);
            }),
            this.invokeSoloCommand('solo relay deploy', RelayCommand.DEPLOY_COMMAND, () => {
                const argv = this.newArgv();
                argv.push('relay', 'deploy', this.optionFromFlag(Flags.deployment), config.deployment, this.optionFromFlag(Flags.clusterRef), config.clusterRef, this.optionFromFlag(Flags.nodeAliasesUnparsed), 'node1');
                return this.argvPushGlobalFlags(argv);
            }),
            {
                title: 'Create Accounts',
                skip: () => config.predefinedAccounts === false,
                task: async (context_, task) => {
                    await this.localConfig.load();
                    await this.remoteConfig.loadAndValidate(argv);
                    const self = this;
                    const subTasks = [];
                    const accountsToCreate = [
                        ...predefinedEcdsaAccounts,
                        ...predefinedEcdsaAccountsWithAlias,
                        ...predefinedEd25519Accounts,
                    ];
                    await self.accountManager.loadNodeClient(config.namespace, self.remoteConfig.getClusterRefs(), context_.config.deployment);
                    for (const [index, account] of accountsToCreate.entries()) {
                        // inject index to avoid closure issues
                        ((index, account) => {
                            subTasks.push({
                                title: `Creating Account ${index}`,
                                task: async (context_, subTask) => {
                                    await helpers.sleep(Duration.ofMillis(100 * index));
                                    const createdAccount = await self.accountManager.createNewAccount(context_.config.namespace, account.privateKey, account.balance.to(HbarUnit.Hbar).toNumber(), account.alias, context_.config.context);
                                    context_.createdAccounts.push({
                                        accountId: AccountId.fromString(createdAccount.accountId),
                                        data: account,
                                        alias: createdAccount.accountAlias,
                                    });
                                    subTask.title = `Account created: ${createdAccount.accountId.toString()}`;
                                },
                            });
                        })(index, account);
                    }
                    // set up the sub-tasks
                    return task.newListr(subTasks, {
                        concurrent: true,
                        rendererOptions: {
                            collapseSubtasks: false,
                        },
                    });
                },
            },
            {
                title: 'Finish',
                task: async (context_) => {
                    this.showQuickStartUserNotes(context_);
                    this.showVersions();
                    this.showPortForwards();
                    this.showCreatedAccounts(context_.createdAccounts);
                    return;
                },
            },
        ], {
            concurrent: false,
            rendererOptions: constants.LISTR_DEFAULT_RENDERER_OPTION,
        });
        try {
            await tasks.run();
        }
        catch (error) {
            throw new SoloError(`Error deploying Solo in quick-start mode: ${error.message}`, error);
        }
        finally {
            await this.taskList
                .callCloseFunctions()
                .then()
                .catch((error) => {
                this.logger.error('Error during closing task list:', error);
            });
        }
        return true;
    }
    showQuickStartUserNotes(context_) {
        const messageGroupKey = 'quick-start-user-notes';
        this.logger.addMessageGroup(messageGroupKey, 'Quick Start User Notes');
        this.logger.addMessageGroupMessage(messageGroupKey, `Cluster Reference: ${context_.config.clusterRef}`);
        this.logger.addMessageGroupMessage(messageGroupKey, `Deployment Name: ${context_.config.deployment}`);
        this.logger.addMessageGroupMessage(messageGroupKey, `Namespace Name: ${context_.config.namespace.name}`);
        this.logger.addMessageGroupMessage(messageGroupKey, 'To quickly delete the deployed resources, run the following command:\n' +
            `kubectl delete ns ${context_.config.namespace.name}`);
        this.logger.showMessageGroup(messageGroupKey);
    }
    showVersions() {
        const messageGroupKey = 'versions-used';
        this.logger.addMessageGroup(messageGroupKey, 'Versions Used');
        this.logger.addMessageGroupMessage(messageGroupKey, `Solo Chart Version: ${version.SOLO_CHART_VERSION}`);
        this.logger.addMessageGroupMessage(messageGroupKey, `Consensus Node Version: ${version.HEDERA_PLATFORM_VERSION}`);
        this.logger.addMessageGroupMessage(messageGroupKey, `Mirror Node Version: ${version.MIRROR_NODE_VERSION}`);
        this.logger.addMessageGroupMessage(messageGroupKey, `Explorer Version: ${version.EXPLORER_VERSION}`);
        this.logger.addMessageGroupMessage(messageGroupKey, `JSON RPC Relay Version: ${version.HEDERA_JSON_RPC_RELAY_VERSION}`);
        this.logger.showMessageGroup(messageGroupKey);
    }
    showCreatedAccounts(createdAccounts = []) {
        if (createdAccounts.length > 0) {
            createdAccounts.sort((a, b) => a.accountId.compare(b.accountId));
            const ecdsaAccounts = createdAccounts.filter((account) => account.data.group === PREDEFINED_ACCOUNT_GROUPS.ECDSA);
            const aliasAccounts = createdAccounts.filter((account) => account.data.group === PREDEFINED_ACCOUNT_GROUPS.ECDSA_ALIAS);
            const ed25519Accounts = createdAccounts.filter((account) => account.data.group === PREDEFINED_ACCOUNT_GROUPS.ED25519);
            const messageGroupKey = 'accounts-created';
            const ecdsaGroupKey = 'accounts-created-ecdsa';
            const ecdsaAliasGroupKey = 'accounts-created-ecdsa-alias';
            const ed25519GroupKey = 'accounts-created-ed25519';
            this.logger.addMessageGroup(messageGroupKey, 'Created Accounts');
            this.logger.addMessageGroup(ecdsaGroupKey, 'ECDSA Accounts:');
            this.logger.addMessageGroup(ecdsaAliasGroupKey, 'ECDSA Alias Accounts:');
            this.logger.addMessageGroup(ed25519GroupKey, 'ED25519 Accounts:');
            this.logger.showMessageGroup(messageGroupKey);
            if (ecdsaAccounts.length > 0) {
                for (const account of ecdsaAccounts) {
                    this.logger.addMessageGroupMessage(ecdsaGroupKey, `Account ID: ${account.accountId.toString()}, Private Key: 0x${account.data.privateKey.toStringRaw()}, Balance: ${account.data.balance.toString()}`);
                }
                this.logger.showMessageGroup(ecdsaGroupKey);
            }
            if (aliasAccounts.length > 0) {
                for (const account of aliasAccounts) {
                    this.logger.addMessageGroupMessage(ecdsaAliasGroupKey, `Account ID: ${account.accountId.toString()}, Public address: ${account.alias}, Private Key: 0x${account.data.privateKey.toStringRaw()}, Balance: ${account.data.balance.toString()}`);
                }
                this.logger.showMessageGroup(ecdsaAliasGroupKey);
            }
            if (ed25519Accounts.length > 0) {
                for (const account of ed25519Accounts) {
                    this.logger.addMessageGroupMessage(ed25519GroupKey, `Account ID: ${account.accountId.toString()}, Private Key: 0x${account.data.privateKey.toStringRaw()}, Balance: ${account.data.balance.toString()}`);
                }
                this.logger.showMessageGroup(ed25519GroupKey);
            }
        }
    }
    showPortForwards() {
        this.logger.showMessageGroup(constants.PORT_FORWARDING_MESSAGE_GROUP);
    }
    async destroy(argv) {
        let config;
        const tasks = this.taskList.newQuickStartSingleDestroyTaskList([
            {
                title: 'Initialize',
                task: async (context_, task) => {
                    this.configManager.update(argv);
                    flags.disablePrompts(DefaultQuickStartCommand_1.SINGLE_DESTROY_FLAGS_LIST.optional);
                    const allFlags = [
                        ...DefaultQuickStartCommand_1.SINGLE_DESTROY_FLAGS_LIST.required,
                        ...DefaultQuickStartCommand_1.SINGLE_DESTROY_FLAGS_LIST.optional,
                    ];
                    await this.configManager.executePrompt(task, allFlags);
                    context_.config = this.configManager.getConfig(DefaultQuickStartCommand_1.SINGLE_DESTROY_CONFIGS_NAME, allFlags);
                    config = context_.config;
                    await this.localConfig.load();
                    if (!config.cacheDir) {
                        config.cacheDir = constants.SOLO_CACHE_DIR;
                    }
                    if (!config.clusterRef) {
                        config.clusterRef = this.localConfig.configuration.clusterRefs.keys().next().value;
                    }
                    if (!config.context) {
                        config.context = this.localConfig.configuration.clusterRefs.get(config.clusterRef).toString();
                    }
                    if (!config.deployment) {
                        if (this.localConfig.configuration.deployments.length === 0) {
                            throw new SoloError('Deployments name is not found in local config');
                        }
                        config.deployment = this.localConfig.configuration.deployments.get(0).name;
                        this.configManager.setFlag(flags.deployment, config.deployment);
                    }
                    if (!config.namespace) {
                        config.namespace = await resolveNamespaceFromDeployment(this.localConfig, this.configManager, task);
                    }
                },
            },
            this.invokeSoloCommand('solo explorer destroy', 'explorer destroy', () => {
                const argv = this.newArgv();
                argv.push('explorer', 'destroy', this.optionFromFlag(flags.clusterRef), config.clusterRef, this.optionFromFlag(flags.deployment), config.deployment, this.optionFromFlag(flags.quiet), this.optionFromFlag(flags.force));
                return this.argvPushGlobalFlags(argv);
            }),
            this.invokeSoloCommand('solo mirror-node destroy', 'mirror-node destroy', () => {
                const argv = this.newArgv();
                argv.push('mirror-node', 'destroy', this.optionFromFlag(flags.clusterRef), config.clusterRef, this.optionFromFlag(flags.deployment), config.deployment, this.optionFromFlag(flags.quiet), this.optionFromFlag(flags.force), this.optionFromFlag(flags.devMode));
                return this.argvPushGlobalFlags(argv);
            }),
            this.invokeSoloCommand('solo relay destroy', 'relay destroy', () => {
                const argv = this.newArgv();
                argv.push('relay', 'destroy', this.optionFromFlag(flags.clusterRef), config.clusterRef, this.optionFromFlag(flags.deployment), config.deployment, this.optionFromFlag(flags.nodeAliasesUnparsed), 'node1', this.optionFromFlag(flags.quiet));
                return this.argvPushGlobalFlags(argv);
            }),
            this.invokeSoloCommand('solo network destroy', 'network destroy', () => {
                const argv = this.newArgv();
                argv.push('network', 'destroy', this.optionFromFlag(flags.deployment), config.deployment, this.optionFromFlag(flags.quiet), this.optionFromFlag(flags.force), this.optionFromFlag(flags.deletePvcs), this.optionFromFlag(flags.deleteSecrets), this.optionFromFlag(flags.enableTimeout));
                return this.argvPushGlobalFlags(argv);
            }),
            this.invokeSoloCommand('solo cluster-ref reset', 'cluster-ref reset', () => {
                const argv = this.newArgv();
                argv.push('cluster-ref', 'reset', this.optionFromFlag(flags.clusterRef), config.clusterRef, this.optionFromFlag(flags.quiet), this.optionFromFlag(flags.force));
                return this.argvPushGlobalFlags(argv);
            }),
            {
                title: 'Delete cache folder',
                task: async () => {
                    fs.rmSync(config.cacheDir, { recursive: true, force: true });
                },
            },
            { title: 'Finish', task: async () => { } },
        ], {
            concurrent: false,
            rendererOptions: constants.LISTR_DEFAULT_RENDERER_OPTION,
        });
        try {
            await tasks.run();
        }
        catch (error) {
            throw new SoloError(`Error destroying Solo in quick-start mode: ${error.message}`, error);
        }
        finally {
            await this.taskList
                .callCloseFunctions()
                .then()
                .catch((error) => this.logger.error('Error during closing task list:', error));
        }
        return true;
    }
    getCommandDefinition() {
        return new CommandBuilder(DefaultQuickStartCommand_1.COMMAND_NAME, 'Manage quick start for solo network', this.logger)
            .addCommandGroup(new CommandGroup('single', 'A single consensus node quick start configuration')
            .addSubcommand(new Subcommand('deploy', 'Deploys all required components for the selected quick start configuration', this, this.deploy, (y) => {
            flags.setRequiredCommandFlags(y, ...DefaultQuickStartCommand_1.SINGLE_ADD_FLAGS_LIST.required);
            flags.setOptionalCommandFlags(y, ...DefaultQuickStartCommand_1.SINGLE_ADD_FLAGS_LIST.optional);
        }))
            .addSubcommand(new Subcommand('destroy', 'Removes the deployed resources for the selected quick start configuration', this, this.destroy, (y) => {
            flags.setRequiredCommandFlags(y, ...DefaultQuickStartCommand_1.SINGLE_DESTROY_FLAGS_LIST.required);
            flags.setOptionalCommandFlags(y, ...DefaultQuickStartCommand_1.SINGLE_DESTROY_FLAGS_LIST.optional);
        })))
            .build();
    }
    async close() { } // no-op
};
DefaultQuickStartCommand = DefaultQuickStartCommand_1 = __decorate([
    injectable(),
    __param(0, inject(InjectTokens.AccountManager)),
    __metadata("design:paramtypes", [Function])
], DefaultQuickStartCommand);
export { DefaultQuickStartCommand };
//# sourceMappingURL=default-quick-start.js.map