"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 fetch = require("node-fetch");
const env = require("../../environment");
const { checkSlashesInUrl } = require("../../utilities");
const { request } = require("../../utilities/workerRequests");
const { clearLock } = require("../../utilities/redis");
const { Replication, getProdAppID } = require("@devlego/backend-core/db");
const { DocumentTypes } = require("../../db/utils");
const { app: appCache } = require("@devlego/backend-core/cache");
const { getProdAppDB, getAppDB } = require("@devlego/backend-core/context");
const { events } = require("@devlego/backend-core");
function redirect(ctx, method, path = "global") {
    return __awaiter(this, void 0, void 0, function* () {
        const { devPath } = ctx.params;
        const queryString = ctx.originalUrl.split("?")[1] || "";
        const response = yield fetch(checkSlashesInUrl(`${env.WORKER_URL}/api/${path}/${devPath}?${queryString}`), request(ctx, {
            method,
            body: ctx.request.body,
        }, true));
        if (response.status !== 200) {
            const err = yield response.text();
            ctx.throw(400, err);
        }
        const cookie = response.headers.get("set-cookie");
        if (cookie) {
            ctx.set("set-cookie", cookie);
        }
        let body;
        try {
            body = yield response.json();
        }
        catch (err) {
            // don't worry about errors, likely no JSON
        }
        ctx.status = response.status;
        if (body) {
            ctx.body = body;
        }
        ctx.cookies;
    });
}
exports.buildRedirectGet = path => {
    return (ctx) => __awaiter(void 0, void 0, void 0, function* () {
        yield redirect(ctx, "GET", path);
    });
};
exports.buildRedirectPost = path => {
    return (ctx) => __awaiter(void 0, void 0, void 0, function* () {
        yield redirect(ctx, "POST", path);
    });
};
exports.buildRedirectDelete = path => {
    return (ctx) => __awaiter(void 0, void 0, void 0, function* () {
        yield redirect(ctx, "DELETE", path);
    });
};
exports.clearLock = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
    const { appId } = ctx.params;
    try {
        yield clearLock(appId, ctx.user);
    }
    catch (err) {
        ctx.throw(400, `Unable to remove lock. ${err}`);
    }
    ctx.body = {
        message: "Lock released successfully.",
    };
});
exports.revert = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
    const { appId } = ctx.params;
    const productionAppId = getProdAppID(appId);
    // App must have been deployed first
    try {
        const db = getProdAppDB({ skip_setup: true });
        const info = yield db.info();
        if (info.error) {
            throw info.error;
        }
        const deploymentDoc = yield db.get(DocumentTypes.DEPLOYMENTS);
        if (!deploymentDoc.history ||
            Object.keys(deploymentDoc.history).length === 0) {
            throw new Error("No deployments for app");
        }
    }
    catch (err) {
        return ctx.throw(400, "App has not yet been deployed");
    }
    const replication = new Replication({
        source: productionAppId,
        target: appId,
    });
    try {
        if (!env.isTest()) {
            // in-memory db stalls on rollback
            yield replication.rollback();
        }
        // update appID in reverted app to be dev version again
        const db = getAppDB();
        const appDoc = yield db.get(DocumentTypes.APP_METADATA);
        appDoc.appId = appId;
        appDoc.instance._id = appId;
        yield db.put(appDoc);
        yield appCache.invalidateAppMetadata(appId);
        ctx.body = {
            message: "Reverted changes successfully.",
        };
        yield events.app.reverted(appDoc);
    }
    catch (err) {
        ctx.throw(400, `Unable to revert. ${err}`);
    }
    finally {
        yield replication.close();
    }
});
exports.getBudibaseVersion = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
    const version = require("../../../package.json").version;
    ctx.body = {
        version,
    };
    yield events.installation.versionChecked(version);
});
