"use strict";
/*
 * Copyright © 2020 Atomist, Inc.
 *
 * 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.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.commandRequestParameterPromptFactory = exports.AtomistContinuationMimeType = exports.NoParameterPrompt = void 0;
const _ = require("lodash");
const handlerRegistrations_1 = require("../../api-helper/machine/handlerRegistrations");
/* tslint:disable:cyclomatic-complexity */
/**
 * No-op NoParameterPrompt implementation that never prompts for new parameters
 * @constructor
 */
const NoParameterPrompt = async () => ({});
exports.NoParameterPrompt = NoParameterPrompt;
exports.AtomistContinuationMimeType = "application/x-atomist-continuation+json";
/* tslint:disable:cyclomatic-complexity */
/**
 * Default ParameterPromptFactory that uses the WebSocket connection to send parameter prompts to the backend.
 * @param ctx
 */
function commandRequestParameterPromptFactory(ctx) {
    return async (parameters, options = {}) => {
        const trigger = ctx.trigger;
        const existingParameters = trigger.parameters;
        const newParameters = _.cloneDeep(parameters);
        // Find out if - and if - which parameters are actually missing
        let requiredMissing = false;
        const params = {};
        for (const parameter in parameters) {
            if (parameters.hasOwnProperty(parameter)) {
                const existingParameter = existingParameters.find(p => p.name === parameter);
                if (!existingParameter) {
                    // If required isn't defined it means the parameter is required
                    if (newParameters[parameter].required || newParameters[parameter].required === undefined) {
                        requiredMissing = true;
                    }
                }
                else {
                    // Do some validation against the rules
                    const parameterDefinition = newParameters[parameter];
                    const value = existingParameter.value;
                    // Force question
                    if (parameterDefinition.force) {
                        trigger.parameters = trigger.parameters.filter(p => p.name !== parameter);
                        requiredMissing = true;
                        continue;
                    }
                    // Verify pattern
                    if (parameterDefinition.pattern && !!value && !value.match(parameterDefinition.pattern)) {
                        requiredMissing = true;
                        continue;
                    }
                    // Verify minLength
                    const minLength = parameterDefinition.minLength || parameterDefinition.min_length;
                    if (minLength !== undefined && !!value && value.length < minLength) {
                        requiredMissing = true;
                        continue;
                    }
                    // Verify maxLength
                    const maxLength = parameterDefinition.maxLength || parameterDefinition.max_length;
                    if (maxLength !== undefined && !!value && value.length > maxLength) {
                        requiredMissing = true;
                        continue;
                    }
                    params[parameter] = existingParameter.value;
                    delete newParameters[parameter];
                }
            }
        }
        // If no parameters are missing we can return the already collected parameters
        if (!requiredMissing) {
            return params;
        }
        // Set up the thread_ts for this response message
        let threadTs;
        if (options.thread === true && !!trigger.source) {
            threadTs = _.get(trigger.source, "slack.message.ts");
        }
        else if (typeof options.thread === "string") {
            threadTs = options.thread;
        }
        const destination = _.cloneDeep(trigger.source);
        _.set(destination, "slack.thread_ts", threadTs);
        // Create a continuation message using the existing HandlerResponse and mixing in parameters
        // and parameter_specs
        const response = {
            api_version: "1",
            correlation_id: trigger.correlation_id,
            team: trigger.team,
            command: trigger.command,
            source: trigger.source,
            destinations: [destination],
            parameters: [...(trigger.parameters || []), ...(trigger.mapped_parameters || [])],
            auto_submit: !!options.autoSubmit ? options.autoSubmit : undefined,
            question: !!options.parameterStyle ? options.parameterStyle.toString() : undefined,
            parameter_specs: _.map(newParameters, (v, k) => ({
                name: k,
                description: v.description,
                required: v.required !== undefined ? v.required : true,
                pattern: v.pattern ? v.pattern.source : undefined,
                valid_input: v.validInput,
                max_length: v.maxLength,
                min_length: v.minLength,
                display_name: v.displayName,
                default_value: v.defaultValue,
                type: v.type,
            })),
            content_type: exports.AtomistContinuationMimeType,
        };
        await ctx.messageClient.respond(response);
        throw new handlerRegistrations_1.CommandListenerExecutionInterruptError(`Prompting for new parameters: ${_.map(newParameters, (v, k) => k).join(", ")}`);
    };
}
exports.commandRequestParameterPromptFactory = commandRequestParameterPromptFactory;
/* tslint:enable:cyclomatic-complexity */
//# sourceMappingURL=parameterPrompt.js.map