"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PROMPT_ME_DESIGNATOR = void 0;
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
const _ = require("lodash");
const contracts_1 = require("@codiac.io/codiac-common/contracts");
const command_base_enterprise_1 = require("../../../command-base-enterprise");
const prettify_1 = require("../../../prettify");
// const { selectFiles, COMPLETED, CANCELLED } = require('select-files-cli');  // gd js wo ts...
// const { selectFiles, COMPLETED, CANCELLED } = require('../../uilogic/file-selector');  // gd js wo ts...
/** The value provided as input that indicates
 * a user's desire to be prompted with a list from which choose the value(s),
 * instead of entering them manually or taking a default. */
exports.PROMPT_ME_DESIGNATOR = "?";
class AssetVolumeCreate extends command_base_enterprise_1.CommandBaseEnterprise {
    run() {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            this.bootstrap();
            const { args, flags } = yield this.parse(AssetVolumeCreate);
            (_a = this._relayContainer) === null || _a === void 0 ? void 0 : _a.ready$.subscribe((ready) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                var _b, _c, _d, _e, _f;
                try {
                    this._userCntx = yield this.establishTenantContext(this._userCntx);
                    let rootMap = yield this.getRootMap();
                    const interactionMode = this.getInteractionMode(flags.silent, flags.echo, flags['to-script']);
                    let enterprise = (yield this.establishEnterpriseContext(rootMap, flags.enterprise, interactionMode)).enterprise;
                    _.remove(rootMap.enterprises, e => e.name != enterprise.name); // trim down to match legacy conditions
                    let aCntx = yield this.establishAssetContext(enterprise, true);
                    let asset = enterprise.assets.find(a => a.name == aCntx[0]);
                    let folderRes;
                    // Silent mode (throws if invalid)
                    if (flags.silent) {
                        if (!args.mountPath) {
                            throw new Error(`No mount path was provided.`);
                        }
                        else if (!flags.name) {
                            throw new Error(`No name was provided for the volume mount.`);
                        }
                        folderRes = {
                            path: args.mountPath,
                            name: flags.name
                        };
                        if (flags.description)
                            folderRes.description = flags.description;
                    }
                    else {
                        // User mode (prompts if invalid)
                        let mountPath = args.mountPath;
                        let name;
                        let desc = flags.description;
                        let confirmed = false;
                        while (!confirmed || !folderRes) {
                            let pathRevisit = (folderRes != undefined); // revisit if we're looping back by denying the confirm
                            let nameRevisit = (folderRes != undefined); // revisit if we're looping back by denying the confirm
                            let descRevisit = (folderRes != undefined); // revisit if we're looping back by denying the confirm
                            // PROMPT FOR ANOTHER MOUNT PATH (if this one is already in use)
                            let existingByPath = (_b = asset === null || asset === void 0 ? void 0 : asset.reservedFolders) === null || _b === void 0 ? void 0 : _b.find(f => f.path == mountPath);
                            while (existingByPath || mountPath == undefined || pathRevisit) {
                                pathRevisit = false;
                                let defaultPath = mountPath;
                                if (existingByPath) {
                                    this._ui.userMessage(`The path [${mountPath}] is already in use by the volume mount [${existingByPath.name}] )("${existingByPath.description}").`);
                                    defaultPath = undefined; // Suggest only valid defaults
                                }
                                mountPath = (yield this._ui.prompt("mountPath", `Enter a mountPath for the volume: `, true, defaultPath));
                                existingByPath = (_c = asset === null || asset === void 0 ? void 0 : asset.reservedFolders) === null || _c === void 0 ? void 0 : _c.find(f => f.path == mountPath);
                            }
                            // PROMPT FOR ANOTHER NAME (if missing or this one is already in use))
                            let defaultName;
                            let existingByName;
                            if (name == undefined) {
                                if (flags.name) {
                                    name = flags.name;
                                    existingByName = (_d = asset.reservedFolders) === null || _d === void 0 ? void 0 : _d.find(f => f.name == name);
                                }
                                else {
                                    let ptn = /(^[\/\s]+|[\/\s]+$)/g; // finds leading and trailing spaces and path chars.
                                    let defaultCandidate = mountPath
                                        .replace(ptn, "") /* trims spaces and path chars ("/") off the start and end of the string. */
                                        .replace(/\//g, "-"); /* replaces path chars with dashes */
                                    if (!((_e = asset.reservedFolders) === null || _e === void 0 ? void 0 : _e.find(f => f.name == name))) {
                                        defaultName = defaultCandidate; // only suggest a valid default that doesnt already exist.
                                    }
                                }
                            }
                            while (name == undefined || existingByName || nameRevisit) {
                                if (name == undefined || nameRevisit) {
                                    name = (yield this._ui.prompt("name", `Refer to this mount folder as: `, true, name !== null && name !== void 0 ? name : defaultName));
                                }
                                nameRevisit = false;
                                existingByName = (_f = asset.reservedFolders) === null || _f === void 0 ? void 0 : _f.find(f => f.name == name);
                                if (existingByName) {
                                    this._ui.userMessage(`The name [${name}] already refers to the mount folder [${existingByName.path}] ("${existingByName.description}").`);
                                    name = undefined;
                                }
                            }
                            // let existingByName = asset.reservedFolders?.find(f => f.name == name);
                            // while (existingByName) {
                            //   this._ui.userMessage(`The name [${name}] already refers to the mount folder [${existingByName.path}] ("${existingByName.description}").`);
                            //   name = (await this._ui.prompt("name", `Refer to this mount folder as: `))!;
                            //   existingByName = asset?.reservedFolders?.find(f => f.name == name);
                            // }
                            // PROMPT FOR DESCRIPTION
                            if (desc == undefined || descRevisit) {
                                descRevisit = false;
                                desc = (yield this._ui.prompt("desc", `Describe the intended purpose for this volume mount: `, false, desc));
                            }
                            // ASSEMBLE and CONFIRM
                            folderRes = {
                                name: name,
                                path: mountPath
                            };
                            if (desc)
                                folderRes.description = desc;
                            this._ui.userMessage((0, prettify_1.prettify)(folderRes));
                            confirmed = yield this._ui.promptConfirm("confirm", "You are about to set this path as a volume mount.  Continue?", true);
                        }
                    }
                    let resultPatch = yield this.writeVolumeMountToAsset(enterprise.name, asset, folderRes);
                    if (resultPatch.success) {
                        this.logger.notice(`Successfully saved volume mount [${folderRes.name}] with path [${folderRes.path}] to asset [${asset.enterprise}/${asset.name}]`);
                        this._ui.userMessage(`Successfully saved volume mount [${folderRes.name}] with path [${folderRes.path}] to asset [${asset.enterprise}/${asset.name}]`);
                    }
                    else if (resultPatch.error) {
                        this.logger.error(`Error saving volume mount [${folderRes.name}] with path [${folderRes.path}] to asset [${asset.enterprise}/${asset.name}]: ${resultPatch.message || ""}; ${resultPatch.error.message || resultPatch.error.stack}`);
                        this._ui.userMessage(`Error saving volume mount [${folderRes.name}] with path [${folderRes.path}] to asset [${asset.enterprise}/${asset.name}]: ${resultPatch.message || ""}; ${resultPatch.error.message || resultPatch.error.stack}`);
                    }
                    else {
                        this.logger.warn(`Failed without error to save volume mount [${folderRes.name}] with path [${folderRes.path}] to asset [${asset.enterprise}/${asset.name}]: ${resultPatch.message || ""}`);
                        this._ui.userMessage(`Failed without error to save volume mount [${folderRes.name}] with path [${folderRes.path}] to asset [${asset.enterprise}/${asset.name}]: ${resultPatch.message || ""}`);
                    }
                }
                catch (err) {
                    this.handleError(err);
                }
                finally {
                    yield this.closeConnections();
                    return;
                }
            }));
        });
    }
    writeVolumeMountToAsset(enterprise, asset, folderRes) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                var _a;
                let result = new contracts_1.SingleResult(false);
                try {
                    if (!asset.reservedFolders)
                        asset.reservedFolders = [];
                    (_a = asset.reservedFolders) === null || _a === void 0 ? void 0 : _a.push(folderRes); // we already validated that this folderRes doesnt already exist in the asset's reservedFolders
                    asset.reservedFolders = _.sortBy(asset.reservedFolders, f => f.path);
                    // Commented out bc patching like this could possibly lead to dups in the reservedFolders.
                    // let ops: patchOperation[] = [];
                    // ops.push(new patchOperation(patchOperationType.add, "reservedFolders", folderRes));  // adds a new element to the reservedFolders array
                    // let patch = new PatchSpecForOne(asset.id!, ops);
                    // result = await this._codiacApi.Asset.tryPatch(patch);
                    // OR we could do this instead - this would be more idempotent
                    this.logger.trace("Asset update", asset);
                    result = yield this._codiacApi.Asset.tryUpdate(asset);
                }
                catch (err) {
                    result.message = `Error updating asset ${asset.name}: ${err.message}`;
                    result.error = err;
                }
                finally {
                    resolve(result);
                }
            }));
        });
    }
}
exports.default = AssetVolumeCreate;
AssetVolumeCreate.description = 'Declares a named path for mounting a volume to instances of the asset.';
AssetVolumeCreate.aliases = ['asset:vol:create', 'asset:vol:add', 'asset:volume:add'];
AssetVolumeCreate.dependsOn = ["name"];
AssetVolumeCreate.flags = {
    help: core_1.Flags.help({ char: 'h' }),
    name: core_1.Flags.string({ char: 'n', required: false, description: "Moniker for identifying, retrieving, and accessing this folder mapping.  Must be unique for the asset." }),
    asset: core_1.Flags.string({ char: 'a', required: false, description: "The name of the asset to which this volume is being applied." }),
    enterprise: core_1.Flags.string({ char: 'e', required: false, description: '(required only if more than one enterprise exists) The name of the enterprise to which the asset belongs.' }),
    description: core_1.Flags.string({ char: 'd', required: false, description: 'Any notes or other information to help clarify the intended purpose of this folder, to assist during the configuration phase when assigning an actual physical file store to it.' }),
    silent: core_1.Flags.boolean({ char: 'y', dependsOn: AssetVolumeCreate.dependsOn, required: false, description: `(Optional: defaults to false) Prevents confirmations of user-values that are remembered from prior runs. Requires: ${AssetVolumeCreate.dependsOn}` })
};
AssetVolumeCreate.args = {
    mountPath: core_1.Args.string({ required: false, description: 'Fully qualified mounting path, inside the container, of the folder being mapped as a volume.  Must be unique for the asset.' })
};
//# sourceMappingURL=create.js.map