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); }
};
/**
 * Copyright (C) 2024 Hedera Hashgraph, LLC
 *
 * 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.
 *
 */
import { IsEmail, IsNotEmpty, IsObject, IsString, validateSync } from 'class-validator';
import fs from 'fs';
import * as yaml from 'yaml';
import { Flags as flags } from '../../commands/flags.js';
import { MissingArgumentError, SoloError } from '../errors.js';
import { SoloLogger } from '../logging.js';
import { IsClusterContextMapping, IsDeployments } from '../validator_decorators.js';
import { ConfigManager } from '../config_manager.js';
import { ErrorMessages } from '../error_messages.js';
import { splitFlagInput } from '../helpers.js';
import { inject, injectable } from 'tsyringe-neo';
import { patchInject } from '../container_helper.js';
let LocalConfig = class LocalConfig {
    filePath;
    logger;
    configManager;
    userEmailAddress;
    // The string is the name of the deployment, will be used as the namespace,
    // so it needs to be available in all targeted clusters
    deployments;
    currentDeploymentName;
    clusterContextMapping = {};
    skipPromptTask = false;
    constructor(filePath, logger, configManager) {
        this.filePath = filePath;
        this.logger = logger;
        this.configManager = configManager;
        this.filePath = patchInject(filePath, 'localConfigFilePath', this.constructor.name);
        this.logger = patchInject(logger, SoloLogger, this.constructor.name);
        this.configManager = patchInject(configManager, ConfigManager, this.constructor.name);
        if (!this.filePath || this.filePath === '')
            throw new MissingArgumentError('a valid filePath is required');
        const allowedKeys = ['userEmailAddress', 'deployments', 'currentDeploymentName', 'clusterContextMapping'];
        if (this.configFileExists()) {
            const fileContent = fs.readFileSync(filePath, 'utf8');
            const parsedConfig = yaml.parse(fileContent);
            for (const key in parsedConfig) {
                if (!allowedKeys.includes(key)) {
                    throw new SoloError(ErrorMessages.LOCAL_CONFIG_GENERIC);
                }
                this[key] = parsedConfig[key];
            }
            this.validate();
            this.skipPromptTask = true;
        }
    }
    validate() {
        const errors = validateSync(this, {});
        if (errors.length) {
            // throw the first error:
            const prop = Object.keys(errors[0]?.constraints);
            if (prop[0]) {
                throw new SoloError(errors[0].constraints[prop[0]]);
            }
            else {
                throw new SoloError(ErrorMessages.LOCAL_CONFIG_GENERIC);
            }
        }
        // Custom validations:
        if (!this.deployments[this.currentDeploymentName]) {
            throw new SoloError(ErrorMessages.LOCAL_CONFIG_CURRENT_DEPLOYMENT_DOES_NOT_EXIST);
        }
    }
    setUserEmailAddress(emailAddress) {
        this.userEmailAddress = emailAddress;
        this.validate();
        return this;
    }
    setDeployments(deployments) {
        this.deployments = deployments;
        this.validate();
        return this;
    }
    setCurrentDeployment(deploymentName) {
        this.currentDeploymentName = deploymentName;
        this.validate();
        return this;
    }
    setClusterContextMapping(clusterContextMapping) {
        this.clusterContextMapping = clusterContextMapping;
        this.validate();
        return this;
    }
    getCurrentDeployment() {
        return this.deployments[this.currentDeploymentName];
    }
    configFileExists() {
        return fs.existsSync(this.filePath);
    }
    async write() {
        const yamlContent = yaml.stringify({
            userEmailAddress: this.userEmailAddress,
            deployments: this.deployments,
            currentDeploymentName: this.currentDeploymentName,
            clusterContextMapping: this.clusterContextMapping,
        });
        await fs.promises.writeFile(this.filePath, yamlContent);
        this.logger.info(`Wrote local config to ${this.filePath}: ${yamlContent}`);
    }
    promptLocalConfigTask(k8) {
        const self = this;
        return {
            title: 'Prompt local configuration',
            skip: this.skipPromptTask,
            task: async (_, task) => {
                if (self.configFileExists) {
                    self.configManager.setFlag(flags.userEmailAddress, self.userEmailAddress);
                }
                const isQuiet = self.configManager.getFlag(flags.quiet);
                const contexts = self.configManager.getFlag(flags.context);
                const deploymentName = self.configManager.getFlag(flags.namespace);
                let userEmailAddress = self.configManager.getFlag(flags.userEmailAddress);
                let deploymentClusters = self.configManager.getFlag(flags.deploymentClusters);
                if (!userEmailAddress) {
                    if (isQuiet)
                        throw new SoloError(ErrorMessages.LOCAL_CONFIG_INVALID_EMAIL);
                    userEmailAddress = await flags.userEmailAddress.prompt(task, userEmailAddress);
                    self.configManager.setFlag(flags.userEmailAddress, userEmailAddress);
                }
                if (!deploymentName)
                    throw new SoloError('Namespace was not specified');
                if (!deploymentClusters) {
                    if (isQuiet) {
                        deploymentClusters = k8.getKubeConfig().getCurrentCluster().name;
                    }
                    else {
                        deploymentClusters = await flags.deploymentClusters.prompt(task, deploymentClusters);
                    }
                    self.configManager.setFlag(flags.deploymentClusters, deploymentClusters);
                }
                const parsedClusters = splitFlagInput(deploymentClusters);
                const deployments = {
                    [deploymentName]: { clusters: parsedClusters },
                };
                const parsedContexts = splitFlagInput(contexts);
                if (parsedContexts.length < parsedClusters.length) {
                    if (!isQuiet) {
                        const promptedContexts = [];
                        for (const cluster of parsedClusters) {
                            const kubeContexts = k8.getContexts();
                            const context = await flags.context.prompt(task, kubeContexts.map(c => c.name), cluster);
                            self.clusterContextMapping[cluster] = context;
                            promptedContexts.push(context);
                        }
                        self.configManager.setFlag(flags.context, promptedContexts.join(','));
                    }
                    else {
                        const context = k8.getKubeConfig().getCurrentContext();
                        for (const cluster of parsedClusters) {
                            self.clusterContextMapping[cluster] = context;
                        }
                        self.configManager.setFlag(flags.context, context);
                    }
                }
                else {
                    for (let i = 0; i < parsedClusters.length; i++) {
                        const cluster = parsedClusters[i];
                        self.clusterContextMapping[cluster] = parsedContexts[i];
                    }
                }
                self.userEmailAddress = userEmailAddress;
                self.deployments = deployments;
                self.currentDeploymentName = deploymentName;
                self.validate();
                await self.write();
            },
        };
    }
};
__decorate([
    IsEmail({}, {
        message: ErrorMessages.LOCAL_CONFIG_INVALID_EMAIL,
    }),
    __metadata("design:type", String)
], LocalConfig.prototype, "userEmailAddress", void 0);
__decorate([
    IsDeployments({
        message: ErrorMessages.LOCAL_CONFIG_INVALID_DEPLOYMENTS_FORMAT,
    }),
    IsNotEmpty(),
    IsObject({
        message: ErrorMessages.LOCAL_CONFIG_INVALID_DEPLOYMENTS_FORMAT,
    }),
    __metadata("design:type", Object)
], LocalConfig.prototype, "deployments", void 0);
__decorate([
    IsString({
        message: ErrorMessages.LOCAL_CONFIG_CURRENT_DEPLOYMENT_DOES_NOT_EXIST,
    }),
    IsNotEmpty(),
    __metadata("design:type", String)
], LocalConfig.prototype, "currentDeploymentName", void 0);
__decorate([
    IsClusterContextMapping({
        message: ErrorMessages.LOCAL_CONFIG_CONTEXT_CLUSTER_MAPPING_FORMAT,
    }),
    IsNotEmpty(),
    __metadata("design:type", Object)
], LocalConfig.prototype, "clusterContextMapping", void 0);
LocalConfig = __decorate([
    injectable(),
    __param(0, inject('localConfigFilePath')),
    __param(1, inject(SoloLogger)),
    __param(2, inject(ConfigManager)),
    __metadata("design:paramtypes", [String, SoloLogger,
        ConfigManager])
], LocalConfig);
export { LocalConfig };
//# sourceMappingURL=local_config.js.map