// 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); }
};
import { Flags as flags } from '../flags.js';
import { showVersionBanner } from '../../core/helpers.js';
import * as constants from '../../core/constants.js';
import { SOLO_CLUSTER_SETUP_CHART } from '../../core/constants.js';
import chalk from 'chalk';
import { ListrLock } from '../../core/lock/listr-lock.js';
import { ErrorMessages } from '../../core/error-messages.js';
import { SoloError } from '../../core/errors/solo-error.js';
import { UserBreak } from '../../core/errors/user-break.js';
import { ListrInquirerPromptAdapter } from '@listr2/prompt-adapter-inquirer';
import { confirm as confirmPrompt } from '@inquirer/prompts';
import { inject, injectable } from 'tsyringe-neo';
import { patchInject } from '../../core/dependency-injection/container-helper.js';
import { InjectTokens } from '../../core/dependency-injection/inject-tokens.js';
import { PathEx } from '../../business/utils/path-ex.js';
import { quote } from 'shell-quote';
import { LocalConfigRuntimeState } from '../../business/runtime-state/config/local/local-config-runtime-state.js';
import { StringFacade } from '../../business/runtime-state/facade/string-facade.js';
import { RemoteConfigRuntimeState } from '../../business/runtime-state/config/remote/remote-config-runtime-state.js';
import { Version } from '../../business/utils/version.js';
let ClusterCommandTasks = class ClusterCommandTasks {
    k8Factory;
    localConfig;
    logger;
    chartManager;
    leaseManager;
    clusterChecks;
    remoteConfig;
    constructor(k8Factory, localConfig, logger, chartManager, leaseManager, clusterChecks, remoteConfig) {
        this.k8Factory = k8Factory;
        this.localConfig = localConfig;
        this.logger = logger;
        this.chartManager = chartManager;
        this.leaseManager = leaseManager;
        this.clusterChecks = clusterChecks;
        this.remoteConfig = remoteConfig;
        this.k8Factory = patchInject(k8Factory, InjectTokens.K8Factory, this.constructor.name);
        this.localConfig = patchInject(localConfig, InjectTokens.LocalConfigRuntimeState, this.constructor.name);
        this.logger = patchInject(logger, InjectTokens.SoloLogger, this.constructor.name);
        this.chartManager = patchInject(chartManager, InjectTokens.ChartManager, this.constructor.name);
        this.leaseManager = patchInject(leaseManager, InjectTokens.LockManager, this.constructor.name);
        this.clusterChecks = patchInject(clusterChecks, InjectTokens.ClusterChecks, this.constructor.name);
        this.remoteConfig = patchInject(remoteConfig, InjectTokens.RemoteConfigRuntimeState, this.constructor.name);
    }
    connectClusterRef() {
        return {
            title: 'Associate a context with a cluster reference: ',
            task: async (context_, task) => {
                task.title += context_.config.clusterRef;
                this.localConfig.configuration.clusterRefs.set(context_.config.clusterRef, new StringFacade(context_.config.context));
                await this.localConfig.persist();
            },
        };
    }
    disconnectClusterRef() {
        return {
            title: 'Remove cluster reference ',
            task: async (context_, task) => {
                task.title += context_.config.clusterRef;
                this.localConfig.configuration.clusterRefs.delete(context_.config.clusterRef);
                await this.localConfig.persist();
            },
        };
    }
    testConnectionToCluster(clusterReference) {
        const self = this;
        return {
            title: 'Test connection to cluster: ',
            task: async (context_, task) => {
                task.title += clusterReference ?? context_.config.clusterRef;
                try {
                    await self.k8Factory.getK8(context_.config.context).namespaces().list();
                }
                catch {
                    task.title = `${task.title} - ${chalk.red('Cluster connection failed')}`;
                    throw new SoloError(`${ErrorMessages.INVALID_CONTEXT_FOR_CLUSTER_DETAILED(context_.config.context, context_.config.clusterRef)}`);
                }
            },
        };
    }
    validateClusterRefs() {
        const self = this;
        return {
            title: 'Validating cluster ref: ',
            task: async (context_, task) => {
                const { clusterRef } = context_.config;
                task.title = clusterRef;
                if (self.localConfig.configuration.clusterRefs.get(clusterRef)) {
                    this.logger.showUser(chalk.yellow(`Cluster ref ${clusterRef} already exists inside local config`));
                }
            },
        };
    }
    /**
     * Prepare values arg for cluster setup command
     *
     * @param chartDirectory
     * @param [prometheusStackEnabled] - a bool to denote whether to install prometheus stack
     * @param [minioEnabled] - a bool to denote whether to install minio
     */
    prepareValuesArg(chartDirectory = flags.chartDirectory.definition.defaultValue, prometheusStackEnabled = flags.deployPrometheusStack.definition.defaultValue, minioEnabled = flags.deployMinio.definition.defaultValue) {
        let valuesArgument = '';
        if (chartDirectory) {
            // Safely construct the path and escape it for shell usage
            const valuesPath = PathEx.join(chartDirectory, 'solo-cluster-setup', 'values.yaml');
            valuesArgument = `-f ${quote([valuesPath])}`;
        }
        valuesArgument += ` --set cloud.prometheusStack.enabled=${prometheusStackEnabled}`;
        valuesArgument += ` --set cloud.minio.enabled=${minioEnabled}`;
        return valuesArgument;
    }
    /** Show list of installed chart */
    async showInstalledChartList(clusterSetupNamespace, context) {
        // TODO convert to logger.addMessageGroup() & logger.addMessageGroupMessage()
        this.logger.showList('Installed Charts', await this.chartManager.getInstalledCharts(clusterSetupNamespace, context));
    }
    initialize(argv, configInit, loadRemoteConfig = false) {
        const { required, optional } = argv;
        // eslint-disable-next-line @typescript-eslint/typedef,unicorn/no-this-assignment
        const self = this;
        argv.flags = [...required, ...optional];
        return {
            title: 'Initialize',
            task: async (context_, task) => {
                await self.localConfig.load();
                if (loadRemoteConfig) {
                    await self.remoteConfig.loadAndValidate(argv);
                }
                context_.config = await configInit(argv, context_, task);
            },
        };
    }
    showClusterList() {
        // eslint-disable-next-line @typescript-eslint/typedef,unicorn/no-this-assignment
        const self = this;
        return {
            title: 'List all available clusters',
            task: async () => {
                await self.localConfig.load();
                const clusterReferences = this.localConfig.configuration.clusterRefs;
                const clusterList = [];
                for (const [clusterName, clusterContext] of clusterReferences) {
                    clusterList.push(`${clusterName}:${clusterContext}`);
                }
                this.logger.showList('Cluster references and the respective contexts', clusterList);
            },
        };
    }
    getClusterInfo() {
        return {
            title: 'Get cluster info',
            task: async (context_, task) => {
                const clusterReference = context_.config.clusterRef;
                const clusterReferences = this.localConfig.configuration.clusterRefs;
                const deployments = this.localConfig.configuration.deployments;
                const context = clusterReferences.get(clusterReference);
                if (!context) {
                    throw new Error(`Cluster "${clusterReference}" not found in the LocalConfig`);
                }
                const deploymentsWithSelectedCluster = Object.entries(deployments)
                    // eslint-disable-next-line @typescript-eslint/no-unused-vars
                    .filter(([_, deployment]) => deployment.clusters.includes(clusterReference))
                    .map(([deploymentName, deployment]) => ({
                    name: deploymentName,
                    namespace: deployment.namespace || 'default',
                }));
                task.output =
                    `Cluster Reference: ${clusterReference}\n` +
                        `Associated Context: ${context}\n` +
                        'Deployments using this Cluster:';
                task.output +=
                    deploymentsWithSelectedCluster.length > 0
                        ? '\n' +
                            deploymentsWithSelectedCluster.map(dep => `  - ${dep.name} [Namespace: ${dep.namespace}]`).join('\n')
                        : '\n  - None';
                this.logger.showUser(task.output);
            },
        };
    }
    prepareChartValues() {
        // eslint-disable-next-line @typescript-eslint/typedef,unicorn/no-this-assignment
        const self = this;
        return {
            title: 'Prepare chart values',
            task: async (context_) => {
                // if minio is already present, don't deploy it
                if (context_.config.deployMinio &&
                    (await self.clusterChecks.isMinioInstalled(context_.config.clusterSetupNamespace))) {
                    context_.config.deployMinio = false;
                }
                // if prometheus is found, don't deploy it
                if (context_.config.deployPrometheusStack &&
                    (await self.clusterChecks.isPrometheusInstalled(context_.config.clusterSetupNamespace))) {
                    context_.config.deployPrometheusStack = false;
                }
                // If all are already present or not wanted, skip installation
                if (!context_.config.deployPrometheusStack && !context_.config.deployMinio) {
                    // TODO: I think this will skip installing the RBAC role
                    context_.isChartInstalled = true;
                    return;
                }
                context_.valuesArg = this.prepareValuesArg(context_.config.chartDirectory, context_.config.deployPrometheusStack, context_.config.deployMinio);
            },
            skip: context_ => context_.isChartInstalled,
        };
    }
    installClusterChart(argv) {
        // eslint-disable-next-line @typescript-eslint/typedef,unicorn/no-this-assignment
        const self = this;
        return {
            title: `Install '${constants.SOLO_CLUSTER_SETUP_CHART}' chart`,
            task: async (context_) => {
                const clusterSetupNamespace = context_.config.clusterSetupNamespace;
                const version = Version.getValidSemanticVersion(context_.config.soloChartVersion, false, 'Solo chart version');
                const valuesArgument = context_.valuesArg;
                try {
                    await this.chartManager.install(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART, constants.SOLO_CLUSTER_SETUP_CHART, context_.config.chartDirectory ? context_.config.chartDirectory : constants.SOLO_TESTING_CHART_URL, version, valuesArgument, context_.config.context);
                    showVersionBanner(self.logger, SOLO_CLUSTER_SETUP_CHART, version);
                }
                catch (error) {
                    // if error, uninstall the chart and rethrow the error
                    self.logger.debug(`Error on installing ${constants.SOLO_CLUSTER_SETUP_CHART}. attempting to rollback by uninstalling the chart`, error);
                    try {
                        await this.chartManager.uninstall(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART, context_.config.context);
                    }
                    catch (error) {
                        this.logger.showUserError(error);
                    }
                    throw new SoloError(`Error on installing ${constants.SOLO_CLUSTER_SETUP_CHART}. attempting to rollback by uninstalling the chart`, error);
                }
                if (argv.dev) {
                    await this.showInstalledChartList(clusterSetupNamespace, context_.config.context);
                }
            },
            skip: context_ => context_.isChartInstalled,
        };
    }
    acquireNewLease() {
        return {
            title: 'Acquire new lease',
            task: async (_, task) => {
                const lease = await this.leaseManager.create();
                return ListrLock.newAcquireLockTask(lease, task);
            },
        };
    }
    uninstallClusterChart(argv) {
        // eslint-disable-next-line @typescript-eslint/typedef,unicorn/no-this-assignment
        const self = this;
        return {
            title: `Uninstall '${constants.SOLO_CLUSTER_SETUP_CHART}' chart`,
            task: async (context_, task) => {
                const clusterSetupNamespace = context_.config.clusterSetupNamespace;
                if (!argv.force && (await self.clusterChecks.isRemoteConfigPresentInAnyNamespace())) {
                    const confirm = await task.prompt(ListrInquirerPromptAdapter).run(confirmPrompt, {
                        default: false,
                        message: 'There is remote config for one of the deployments' +
                            'Are you sure you would like to uninstall the cluster?',
                    });
                    if (!confirm) {
                        throw new UserBreak('Aborted application by user prompt');
                    }
                }
                await self.chartManager.uninstall(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART, this.k8Factory.default().contexts().readCurrent());
                if (argv.dev) {
                    await this.showInstalledChartList(clusterSetupNamespace);
                }
            },
            skip: context_ => !context_.isChartInstalled,
        };
    }
};
ClusterCommandTasks = __decorate([
    injectable(),
    __param(0, inject(InjectTokens.K8Factory)),
    __param(1, inject(InjectTokens.LocalConfigRuntimeState)),
    __param(2, inject(InjectTokens.SoloLogger)),
    __param(3, inject(InjectTokens.ChartManager)),
    __param(4, inject(InjectTokens.LockManager)),
    __param(5, inject(InjectTokens.ClusterChecks)),
    __param(6, inject(InjectTokens.RemoteConfigRuntimeState)),
    __metadata("design:paramtypes", [Object, LocalConfigRuntimeState, Object, Function, Function, Function, RemoteConfigRuntimeState])
], ClusterCommandTasks);
export { ClusterCommandTasks };
//# sourceMappingURL=tasks.js.map