"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 env = require("../../environment");
const { getAllApps } = require("@devlego/backend-core/db");
const { exportDB, sendTempFile, readFileSync, } = require("../../utilities/fileSystem");
const { stringToReadStream } = require("../../utilities");
const { getGlobalDBName, getGlobalDB, } = require("@devlego/backend-core/tenancy");
const { create } = require("./application");
const { getDocParams, DocumentTypes, isDevAppID } = require("../../db/utils");
function createApp(appName, appImport) {
    return __awaiter(this, void 0, void 0, function* () {
        const ctx = {
            request: {
                body: {
                    templateString: appImport,
                    name: appName,
                },
            },
        };
        return create(ctx);
    });
}
exports.exportApps = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
    if (env.SELF_HOSTED || !env.MULTI_TENANCY) {
        ctx.throw(400, "Exporting only allowed in multi-tenant cloud environments.");
    }
    const apps = yield getAllApps({ all: true });
    const globalDBString = yield exportDB(getGlobalDBName(), {
        filter: doc => !doc._id.startsWith(DocumentTypes.USER),
    });
    let allDBs = {
        global: globalDBString,
    };
    for (let app of apps) {
        const appId = app.appId || app._id;
        // only export the dev apps as they will be the latest, the user can republish the apps
        // in their self hosted environment
        if (isDevAppID(appId)) {
            allDBs[app.name] = yield exportDB(appId);
        }
    }
    const filename = `cloud-export-${new Date().getTime()}.txt`;
    ctx.attachment(filename);
    ctx.body = sendTempFile(JSON.stringify(allDBs));
});
function getAllDocType(db, docType) {
    return __awaiter(this, void 0, void 0, function* () {
        const response = yield db.allDocs(getDocParams(docType, null, {
            include_docs: true,
        }));
        return response.rows.map(row => row.doc);
    });
}
function hasBeenImported() {
    return __awaiter(this, void 0, void 0, function* () {
        if (!env.SELF_HOSTED || env.MULTI_TENANCY) {
            return true;
        }
        const apps = yield getAllApps({ all: true });
        return apps.length !== 0;
    });
}
exports.hasBeenImported = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
    ctx.body = {
        imported: yield hasBeenImported(),
    };
});
exports.importApps = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
    if (!env.SELF_HOSTED || env.MULTI_TENANCY) {
        ctx.throw(400, "Importing only allowed in self hosted environments.");
    }
    const beenImported = yield hasBeenImported();
    if (beenImported || !ctx.request.files || !ctx.request.files.importFile) {
        ctx.throw(400, "Import file is required and environment must be fresh to import apps.");
    }
    const importFile = ctx.request.files.importFile;
    const importString = readFileSync(importFile.path);
    const dbs = JSON.parse(importString);
    const globalDbImport = dbs.global;
    // remove from the list of apps
    delete dbs.global;
    const globalDb = getGlobalDB();
    // load the global db first
    yield globalDb.load(stringToReadStream(globalDbImport));
    for (let [appName, appImport] of Object.entries(dbs)) {
        yield createApp(appName, appImport);
    }
    // if there are any users make sure to remove them
    let users = yield getAllDocType(globalDb, DocumentTypes.USER);
    let userDeletionPromises = [];
    for (let user of users) {
        userDeletionPromises.push(globalDb.remove(user._id, user._rev));
    }
    if (userDeletionPromises.length > 0) {
        yield Promise.all(userDeletionPromises);
    }
    yield globalDb.bulkDocs(users);
    ctx.body = {
        message: "Apps successfully imported.",
    };
});
