var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import UserMiddleware from "../Middleware/UserAuthorization";
import Express from "../Utils/Express";
import Response from "../Utils/Response";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import CommonAPI from "./CommonAPI";
import BaseModel from "../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
import { DEFAULT_LIMIT, LIMIT_PER_PROJECT, } from "../../Types/Database/LimitMax";
import BadRequestException from "../../Types/Exception/BadRequestException";
import JSONFunctions from "../../Types/JSONFunctions";
import ObjectID from "../../Types/ObjectID";
import PositiveNumber from "../../Types/PositiveNumber";
export default class BaseAPI {
    constructor(type, service) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
        this.entityType = type;
        const router = Express.getRouter();
        // Create
        router.post(`${(_a = new this.entityType().getCrudApiPath()) === null || _a === void 0 ? void 0 : _a.toString()}`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                await this.createItem(req, res);
            }
            catch (err) {
                next(err);
            }
        });
        // List
        router.post(`${(_b = new this.entityType().getCrudApiPath()) === null || _b === void 0 ? void 0 : _b.toString()}/get-list`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                await this.getList(req, res);
            }
            catch (err) {
                next(err);
            }
        });
        // List
        router.get(`${(_c = new this.entityType().getCrudApiPath()) === null || _c === void 0 ? void 0 : _c.toString()}/get-list`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                await this.getList(req, res);
            }
            catch (err) {
                next(err);
            }
        });
        // count
        router.post(`${(_d = new this.entityType().getCrudApiPath()) === null || _d === void 0 ? void 0 : _d.toString()}/count`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                await this.count(req, res);
            }
            catch (err) {
                next(err);
            }
        });
        // Get Item
        router.post(`${(_e = new this.entityType().getCrudApiPath()) === null || _e === void 0 ? void 0 : _e.toString()}/:id/get-item`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                await this.getItem(req, res);
            }
            catch (err) {
                next(err);
            }
        });
        // Get Item
        router.get(`${(_f = new this.entityType().getCrudApiPath()) === null || _f === void 0 ? void 0 : _f.toString()}/:id/get-item`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                await this.getItem(req, res);
            }
            catch (err) {
                next(err);
            }
        });
        // Update
        router.put(`${(_g = new this.entityType().getCrudApiPath()) === null || _g === void 0 ? void 0 : _g.toString()}/:id`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                await this.updateItem(req, res);
            }
            catch (err) {
                next(err);
            }
        });
        router.post(`${(_h = new this.entityType().getCrudApiPath()) === null || _h === void 0 ? void 0 : _h.toString()}/:id/update-item`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                await this.updateItem(req, res);
            }
            catch (err) {
                next(err);
            }
        });
        router.get(`${(_j = new this.entityType().getCrudApiPath()) === null || _j === void 0 ? void 0 : _j.toString()}/:id/update-item`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                await this.updateItem(req, res);
            }
            catch (err) {
                next(err);
            }
        });
        // Delete
        router.delete(`${(_k = new this.entityType().getCrudApiPath()) === null || _k === void 0 ? void 0 : _k.toString()}/:id`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                await this.deleteItem(req, res);
            }
            catch (err) {
                next(err);
            }
        });
        router.post(`${(_l = new this.entityType().getCrudApiPath()) === null || _l === void 0 ? void 0 : _l.toString()}/:id/delete-item`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                await this.deleteItem(req, res);
            }
            catch (err) {
                next(err);
            }
        });
        router.get(`${(_m = new this.entityType().getCrudApiPath()) === null || _m === void 0 ? void 0 : _m.toString()}/:id/delete-item`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                await this.deleteItem(req, res);
            }
            catch (err) {
                next(err);
            }
        });
        this.router = router;
        this.service = service;
    }
    async getPermissionsForTenant(req) {
        var _a, _b, _c;
        const permissions = [];
        const props = await CommonAPI.getDatabaseCommonInteractionProps(req);
        if (props &&
            props.userTenantAccessPermission &&
            props.userTenantAccessPermission[((_a = props.tenantId) === null || _a === void 0 ? void 0 : _a.toString()) || ""]) {
            return (((_c = props.userTenantAccessPermission[((_b = props.tenantId) === null || _b === void 0 ? void 0 : _b.toString()) || ""]) === null || _c === void 0 ? void 0 : _c.permissions) || []);
        }
        return permissions;
    }
    getTenantId(req) {
        if (req.tenantId) {
            return req.tenantId;
        }
        return null;
    }
    async getList(req, res) {
        await this.onBeforeList(req, res);
        /*
         * Extract pagination parameters from query or body (for POST requests)
         * Support both 'skip' and 'offset' parameters (offset is alias for skip)
         */
        let skipValue = 0;
        let limitValue = DEFAULT_LIMIT;
        if (req.query["skip"]) {
            skipValue = parseInt(req.query["skip"], 10) || 0;
        }
        else if (req.body && req.body["skip"] !== undefined) {
            skipValue = parseInt(req.body["skip"], 10) || 0;
        }
        if (req.query["limit"]) {
            limitValue = parseInt(req.query["limit"], 10) || DEFAULT_LIMIT;
        }
        else if (req.body && req.body["limit"] !== undefined) {
            limitValue = parseInt(req.body["limit"], 10) || DEFAULT_LIMIT;
        }
        const skip = new PositiveNumber(skipValue);
        const limit = new PositiveNumber(limitValue);
        if (limit.toNumber() > LIMIT_PER_PROJECT) {
            throw new BadRequestException("Limit should be less than " + LIMIT_PER_PROJECT);
        }
        if (skip.toNumber() < 0) {
            throw new BadRequestException("Skip should be greater than or equal to 0");
        }
        if (limit.toNumber() <= 0) {
            throw new BadRequestException("Limit should be greater than 0");
        }
        let query = {};
        let select = {};
        let sort = {};
        let groupBy;
        if (req.body) {
            query = JSONFunctions.deserialize(req.body["query"]);
            select = JSONFunctions.deserialize(req.body["select"]);
            sort = JSONFunctions.deserialize(req.body["sort"]);
            groupBy = JSONFunctions.deserialize(req.body["groupBy"]);
        }
        const databaseProps = await CommonAPI.getDatabaseCommonInteractionProps(req);
        const list = await this.service.findBy({
            query,
            select,
            skip: skip,
            limit: limit,
            groupBy: groupBy,
            sort: sort,
            props: databaseProps,
        });
        const count = await this.service.countBy({
            query,
            props: databaseProps,
        });
        return Response.sendEntityArrayResponse(req, res, list, count, this.entityType);
    }
    async count(req, res) {
        let query = {};
        await this.onBeforeCount(req, res);
        if (req.body) {
            query = JSONFunctions.deserialize(req.body["query"]);
        }
        const databaseProps = await CommonAPI.getDatabaseCommonInteractionProps(req);
        const count = await this.service.countBy({
            query,
            props: databaseProps,
        });
        return Response.sendJsonObjectResponse(req, res, {
            count: count.toNumber(),
        });
    }
    async getItem(req, res) {
        const idParam = req.params["id"];
        ObjectID.validateUUID(idParam);
        const objectId = new ObjectID(idParam);
        await this.onBeforeGet(req, res);
        let select = {};
        if (req.body) {
            select = JSONFunctions.deserialize(req.body["select"]);
        }
        const item = await this.service.findOneById({
            id: objectId,
            select,
            props: await CommonAPI.getDatabaseCommonInteractionProps(req),
        });
        return Response.sendEntityResponse(req, res, item, this.entityType);
    }
    async deleteItem(req, res) {
        await this.onBeforeDelete(req, res);
        const idParam = req.params["id"];
        ObjectID.validateUUID(idParam);
        const objectId = new ObjectID(idParam);
        await this.service.deleteOneById({
            id: objectId,
            props: await CommonAPI.getDatabaseCommonInteractionProps(req),
        });
        return Response.sendEmptySuccessResponse(req, res);
    }
    async updateItem(req, res) {
        await this.onBeforeUpdate(req, res);
        const idParam = req.params["id"];
        ObjectID.validateUUID(idParam);
        const objectId = new ObjectID(idParam);
        const objectIdString = objectId.toString();
        const body = req.body;
        const item = JSONFunctions.deserialize(body["data"]);
        delete item["_id"];
        delete item["createdAt"];
        delete item["updatedAt"];
        await this.service.updateOneById({
            id: new ObjectID(objectIdString),
            data: item,
            props: await CommonAPI.getDatabaseCommonInteractionProps(req),
        });
        return Response.sendEmptySuccessResponse(req, res);
    }
    async createItem(req, res) {
        await this.onBeforeCreate(req, res);
        const body = req.body;
        const item = BaseModel.fromJSON(body["data"], this.entityType);
        const miscDataProps = JSONFunctions.deserialize(body["miscDataProps"]);
        const createBy = {
            data: item,
            miscDataProps: miscDataProps,
            props: await CommonAPI.getDatabaseCommonInteractionProps(req),
        };
        const savedItem = await this.service.create(createBy);
        return Response.sendEntityResponse(req, res, savedItem, this.entityType);
    }
    getRouter() {
        return this.router;
    }
    getEntityName() {
        return this.entityType.name;
    }
    async onBeforeList(_req, _res) {
        return Promise.resolve(true);
    }
    async onBeforeCreate(_req, _res) {
        return Promise.resolve(true);
    }
    async onBeforeGet(_req, _res) {
        return Promise.resolve(true);
    }
    async onBeforeUpdate(_req, _res) {
        return Promise.resolve(true);
    }
    async onBeforeDelete(_req, _res) {
        return Promise.resolve(true);
    }
    async onBeforeCount(_req, _res) {
        return Promise.resolve(true);
    }
}
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], BaseAPI.prototype, "getPermissionsForTenant", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", Promise)
], BaseAPI.prototype, "getList", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", Promise)
], BaseAPI.prototype, "count", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", Promise)
], BaseAPI.prototype, "getItem", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", Promise)
], BaseAPI.prototype, "deleteItem", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", Promise)
], BaseAPI.prototype, "updateItem", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", Promise)
], BaseAPI.prototype, "createItem", null);
//# sourceMappingURL=BaseAPI.js.map