"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());
    });
};
require("svelte/register");
const send = require("koa-send");
const { resolve, join } = require("../../../utilities/centralPath");
const uuid = require("uuid");
const { ObjectStoreBuckets } = require("../../../constants");
const { processString } = require("@devlego/string-templates");
const { loadHandlebarsFile, NODE_MODULES_PATH, TOP_LEVEL_PATH, } = require("../../../utilities/fileSystem");
const env = require("../../../environment");
const { clientLibraryPath } = require("../../../utilities");
const { upload } = require("../../../utilities/fileSystem");
const { attachmentsRelativeURL } = require("../../../utilities");
const { DocumentTypes, isDevAppID } = require("../../../db/utils");
const { getAppDB, getAppId } = require("@devlego/backend-core/context");
const { setCookie, clearCookie } = require("@devlego/backend-core/utils");
const AWS = require("aws-sdk");
const { events } = require("@devlego/backend-core");
const fs = require("fs");
const { downloadTarballDirect, } = require("../../../utilities/fileSystem/utilities");
function prepareUpload({ s3Key, bucket, metadata, file }) {
    return __awaiter(this, void 0, void 0, function* () {
        const response = yield upload({
            bucket,
            metadata,
            filename: s3Key,
            path: file.path,
            type: file.type,
        });
        // don't store a URL, work this out on the way out as the URL could change
        return {
            size: file.size,
            name: file.name,
            url: attachmentsRelativeURL(response.Key),
            extension: [...file.name.split(".")].pop(),
            key: response.Key,
        };
    });
}
exports.toggleBetaUiFeature = function (ctx) {
    return __awaiter(this, void 0, void 0, function* () {
        const cookieName = `beta:${ctx.params.feature}`;
        if (ctx.cookies.get(cookieName)) {
            clearCookie(ctx, cookieName);
            ctx.body = {
                message: `${ctx.params.feature} disabled`,
            };
            return;
        }
        let builderPath = resolve(TOP_LEVEL_PATH, "new_design_ui");
        // // download it from S3
        if (!fs.existsSync(builderPath)) {
            fs.mkdirSync(builderPath);
        }
        yield downloadTarballDirect("https://cdn.budi.live/beta:design_ui/new_ui.tar.gz", builderPath);
        setCookie(ctx, {}, cookieName);
        ctx.body = {
            message: `${ctx.params.feature} enabled`,
        };
    });
};
exports.serveBuilder = function (ctx) {
    return __awaiter(this, void 0, void 0, function* () {
        const builderPath = resolve(TOP_LEVEL_PATH, "builder");
        yield send(ctx, ctx.file, { root: builderPath });
        if (!ctx.file.includes("assets/")) {
            yield events.serve.servedBuilder();
        }
    });
};
exports.uploadFile = function (ctx) {
    return __awaiter(this, void 0, void 0, function* () {
        let files = ctx.request.files.file.length > 1
            ? Array.from(ctx.request.files.file)
            : [ctx.request.files.file];
        const uploads = files.map((file) => __awaiter(this, void 0, void 0, function* () {
            const fileExtension = [...file.name.split(".")].pop();
            // filenames converted to UUIDs so they are unique
            const processedFileName = `${uuid.v4()}.${fileExtension}`;
            return prepareUpload({
                file,
                s3Key: `${ctx.appId}/attachments/${processedFileName}`,
                bucket: ObjectStoreBuckets.APPS,
            });
        }));
        ctx.body = yield Promise.all(uploads);
    });
};
exports.serveApp = function (ctx) {
    return __awaiter(this, void 0, void 0, function* () {
        const db = getAppDB({ skip_setup: true });
        const appInfo = yield db.get(DocumentTypes.APP_METADATA);
        let appId = getAppId();
        if (!env.isJest()) {
            const App = require("./templates/BudibaseApp.svelte").default;
            const { head, html, css } = App.render({
                title: appInfo.name,
                production: env.isProd(),
                appId,
                clientLibPath: clientLibraryPath(appId, appInfo.version, ctx),
            });
            const appHbs = loadHandlebarsFile(`${__dirname}/templates/app.hbs`);
            ctx.body = yield processString(appHbs, {
                head,
                body: html,
                style: css.code,
                appId,
            });
        }
        else {
            // just return the app info for jest to assert on
            ctx.body = appInfo;
        }
        if (isDevAppID(appInfo.appId)) {
            yield events.serve.servedAppPreview(appInfo);
        }
        else {
            yield events.serve.servedApp(appInfo);
        }
    });
};
exports.serveClientLibrary = function (ctx) {
    return __awaiter(this, void 0, void 0, function* () {
        return send(ctx, "budibase-client.js", {
            root: join(NODE_MODULES_PATH, "@devlego", "client", "dist"),
        });
    });
};
exports.getSignedUploadURL = function (ctx) {
    var _a, _b, _c, _d;
    return __awaiter(this, void 0, void 0, function* () {
        const database = getAppDB();
        // Ensure datasource is valid
        let datasource;
        try {
            const { datasourceId } = ctx.params;
            datasource = yield database.get(datasourceId);
            if (!datasource) {
                ctx.throw(400, "The specified datasource could not be found");
            }
        }
        catch (error) {
            ctx.throw(400, "The specified datasource could not be found");
        }
        // Ensure we aren't using a custom endpoint
        if ((_a = datasource === null || datasource === void 0 ? void 0 : datasource.config) === null || _a === void 0 ? void 0 : _a.endpoint) {
            ctx.throw(400, "S3 datasources with custom endpoints are not supported");
        }
        // Determine type of datasource and generate signed URL
        let signedUrl;
        let publicUrl;
        const awsRegion = ((_b = datasource === null || datasource === void 0 ? void 0 : datasource.config) === null || _b === void 0 ? void 0 : _b.region) || "eu-west-1";
        if (datasource.source === "S3") {
            const { bucket, key } = ctx.request.body || {};
            if (!bucket || !key) {
                ctx.throw(400, "bucket and key values are required");
                return;
            }
            try {
                const s3 = new AWS.S3({
                    region: awsRegion,
                    accessKeyId: (_c = datasource === null || datasource === void 0 ? void 0 : datasource.config) === null || _c === void 0 ? void 0 : _c.accessKeyId,
                    secretAccessKey: (_d = datasource === null || datasource === void 0 ? void 0 : datasource.config) === null || _d === void 0 ? void 0 : _d.secretAccessKey,
                    apiVersion: "2006-03-01",
                    signatureVersion: "v4",
                });
                const params = { Bucket: bucket, Key: key };
                signedUrl = s3.getSignedUrl("putObject", params);
                publicUrl = `https://${bucket}.s3.${awsRegion}.amazonaws.com/${key}`;
            }
            catch (error) {
                ctx.throw(400, error);
            }
        }
        ctx.body = { signedUrl, publicUrl };
    });
};
