"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
const _ = require("lodash");
const contracts_1 = require("@codiac.io/codiac-common/contracts");
const contracts_2 = require("../../../apis/codiac-api/contracts");
const command_base_exec_1 = require("../../../command-base-exec");
const config_ui_utils_1 = require("../../../uilogic/config-ui-utils");
const list_1 = require("./list");
const type_safety_utils_1 = require("../../../uilogic/type-safety-utils");
class AssetProbeDelete extends command_base_exec_1.CommandBaseExec {
    captureArgs() {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { args, flags } = yield this.parse(AssetProbeDelete);
            let partial = {};
            if (flags.enterprise)
                partial.enterprise = flags.enterprise;
            if (flags.id) {
                partial.ids = [];
                for (let idspec of flags.id)
                    partial.ids.push(...idspec.split(","));
            }
            else {
                partial.descriptor = {};
                if (flags.asset)
                    partial.descriptor.asset = flags.asset;
                if (flags.usage)
                    partial.descriptor.usage = type_safety_utils_1.TypeSafetyUtils.toEnum(contracts_2.ProbeUsageTypesEnum, flags.usage); // <--- the flags def's options constraint guarantees valid entry here.
                if (flags["version-range"])
                    partial.descriptor.versionRange = flags["version-range"];
            }
            // ---------------------------------------------------------------
            // TODO: move everything from here down into the base class
            // ---------------------------------------------------------------
            const interactionMode = (this.pipedInput) ? config_ui_utils_1.InteractionModes.silent : (_b = (_a = undefined !== null && undefined !== void 0 ? undefined : (flags.echo ? config_ui_utils_1.InteractionModes.echo : undefined)) !== null && _a !== void 0 ? _a : (flags["to-script"] ? config_ui_utils_1.InteractionModes.toscript : undefined)) !== null && _b !== void 0 ? _b : (flags.silent ? config_ui_utils_1.InteractionModes.silent : undefined);
            const takeDefaults = flags['take-defaults'];
            return [partial, interactionMode, takeDefaults];
        });
    }
    buildCandidate_silently(partial, rootMap) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let candidate;
            if (partial.ids != undefined) {
                candidate = { enterprise: partial.enterprise, ids: partial.ids };
            }
            else {
                // 1) Check for missing input
                if (((_a = partial.descriptor) === null || _a === void 0 ? void 0 : _a.asset) == undefined)
                    throw new Error("Missing asset (please set the --asset flag).");
                if (((_b = partial.descriptor) === null || _b === void 0 ? void 0 : _b.usage) == undefined)
                    throw new Error("Missing usage type (please set the --usage flag).");
                // 2) validate before we fetch (Check for existence)
                const ent = rootMap.enterprises.find(e => e.name == candidate.enterprise);
                if (!ent)
                    throw new Error("Invalid enterprise: not found.");
                const asset = ent.assets.find(a => { var _a; return a.name == ((_a = partial.descriptor) === null || _a === void 0 ? void 0 : _a.asset); });
                if (!asset)
                    throw new Error("Invalid asset: not found.");
                // 3) Fetch the id
                let req = {
                    enterprise: partial.enterprise,
                    asset: partial.descriptor.asset,
                    // usage: partial.descriptor.usage  // <-- not in the criteria yet
                    // versionRange: partial.descriptor.versionRange  // <-- not in the criteria yet
                };
                let list = yield this._codiacApi.Probe.readMany(req);
                // Build local query (due to weak criteria obj)...
                let filters = [];
                /** User explicitly instructed us to force the delete over all version ranges. */
                const forAllVersions = Boolean(partial.descriptor.versionRange != AssetProbeDelete.VERSION_RANGE_WILDCARD);
                if (partial.descriptor.usage) {
                    filters.push(x => { var _a; return x.type == ((_a = partial.descriptor) === null || _a === void 0 ? void 0 : _a.usage); });
                }
                if (partial.descriptor.versionRange && !forAllVersions) {
                    filters.push(x => { var _a; return x.versionRange == ((_a = partial.descriptor) === null || _a === void 0 ? void 0 : _a.versionRange); });
                }
                list = list.filter(x => list_1.AssetProbeUiLogic.checkAll(x, filters));
                if (list.length > 0) {
                    let found;
                    if (list.length > 1 /* && !forAllVersions */) {
                        // throw new Error("More than one probe definition was found for various version ranges.  You will need to specify a specific version range or a wildcard * to delete.");
                        throw new Error("More than one probe definition was found for various version ranges.  You will need to specify a specific version range to delete.");
                    }
                    else {
                        found = list[0];
                    }
                    candidate = {
                        enterprise: found.enterprise,
                        descriptor: {
                            asset: found.asset,
                            usage: found.type,
                            versionRange: (list.length > 1 && forAllVersions) ? AssetProbeDelete.VERSION_RANGE_WILDCARD : found.versionRange
                        },
                        ids: list.map(x => x.id)
                    };
                }
                else {
                    throw new Error("Probe not found (Please check the Probe list with: cod asset probe list).");
                }
            }
            return candidate;
        });
    }
    buildCandidate_interactively(partial, rootMap, takeDefaults) {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            // let list = await this._codiacApi.Probe.readMany({ all: true, enterprise: partial.enterprise });
            // MarkStarthere("get these from the rootmap instead...")
            let ent = rootMap.enterprises.find(e => e.name == partial.enterprise);
            if (!ent)
                throw new Error("Enterprise not found."); // this will never happen, but it stiffens our ent object.
            let list = [];
            _.orderBy(ent.assets, a => a.name).forEach(a => { var _a; return list.push(...((_a = a.probes) !== null && _a !== void 0 ? _a : [])); });
            if (list.length == 0) {
                this._ui.userMessage("There are no probes in the enterprise ".concat(partial.enterprise, ". No work to do."));
                this.exit(0);
                return undefined; // this line wont get hit - it's here for ts consistency       
            }
            // 1) Force focus onto a single asset
            let assetName;
            let assetChanged;
            let assetType;
            [assetName, assetChanged, assetType] = yield this.rootMapUtils.promptForAsset(ent.assets.filter(a => { var _a, _b; return ((_b = (_a = a.probes) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0; }), (_a = partial.descriptor) === null || _a === void 0 ? void 0 : _a.asset, true);
            if (!partial.descriptor)
                partial.descriptor = {};
            partial.descriptor.asset = assetName;
            // 2) Select the probe
            let selected;
            let found = list.filter(obj => {
                var _a, _b, _c;
                if (partial.ids) {
                    return obj.id && partial.ids.includes(obj.id);
                }
                else {
                    let include = true;
                    if ((_a = partial.descriptor) === null || _a === void 0 ? void 0 : _a.asset)
                        include = include && (obj.asset == partial.descriptor.asset);
                    if ((_b = partial.descriptor) === null || _b === void 0 ? void 0 : _b.usage)
                        include = include && (obj.type == partial.descriptor.usage);
                    if ((_c = partial.descriptor) === null || _c === void 0 ? void 0 : _c.versionRange)
                        include = include && (obj.versionRange == partial.descriptor.versionRange);
                    return include;
                }
            });
            if (found.length == 0) {
                this._ui.userMessage("No Probes found.  No work was done.");
                this.exit(0);
                return undefined; // this line wont get hit - it's here for ts consistency       
            }
            else if (found.length == 1) {
                selected = found[0];
            }
            let keep = false; // takeDefaults
            if (selected) {
                keep = yield this._ui.promptConfirm("confirmEntity", "Delete: ".concat(list_1.AssetProbeUiLogic.displayNameFor(selected, this._styler)), false);
            }
            if (selected && !keep && list.length == 1) {
                this._ui.userMessage("There are no other Probes.  No work was done.");
                this.exit(0);
                return undefined; // this line wont get hit - it's here for ts consistency 
            }
            if (!selected || !keep) {
                let choices = list.map(obj => ({ name: list_1.AssetProbeUiLogic.displayNameFor(obj, this._styler, false), value: obj.id }));
                let selectedId = yield this._ui.promptSelect("selectEntity", "Delete: ", choices, false, false);
                selected = list.find(x => x.id == selectedId); // assertion ok - the choices came from this list
            }
            // 3) Assemble the final request
            let candidate = {
                enterprise: selected.enterprise,
                id: selected.id
            };
            // Only populate the descriptor if the user enter them originally as command params. 
            // (For use in building the command string; this is how we determine 
            // if they came in with an id or with descriptor args).
            if (!partial.ids) {
                candidate.descriptor = {
                    asset: selected.asset,
                    usage: selected.type,
                    versionRange: selected.versionRange
                };
            }
            return candidate;
        });
    }
    buildCommandString(candidate, cmd) {
        cmd.push("--enterprise", candidate.enterprise);
        if (candidate.descriptor) {
            // DEVNOTE: Assertions ok here bc we already guaranteed that descriptor is all or nothing.
            cmd.push("--asset", candidate.descriptor.asset);
            cmd.push("--usage", candidate.descriptor.usage.toString());
            if (candidate.descriptor.versionRange)
                cmd.push("--version-range", candidate.descriptor.versionRange);
        }
        else {
            if (candidate.ids)
                cmd.push("--id", candidate.ids.join(",")); // this if stmt will always be true.
        }
        cmd.push("--silent");
        return cmd;
    }
    executeTask(candidate) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let delRes = new contracts_1.BatchResult(false);
            if (candidate.ids) {
                this._ui.startSpinner("Removing Probe definition");
                // TODO: Verify that embedding is fulfilled on DeleteWhere, so we can use this instead... 
                // delRes = await this._codiacApi.Probe.tryDeleteWhere({ ids: candidate.ids });
                delRes = yield this.batchDelete(candidate.ids);
                this._ui.stopSpinner(delRes.success ? "Completed" : "Failed");
                if (delRes.error)
                    throw delRes.error;
                if (delRes.success) {
                    if (delRes.successes && (delRes.successes.length > 0)) {
                        this._ui.userMessage(this._styler.colorGood("Success!").concat(" Deleted ", delRes.successes.length.toString(), " probes."));
                    }
                    else {
                        this._ui.userMessage("No probes found to delete. No work was done.");
                    }
                }
                else if (delRes.failures && (delRes.failures.length > 0)) {
                    let msg = [];
                    msg.push("Deleted ", ((_b = (_a = delRes.successes) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0).toString());
                    msg.push("failed deleting ", delRes.failures.length.toString());
                    this._ui.userMessage(msg.join(" and ").concat(" probes."));
                    delRes.failures
                        .filter(fail => fail.message != undefined)
                        .forEach(fail => { var _a; return this._ui.userMessage((_a = fail.message) !== null && _a !== void 0 ? _a : ""); });
                }
                else {
                    // Ensures all cases are rendered (regardless of whether batch returns success or fail on no work done)
                    this._ui.userMessage("No work to do.");
                }
            }
        });
    }
    /** TEMP!! until we verify that deleteWhere properly fulfills embeds.  */
    batchDelete(ids) {
        var _a, _b, _c, _d;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let delRes = new contracts_1.BatchResult(false);
            for (let idToDelete of ids) {
                const resEach = yield this._codiacApi.Probe.tryDelete({ id: idToDelete });
                if (resEach.success && resEach.output) {
                    if (delRes.successes == undefined)
                        delRes.successes = [];
                    delRes.successes.push(resEach.output);
                }
                else {
                    if (delRes.failures == undefined)
                        delRes.failures = [];
                    delRes.failures.push(resEach);
                }
            }
            delRes.success = Boolean(((_b = (_a = delRes.failures) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) == 0) && Boolean(((_d = (_c = delRes.successes) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0) > 0);
            return delRes;
        });
    }
}
exports.default = AssetProbeDelete;
/** Value to specify for version range to delete probes for all version ranges. */
AssetProbeDelete.VERSION_RANGE_WILDCARD = "*";
AssetProbeDelete.description = 'Removes an asset probe definition.  DOES NOT running assets; assets will need to be redeployed for this change to affect their runtime instances.';
AssetProbeDelete.examples = [
    '<%= config.bin %> <%= command.id %>',
];
AssetProbeDelete.flags = {
    enterprise: core_1.Flags.string({ char: 'e', description: 'The name of the enterprise on which to apply this naming strategy. NOTE: You can leave this blank if there is only one.' }),
    asset: core_1.Flags.string({ char: 'a', exclusive: ["id"], required: false, description: 'The asset that owns the probe.' }),
    usage: core_1.Flags.string({ char: 'u', description: 'The diagnostic purpose the probe serves.', options: [contracts_2.ProbeUsageTypesEnum.readiness, contracts_2.ProbeUsageTypesEnum.liveness, contracts_2.ProbeUsageTypesEnum.startup] }),
    "version-range": core_1.Flags.string({ char: 'v', required: false, description: "The semantic version range of the asset in which the probe definition applies. You can use the wildcard * to force delete probes for all version ranges. (Note: if specifying, best to select this one interactively if applicable, because you cannot just make one up, it must match the exact range on the the probe record." }),
    id: core_1.Flags.string({ multiple: true, exclusive: ["enterprise", "asset"], description: "The system id of the probe itself. Specify multiple ids by separating with commands and/or adding this flag multiple times.  You can enter this parameter instead of the other probe descriptors." }),
    // TODO: Move these into the base class
    silent: core_1.Flags.boolean({ exclusive: ["echo", "to-script"], description: 'Non-Interactive mode; executes without any user interaction and fails on any missing or invalid arguments.' }),
    echo: core_1.Flags.boolean({ exclusive: ["to-script", "silent"], description: 'Echo interaction mode; renders the equivalent non-interactive cli command for future use before final execution.' }),
    "to-script": core_1.Flags.boolean({ exclusive: ["echo", "silent"], description: 'Toscript interaction mode; renders the equivalent non-interactive cli command WITHOUT any execution.' }),
    "take-defaults": core_1.Flags.boolean({ exclusive: ["silent"], description: "Setting this to true prevents prompting for confirmation on parameters that were passed in or were automatically set to default values (Irrelevant in --silent mode).  This behavior does NOT apply to scenarios that the command needs to override invalid user input; such cases will always prompt for confirmation.  eg: when no argument was provided for file or type, and only one exists, the system will render the autoselected file unless this flag is set." })
};
AssetProbeDelete.args = {};
//# sourceMappingURL=delete.js.map