"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const crypto_1 = tslib_1.__importDefault(require("crypto"));
const child_process_1 = tslib_1.__importDefault(require("child_process"));
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
const http_1 = tslib_1.__importDefault(require("http"));
const path_1 = tslib_1.__importDefault(require("path"));
const morgan_1 = tslib_1.__importDefault(require("morgan"));
const multer_1 = tslib_1.__importDefault(require("multer"));
const express_1 = tslib_1.__importDefault(require("express"));
const socket_io_1 = tslib_1.__importDefault(require("socket.io"));
const constants_1 = require("./constants");
const assets_1 = require("./utils/assets");
const collection_1 = require("./utils/collection");
const workspace = process.env.TUTURE_PATH || process.cwd();
const diffPath = path_1.default.join(workspace, constants_1.DIFF_PATH);
const makeServer = (config) => {
    const app = express_1.default();
    const server = http_1.default.createServer(app);
    const { assetsRoot } = config;
    // Socket.IO server instance.
    const io = socket_io_1.default(server);
    // File upload middleware.
    const upload = multer_1.default({
        storage: multer_1.default.diskStorage({
            destination(req, file, cb) {
                cb(null, assetsRoot);
            },
        }),
    });
    // Middleware for checking whether assets root exists.
    const checkAssetsRoot = (req, res, next) => {
        if (!fs_extra_1.default.existsSync(assetsRoot)) {
            fs_extra_1.default.mkdirSync(assetsRoot);
        }
        next();
    };
    if (process.env.NODE_ENV === 'development') {
        app.use(morgan_1.default('dev'));
    }
    app.use(express_1.default.json({ limit: '50mb' }));
    app.use(express_1.default.urlencoded({ extended: false }));
    app.use('/static', express_1.default.static(constants_1.EDITOR_STATIC_PATH));
    app.use(`/${assetsRoot}`, express_1.default.static(assetsRoot));
    app.get('/diff', (_, res) => {
        res.json(JSON.parse(fs_extra_1.default.readFileSync(diffPath).toString()));
    });
    app.get('/collection', async (_, res) => {
        const collection = await collection_1.loadCollection();
        res.json(collection);
    });
    app.post('/save', (req, res) => {
        collection_1.saveCollection(req.body);
        res.sendStatus(200);
    });
    app.post('/upload', checkAssetsRoot, upload.single('file'), (req, res) => {
        const { originalname } = req.file;
        let savePath = path_1.default.join(assetsRoot, originalname);
        // If target file already exists (likely to happen when uploading image
        // from clipboard), append a unique ID to its name.
        if (fs_extra_1.default.existsSync(savePath)) {
            const { dir, name, ext } = path_1.default.parse(savePath);
            const uniqueId = crypto_1.default.randomBytes(8).toString('hex');
            savePath = path_1.default.join(dir, `${name}-${uniqueId}${ext}`);
        }
        // Move temporarily created file to final save path.
        fs_extra_1.default.moveSync(req.file.path, savePath);
        // Enforce UNIX style path sep in markdown asset path.
        savePath = savePath.split(path_1.default.sep).join('/');
        // Trying to upload to image hosting.
        assets_1.uploadSingle(savePath);
        res.json({ path: savePath });
    });
    app.post('/commit', (req, res) => {
        child_process_1.default.execFile('tuture', ['commit', '-m', req.body.message], {}, (err) => {
            if (err) {
                res.sendStatus(500);
            }
            else {
                res.sendStatus(200);
            }
        });
    });
    app.get('/reload', (_, res) => {
        io.emit('reload');
        res.sendStatus(200);
    });
    app.get('*', (_, res) => {
        const html = fs_extra_1.default
            .readFileSync(path_1.default.join(constants_1.EDITOR_PATH, 'index.html'))
            .toString();
        res.send(html);
    });
    return app;
};
exports.default = makeServer;
