"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
const contracts_1 = require("../../../apis/codiac-api/contracts");
const contracts_2 = require("@codiac.io/codiac-common/contracts");
const command_base_exec_tenant_1 = require("../../../command-base-exec-tenant");
const prettify_1 = require("../../../prettify");
const cloud_resource_configurator_factory_1 = require("../../../uilogic/cloud-resource-configurator-factory");
const cloud_provider_contextualizer_1 = require("../../../uilogic/cloud-provider-contextualizer");
const image_registry_contextualizer_1 = require("../../../uilogic/image-registry-contextualizer");
const image_contextualizer_1 = require("../../../uilogic/image-contextualizer");
const pull_secret_1 = require("@codiac.io/codiac-domain/pull-secret");
const codiac_domain_1 = require("@codiac.io/codiac-domain");
const type_safety_utils_1 = require("../../../uilogic/type-safety-utils");
class ImageRegistryPullSecretSet extends command_base_exec_tenant_1.CommandBaseExecTenant {
    bootstrap() {
        super.bootstrap();
        cloud_provider_contextualizer_1.CloudProviderContextualizer.bootstrap(this.ioc);
        this.ioc.bind(image_registry_contextualizer_1.ImageRegistryContextualizer).toSelf();
        this.ioc.bind(image_contextualizer_1.ImageContextualizer).toSelf();
    }
    // --------------------------------------------------------------------
    // Lazy-loaded properties
    get uiRegistry() {
        if (this._uiRegistry_backer === undefined) {
            this._uiRegistry_backer = this.ioc.get(image_registry_contextualizer_1.ImageRegistryContextualizer);
        }
        return this._uiRegistry_backer;
    }
    // --------------------------------------------------------------------
    captureArgs() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { flags } = yield this.parse(ImageRegistryPullSecretSet);
            let partial = {};
            if (flags.registry)
                partial.regCode = flags.registry;
            partial.isPrimary = (flags.item !== "secondary");
            // secretRef fields are stashed on partial.secretRef
            let secretRef = {};
            if (flags.storeType)
                secretRef.type = type_safety_utils_1.TypeSafetyUtils.toEnum(contracts_1.KvpStoreTypesEnum, flags.storeType);
            if (flags.storeName)
                secretRef.name = flags.storeName;
            if (flags.name)
                secretRef.key = flags.name;
            if (flags.scope)
                secretRef.scope = type_safety_utils_1.TypeSafetyUtils.toEnum(codiac_domain_1.PullSecretScopesEnum, flags.scope);
            if (Object.keys(secretRef).length > 0)
                partial.secretRef = secretRef;
            return [partial, false];
        });
    }
    buildCandidate_silently(partial, rootMap) {
        var _a, _b, _c, _d, _e;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (!partial.regCode)
                throw new Error("A registry code must be set");
            if (!((_a = partial.secretRef) === null || _a === void 0 ? void 0 : _a.type))
                throw new Error("store type name must be set");
            if (!((_b = partial.secretRef) === null || _b === void 0 ? void 0 : _b.name))
                throw new Error("store name must be set");
            if (!((_c = partial.secretRef) === null || _c === void 0 ? void 0 : _c.key))
                throw new Error("secret name must be set");
            let registries = yield this._codiacApi.ImageRegistry.readMany({ all: true }, { throwNotFound: false });
            let registry = registries.find(r => r.code === partial.regCode);
            if (!registry) {
                throw new Error(`No ImageRegistry record currently exists with code: [${partial.regCode}]. You might need to check your spelling or capture your image registry.`);
            }
            let expiresOn = (_d = partial.secretRef.expiresOn) !== null && _d !== void 0 ? _d : new Date(Date.now() + (1000 * 60 * 60 * 24 * 365 * 5)); // Stub to 5 years
            let secretRef = new pull_secret_1.PullSecretRef(partial.secretRef.type, partial.secretRef.name, partial.secretRef.key, expiresOn);
            if (partial.secretRef.scope)
                secretRef.scope = partial.secretRef.scope;
            return { secretRef, isPrimary: (_e = partial.isPrimary) !== null && _e !== void 0 ? _e : true, regCode: partial.regCode, registry };
        });
    }
    buildCandidate_interactively(partial, takeDefaults, rootMap) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let registries = yield this._codiacApi.ImageRegistry.readMany({ all: true }, { throwNotFound: false });
            if (registries.length === 0)
                throw new Error(`Cannot set pull secrets: No image registries are defined yet.`);
            cloud_resource_configurator_factory_1.RegistryConfiguratorFactory.bootstrap(this.ioc);
            let p = {
                isPrimary: (_a = partial.isPrimary) !== null && _a !== void 0 ? _a : true,
                regCode: partial.regCode,
                storeType: (_b = partial.secretRef) === null || _b === void 0 ? void 0 : _b.type,
                storeName: (_c = partial.secretRef) === null || _c === void 0 ? void 0 : _c.name,
                secretName: (_d = partial.secretRef) === null || _d === void 0 ? void 0 : _d.key,
                expiresOn: (_e = partial.secretRef) === null || _e === void 0 ? void 0 : _e.expiresOn,
                scope: (_g = (_f = partial.secretRef) === null || _f === void 0 ? void 0 : _f.scope) !== null && _g !== void 0 ? _g : codiac_domain_1.PullSecretScopesEnum.everywhere,
                providerSubscriptionId: undefined,
            };
            let secretStores;
            let candidate;
            let confirmed;
            while (!confirmed) {
                console.clear();
                // REGISTRY  (we've already gated this method for registries.length > 0)
                let selectedRegistry;
                let keepRegistry = (p.regCode === undefined) ? false : yield this._ui.promptConfirm("keepRegistry", `${this._styler.hilite(p.regCode)} pull secret`);
                if (!keepRegistry) {
                    selectedRegistry = (yield this.uiRegistry.promptForExistingRegistry(contracts_1.PackageType.container, false, registries));
                    p.regCode = selectedRegistry.code;
                    p.providerSubscriptionId = selectedRegistry.subscriptionId;
                }
                // PRIMARY/SECONDARY
                p.isPrimary = (_h = p.isPrimary) !== null && _h !== void 0 ? _h : true;
                let keepPrimary = yield this._ui.promptConfirm("keepPrimary", `${this._styler.hilite(p.isPrimary ? "Primary" : "Secondary")} pull secret`);
                if (!keepPrimary) {
                    p.isPrimary = (yield this._ui.promptSelect("isPrimary", "Which pull secret?: ", [{ name: "Primary", value: true }, { name: "Secondary", value: false }]));
                }
                // SCOPE
                let keepScope = yield this._ui.promptConfirm("keepScope", `Scope: ${this._styler.hilite(p.scope)}`);
                if (!keepScope) {
                    let scopeChoices = [
                        { name: codiac_domain_1.PullSecretScopesEnum.everywhere.concat(" (always implement this)"), value: codiac_domain_1.PullSecretScopesEnum.everywhere },
                        { name: codiac_domain_1.PullSecretScopesEnum.unmatchingSubx.concat(" (only when registry and cluster subscriptions differ)"), value: codiac_domain_1.PullSecretScopesEnum.unmatchingSubx }
                    ];
                    const selected = (yield this._ui.promptSelect("scope", "Scope: ", scopeChoices));
                    p.scope = type_safety_utils_1.TypeSafetyUtils.toEnum(codiac_domain_1.PullSecretScopesEnum, selected);
                }
                // SECRET STORE
                let keepSecret = false;
                while (keepSecret === false) {
                    let keepStore = (p.storeName === undefined) ? false : yield this._ui.promptConfirm("keepStore", `Secret Store: ${this._styler.hilite(p.storeName)}`);
                    if (!keepStore) {
                        let original = `${p.storeType}|${p.storeName}`;
                        // Lazy-load existing secret stores
                        secretStores = secretStores !== null && secretStores !== void 0 ? secretStores : yield this._codiacApi.KvpStoreDef.readMany({ all: true }, { throwNotFound: false });
                        // limit generic kvp stores to only secret stores...
                        secretStores = secretStores.filter(s => [contracts_1.KvpStoreTypesEnum.awsKeyVault, contracts_1.KvpStoreTypesEnum.azKeyVault].map(x => x.toString()).includes(s.type));
                        if (secretStores.length === 0)
                            throw new Error(`Cannot define pull secret: No secret stores have been declared.`);
                        let storeChoices = secretStores.map((s, n) => { return { name: `${s.name} (${s.type})`, value: n }; });
                        let index = (yield this._ui.promptSelect("secretStore", "Secret Store?: ", storeChoices));
                        p.storeName = secretStores[index].name;
                        p.storeType = secretStores[index].type;
                        p.providerSubscriptionId = secretStores[index].subscriptionId;
                        // Reset the secret name if we changed the secret store
                        if (`${p.storeType}|${p.storeName}` !== original) {
                            p.secretName = undefined;
                        }
                    }
                    // SECRET
                    keepSecret = (p.secretName === undefined) ? false : yield this._ui.promptConfirm("keepSecret", `Secret name: ${this._styler.hilite(p.secretName)}`);
                    if (!keepSecret) {
                        this._ui.startSpinner("Loading list of secrets...");
                        let secrets = [];
                        if (p.storeType != undefined && p.storeName != undefined) {
                            let def = {
                                name: p.storeName,
                                type: p.storeType,
                                subscriptionId: p.providerSubscriptionId
                            };
                            let keysRes = yield this.genRelayClient.Call.postReadVaultStoreKeys({ kvpStoreDef: def });
                            if (keysRes.error)
                                throw keysRes.error;
                            secrets = (_j = keysRes.output) !== null && _j !== void 0 ? _j : [];
                        }
                        this._ui.stopSpinner(`found ${secrets.length}`);
                        let origSecretName = p.secretName;
                        p.secretName = undefined;
                        if (secrets.length > 0) {
                            let choices = secrets.map(s => { return { name: s, value: s }; });
                            p.secretName = (yield this._ui.promptSelect("secretName", "Secret name: ", choices));
                            keepSecret = true;
                        }
                        else {
                            this._ui.userMessage(`No secrets exist in [${p.storeName}]`);
                            keepSecret = false;
                        }
                    }
                }
                let secretRef = new pull_secret_1.PullSecretRef(p.storeType, p.storeName, p.secretName, p.expiresOn);
                if (p.scope == codiac_domain_1.PullSecretScopesEnum.unmatchingSubx)
                    secretRef.scope = p.scope;
                let registry = registries.find(r => r.code === p.regCode);
                candidate = { secretRef, isPrimary: p.isPrimary, regCode: p.regCode, registry };
                this._ui.userMessage((0, prettify_1.prettify)(candidate));
                this._ui.userMessage(`You are about to set the ${candidate.isPrimary ? "primary" : "secondary"} pull secret for ${this._styler.bold(this._styler.hilite(candidate.regCode))} [Tenant: ${this._userCntx.currentTenantCode}].`);
                confirmed = yield this._ui.promptConfirm("confirmPullSecret", "Continue?", false);
            }
            if (candidate === undefined)
                throw new Error("No PullSecret was defined.");
            return candidate;
        });
    }
    buildCommandString(candidate, cmd) {
        cmd.push("--registry", candidate.regCode);
        if (!candidate.isPrimary)
            cmd.push("--item", "secondary");
        cmd.push("--storeType", candidate.secretRef.type);
        cmd.push("--storeName", candidate.secretRef.name);
        cmd.push("--name", candidate.secretRef.key);
        cmd.push("--silent");
        return cmd;
    }
    executeTask(candidate) {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let pullSecretField = candidate.isPrimary ? "pullSecret" : "pullSecretSecondary";
            let patchSpec = {
                id: candidate.registry.id,
                operations: [
                    {
                        op: contracts_2.patchOperationType.replace,
                        path: pullSecretField,
                        value: candidate.secretRef
                    }
                ]
            };
            let result = yield this._codiacApi.ImageRegistry.tryPatch(patchSpec);
            if (result.success) {
                this._ui.userMessage(`Successfully updated ${pullSecretField} on ${candidate.registry.type} image registry [${this._styler.hilite(candidate.registry.code)}]`);
            }
            else if (result.error) {
                this._ui.userMessage(`${this._styler.colorCritical("Error")} updating ${pullSecretField} on ${candidate.registry.type} image registry [${candidate.registry.code}]: ${result.error.name} ${(_a = result.error.message) !== null && _a !== void 0 ? _a : result.error.stack}`);
            }
        });
    }
}
exports.default = ImageRegistryPullSecretSet;
ImageRegistryPullSecretSet.description = 'Upserts the primary and secondary pull secret references for the given container registry.';
ImageRegistryPullSecretSet.aliases = ['pullsecret'];
ImageRegistryPullSecretSet.flags = {
    help: core_1.Flags.help({ char: 'h' }),
    registry: core_1.Flags.string({ char: 'r', required: false, exclusive: ["kit"], description: "The container registry in which the image exists (defaults to docker hub)." }),
    item: core_1.Flags.string({ char: 'f', options: ["primary", "secondary"], required: false, default: "primary", description: "Applies the command to either the primary (default) or secondary secret for the image registry." }),
    scope: core_1.Flags.string({ options: Object.values(codiac_domain_1.PullSecretScopesEnum), required: false, description: "Applicability of the pullsecret. Allows for other authorization methods when the cluster and image registry are in the same subscription." }),
    storeType: core_1.Flags.string({ char: 't', required: false, options: Object.values(contracts_1.KvpStoreTypesEnum), description: "The type of secret store containing the actual pull secrets." }),
    storeName: core_1.Flags.string({ char: 's', required: false, description: "The name of the secret store containing the actual pull secrets." }),
    name: core_1.Flags.string({ char: 'n', required: false, description: "The name of the secret within the secret store." }),
    silent: core_1.Flags.boolean({ exclusive: ["echo", "to-script"], description: 'Executes without any user interaction; fails on missing or invalid arguments.' }),
    echo: core_1.Flags.boolean({ exclusive: ["to-script", "silent"], description: 'Renders the equivalent non-interactive command for future use before executing.' }),
    "to-script": core_1.Flags.boolean({ exclusive: ["echo", "silent"], description: 'Renders the equivalent non-interactive command without executing it.' }),
};
ImageRegistryPullSecretSet.args = {};
//# sourceMappingURL=set.js.map