"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
const emitter = require("../events/index");
const { getAutomationParams } = require("../db/utils");
const { coerce } = require("../utilities/rowProcessor");
const { definitions } = require("./triggerInfo");
const { isDevAppID } = require("../db/utils");
// need this to call directly, so we can get a response
const { queue } = require("./bullboard");
const { checkTestFlag } = require("../utilities/redis");
const utils = require("./utils");
const env = require("../environment");
const { doInAppContext, getAppDB } = require("@devlego/backend-core/context");
const TRIGGER_DEFINITIONS = definitions;
const JOB_OPTS = {
    removeOnComplete: true,
    removeOnFail: true,
};
function queueRelevantRowAutomations(event, eventType) {
    return __awaiter(this, void 0, void 0, function* () {
        if (event.appId == null) {
            throw `No appId specified for ${eventType} - check event emitters.`;
        }
        doInAppContext(event.appId, () => __awaiter(this, void 0, void 0, function* () {
            const db = getAppDB();
            let automations = yield db.allDocs(getAutomationParams(null, { include_docs: true }));
            // filter down to the correct event type
            automations = automations.rows
                .map(automation => automation.doc)
                .filter(automation => {
                const trigger = automation.definition.trigger;
                return trigger && trigger.event === eventType;
            });
            for (let automation of automations) {
                let automationDef = automation.definition;
                let automationTrigger = automationDef ? automationDef.trigger : {};
                // don't queue events which are for dev apps, only way to test automations is
                // running tests on them, in production the test flag will never
                // be checked due to lazy evaluation (first always false)
                if (!env.ALLOW_DEV_AUTOMATIONS &&
                    isDevAppID(event.appId) &&
                    !(yield checkTestFlag(automation._id))) {
                    continue;
                }
                if (automationTrigger.inputs &&
                    automationTrigger.inputs.tableId === event.row.tableId) {
                    yield queue.add({ automation, event }, JOB_OPTS);
                }
            }
        }));
    });
}
emitter.on("row:save", function (event) {
    return __awaiter(this, void 0, void 0, function* () {
        /* istanbul ignore next */
        if (!event || !event.row || !event.row.tableId) {
            return;
        }
        yield queueRelevantRowAutomations(event, "row:save");
    });
});
emitter.on("row:update", function (event) {
    return __awaiter(this, void 0, void 0, function* () {
        /* istanbul ignore next */
        if (!event || !event.row || !event.row.tableId) {
            return;
        }
        yield queueRelevantRowAutomations(event, "row:update");
    });
});
emitter.on("row:delete", function (event) {
    return __awaiter(this, void 0, void 0, function* () {
        /* istanbul ignore next */
        if (!event || !event.row || !event.row.tableId) {
            return;
        }
        yield queueRelevantRowAutomations(event, "row:delete");
    });
});
exports.externalTrigger = function (automation, params, { getResponses } = {}) {
    return __awaiter(this, void 0, void 0, function* () {
        if (automation.definition != null &&
            automation.definition.trigger != null &&
            automation.definition.trigger.stepId === definitions.APP.stepId &&
            automation.definition.trigger.stepId === "APP" &&
            !(yield checkTestFlag(automation._id))) {
            // values are likely to be submitted as strings, so we shall convert to correct type
            const coercedFields = {};
            const fields = automation.definition.trigger.inputs.fields;
            for (let key of Object.keys(fields || {})) {
                coercedFields[key] = coerce(params.fields[key], fields[key]);
            }
            params.fields = coercedFields;
        }
        const data = { automation, event: params };
        if (getResponses) {
            return utils.processEvent({ data });
        }
        else {
            return queue.add(data, JOB_OPTS);
        }
    });
};
exports.TRIGGER_DEFINITIONS = TRIGGER_DEFINITIONS;
