text: "use strict";
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.prepareStepArgs = exports.isStepEvent = exports.processStepMiddleware = exports.validate = exports.WorkflowStep = void 0;
  const process_1 = require("./middleware/process");
  const errors_1 = require("./errors");
  /** Constants */
  const VALID_PAYLOAD_TYPES = new Set(['workflow_step_edit', 'workflow_step', 'workflow_step_execute']);
  /** Class */
  class WorkflowStep {
      constructor(callbackId, config) {
          validate(callbackId, config);
          const { save, edit, execute } = config;
          this.callbackId = callbackId;
          this.save = Array.isArray(save) ? save : [save];
          this.edit = Array.isArray(edit) ? edit : [edit];
          this.execute = Array.isArray(execute) ? execute : [execute];
      }
      getMiddleware() {
          return async (args) => {
              if (isStepEvent(args) && this.matchesConstraints(args)) {
                  return this.processEvent(args);
              }
              return args.next();
          };
      }
      matchesConstraints(args) {
          return args.payload.callback_id === this.callbackId;
      }
      async processEvent(args) {
          const { payload } = args;
          const stepArgs = prepareStepArgs(args);
          const stepMiddleware = this.getStepMiddleware(payload);
          return processStepMiddleware(stepArgs, stepMiddleware);
      }
      getStepMiddleware(payload) {
          switch (payload.type) {
              case 'workflow_step_edit':
                  return this.edit;
              case 'workflow_step':
                  return this.save;
              case 'workflow_step_execute':
                  return this.execute;
              default:
                  return [];
          }
      }
  }
  exports.WorkflowStep = WorkflowStep;
  /** Helper Functions */
  function validate(callbackId, config) {
      // Ensure callbackId is valid
      if (typeof callbackId !== 'string') {
          const errorMsg = 'WorkflowStep expects a callback_id as the first argument';
          throw new errors_1.WorkflowStepInitializationError(errorMsg);
      }
      // Ensure step config object is passed in
      if (typeof config !== 'object') {
          const errorMsg = 'WorkflowStep expects a configuration object as the second argument';
          throw new errors_1.WorkflowStepInitializationError(errorMsg);
      }
      // Check for missing required keys
      const requiredKeys = ['save', 'edit', 'execute'];
      const missingKeys = [];
      requiredKeys.forEach((key) => {
          if (config[key] === undefined) {
              missingKeys.push(key);
          }
      });
      if (missingKeys.length > 0) {
          const errorMsg = `WorkflowStep is missing required keys: ${missingKeys.join(', ')}`;
          throw new errors_1.WorkflowStepInitializationError(errorMsg);
      }
      // Ensure a callback or an array of callbacks is present
      const requiredFns = ['save', 'edit', 'execute'];
      requiredFns.forEach((fn) => {
          if (typeof config[fn] !== 'function' && !Array.isArray(config[fn])) {
              const errorMsg = `WorkflowStep ${fn} property must be a function or an array of functions`;
              throw new errors_1.WorkflowStepInitializationError(errorMsg);
          }
      });
  }
  exports.validate = validate;
  /**
   * `processStepMiddleware()` invokes each callback for lifecycle event
   * @param args workflow_step_edit action
   */
  async function processStepMiddleware(args, middleware) {
      const { context, client, logger } = args;
      // TODO :: revisit type used below (look into contravariance)
      const callbacks = [...middleware];
      const lastCallback = callbacks.pop();
      if (lastCallback !== undefined) {
          await process_1.processMiddleware(callbacks, args, context, client, logger, async () => lastCallback({ ...args, context, client, logger }));
      }
  }
  exports.processStepMiddleware = processStepMiddleware;
  function isStepEvent(args) {
      return VALID_PAYLOAD_TYPES.has(args.payload.type);
  }
  exports.isStepEvent = isStepEvent;
  function selectToken(context) {
      return context.botToken !== undefined ? context.botToken : context.userToken;
  }
  /**
   * Factory for `configure()` utility
   * @param args workflow_step_edit action
   */
  function createStepConfigure(args) {
      const { context, client, body: { callback_id, trigger_id }, } = args;
      const token = selectToken(context);
      return (params) => {
          return client.views.open({
              token,
              trigger_id,
              view: {
                  callback_id,
                  type: 'workflow_step',
                  ...params,
              },
          });
      };
  }
  /**
   * Factory for `update()` utility
   * @param args view_submission event
   */
  function createStepUpdate(args) {
      const { context, client, body: { workflow_step: { workflow_step_edit_id }, }, } = args;
      const token = selectToken(context);
      return (params = {}) => {
          return client.workflows.updateStep({
              token,
              workflow_step_edit_id,
              ...params,
          });
      };
  }
  /**
   * Factory for `complete()` utility
   * @param args workflow_step_execute event
   */
  function createStepComplete(args) {
      const { context, client, payload: { workflow_step: { workflow_step_execute_id }, }, } = args;
      const token = selectToken(context);
      return (params = {}) => {
          return client.workflows.stepCompleted({
              token,
              workflow_step_execute_id,
              ...params,
          });
      };
  }
  /**
   * Factory for `fail()` utility
   * @param args workflow_step_execute event
   */
  function createStepFail(args) {
      const { context, client, payload: { workflow_step: { workflow_step_execute_id }, }, } = args;
      const token = selectToken(context);
      return (params) => {
          const { error } = params;
          return client.workflows.stepFailed({
              token,
              workflow_step_execute_id,
              error,
          });
      };
  }
  /**
   * `prepareStepArgs()` takes in a workflow step's args and:
   *  1. removes the next() passed in from App-level middleware processing
   *    - events will *not* continue down global middleware chain to subsequent listeners
   *  2. augments args with step lifecycle-specific properties/utilities
   * */
  // TODO :: refactor to incorporate a generic parameter
  function prepareStepArgs(args) {
      const { next, ...stepArgs } = args;
      const preparedArgs = { ...stepArgs };
      switch (preparedArgs.payload.type) {
          case 'workflow_step_edit':
              preparedArgs.step = preparedArgs.action.workflow_step;
              preparedArgs.configure = createStepConfigure(preparedArgs);
              break;
          case 'workflow_step':
              preparedArgs.step = preparedArgs.body.workflow_step;
              preparedArgs.update = createStepUpdate(preparedArgs);
              break;
          case 'workflow_step_execute':
              preparedArgs.step = preparedArgs.event.workflow_step;
              preparedArgs.complete = createStepComplete(preparedArgs);
              preparedArgs.fail = createStepFail(preparedArgs);
              break;
          default:
              break;
      }
      return preparedArgs;
  }
  exports.prepareStepArgs = prepareStepArgs;
  //# sourceMappingURL=WorkflowStep.js.map