"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.shutdown = void 0;
const applications_1 = __importDefault(require("./applications"));
const queries_1 = __importDefault(require("./queries"));
const tables_1 = __importDefault(require("./tables"));
const rows_1 = __importDefault(require("./rows"));
const users_1 = __importDefault(require("./users"));
const authorized_1 = __importDefault(require("../../../middleware/authorized"));
const publicApi_1 = __importDefault(require("../../../middleware/publicApi"));
const resourceId_1 = require("../../../middleware/resourceId");
const mapper_1 = __importDefault(require("./middleware/mapper"));
const environment_1 = __importDefault(require("../../../environment"));
// below imports don't have declaration files
const Router = require("@koa/router");
const { RateLimit, Stores } = require("koa2-ratelimit");
const { PermissionLevels, PermissionTypes, } = require("@devlego/backend-core/permissions");
const { getRedisOptions } = require("@devlego/backend-core/redis").utils;
const PREFIX = "/api/public/v1";
// allow a lot more requests when in test
const DEFAULT_API_REQ_LIMIT_PER_SEC = environment_1.default.isTest() ? 100 : 10;
function getApiLimitPerSecond() {
    if (!environment_1.default.API_REQ_LIMIT_PER_SEC) {
        return DEFAULT_API_REQ_LIMIT_PER_SEC;
    }
    return parseInt(environment_1.default.API_REQ_LIMIT_PER_SEC);
}
let rateLimitStore = null;
if (!environment_1.default.isTest()) {
    const REDIS_OPTS = getRedisOptions();
    let options;
    if (REDIS_OPTS.redisProtocolUrl) {
        // fully qualified redis URL
        options = {
            url: REDIS_OPTS.redisProtocolUrl,
        };
    }
    else {
        options = {
            socket: {
                host: REDIS_OPTS.host,
                port: REDIS_OPTS.port,
            },
            password: REDIS_OPTS.opts.password,
            database: 1,
        };
    }
    rateLimitStore = new Stores.Redis(options);
    RateLimit.defaultOptions({
        store: rateLimitStore,
    });
}
// rate limiting, allows for 2 requests per second
const limiter = RateLimit.middleware({
    interval: { sec: 1 },
    // per ip, per interval
    max: getApiLimitPerSecond(),
});
const publicRouter = new Router({
    prefix: PREFIX,
});
publicRouter.use(limiter);
function addMiddleware(endpoints, middleware, opts = { output: false }) {
    if (!endpoints) {
        return;
    }
    if (!Array.isArray(endpoints)) {
        endpoints = [endpoints];
    }
    for (let endpoint of endpoints) {
        if (opts === null || opts === void 0 ? void 0 : opts.output) {
            endpoint.addOutputMiddleware(middleware);
        }
        else {
            endpoint.addMiddleware(middleware);
        }
    }
}
function addToRouter(endpoints) {
    if (endpoints) {
        for (let endpoint of endpoints) {
            endpoint.apply(publicRouter);
        }
    }
}
function applyRoutes(endpoints, permType, resource, subResource) {
    const paramMiddleware = subResource
        ? (0, resourceId_1.paramSubResource)(resource, subResource)
        : (0, resourceId_1.paramResource)(resource);
    const publicApiMiddleware = (0, publicApi_1.default)({
        requiresAppId: permType !== PermissionTypes.APP && permType !== PermissionTypes.USER,
    });
    addMiddleware(endpoints.read, publicApiMiddleware);
    addMiddleware(endpoints.write, publicApiMiddleware);
    // add the parameter capture middleware
    addMiddleware(endpoints.read, paramMiddleware);
    addMiddleware(endpoints.write, paramMiddleware);
    // add the authorization middleware, using the correct perm type
    addMiddleware(endpoints.read, (0, authorized_1.default)(permType, PermissionLevels.READ));
    addMiddleware(endpoints.write, (0, authorized_1.default)(permType, PermissionLevels.WRITE));
    // add the output mapper middleware
    addMiddleware(endpoints.read, mapper_1.default, { output: true });
    addMiddleware(endpoints.write, mapper_1.default, { output: true });
    addToRouter(endpoints.read);
    addToRouter(endpoints.write);
}
applyRoutes(applications_1.default, PermissionTypes.APP, "appId");
applyRoutes(tables_1.default, PermissionTypes.TABLE, "tableId");
applyRoutes(users_1.default, PermissionTypes.USER, "userId");
applyRoutes(queries_1.default, PermissionTypes.QUERY, "queryId");
// needs to be applied last for routing purposes, don't override other endpoints
applyRoutes(rows_1.default, PermissionTypes.TABLE, "tableId", "rowId");
exports.default = publicRouter;
const shutdown = () => {
    if (rateLimitStore) {
        rateLimitStore.client.disconnect();
        rateLimitStore = null;
    }
};
exports.shutdown = shutdown;
