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 ApiKeyService from "../Services/ApiKeyService";
import GlobalConfigService from "../Services/GlobalConfigService";
import UserService from "../Services/UserService";
import BadDataException from "../../Types/Exception/BadDataException";
import ObjectID from "../../Types/ObjectID";
import UserType from "../../Types/UserType";
import APIKeyAccessPermission from "../Utils/APIKey/AccessPermission";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import SpanUtil from "../Utils/Telemetry/SpanUtil";
export default class ProjectMiddleware {
    static getProjectId(req) {
        let projectId = null;
        if (req.params && req.params["projectId"]) {
            projectId = new ObjectID(req.params["projectId"]);
        }
        else if (req.params && req.params["tenantid"]) {
            projectId = new ObjectID(req.params["tenantid"]);
        }
        else if (req.query && req.query["tenantid"]) {
            projectId = new ObjectID(req.query["tenantid"]);
        }
        else if (req.headers && req.headers["tenantid"]) {
            // Header keys are automatically transformed to lowercase
            projectId = new ObjectID(req.headers["tenantid"]);
        }
        else if (req.headers && req.headers["projectid"]) {
            // Header keys are automatically transformed to lowercase
            projectId = new ObjectID(req.headers["projectid"]);
        }
        else if (req.body && req.body.projectId) {
            projectId = new ObjectID(req.body.projectId);
        }
        return projectId;
    }
    static getApiKey(req) {
        if (req.headers && req.headers["apikey"]) {
            return new ObjectID(req.headers["apikey"]);
        }
        return null;
    }
    static hasApiKey(req) {
        return Boolean(this.getApiKey(req));
    }
    static hasProjectID(req) {
        return Boolean(this.getProjectId(req));
    }
    static async isValidProjectIdAndApiKeyMiddleware(req, _res, next) {
        try {
            let tenantId = this.getProjectId(req);
            const apiKey = this.getApiKey(req);
            if (tenantId) {
                req.tenantId = tenantId;
                // Tag the current span with project context for observability
                SpanUtil.addAttributesToCurrentSpan({
                    projectId: tenantId.toString(),
                });
            }
            if (!apiKey) {
                throw new BadDataException("API Key not found in the request header. Please provide a valid API Key in the request header.");
            }
            /*
             * Cached lookup — see ApiKeyService.findApiKey. Hot path for any
             * automated caller hitting the API by key.
             */
            const apiKeyRow = await ApiKeyService.findApiKey(apiKey);
            if (apiKeyRow) {
                tenantId = apiKeyRow.projectId;
                req.tenantId = tenantId;
                req.userType = UserType.API;
                /*
                 * TODO: Add API key permissions.
                 */
                req.userGlobalAccessPermission =
                    await APIKeyAccessPermission.getDefaultApiGlobalPermission(tenantId);
                const userTenantAccessPermission = await APIKeyAccessPermission.getApiTenantAccessPermission(tenantId, apiKeyRow.id);
                if (userTenantAccessPermission) {
                    req.userTenantAccessPermission = {};
                    req
                        .userTenantAccessPermission[tenantId.toString()] = userTenantAccessPermission;
                    return next();
                }
            }
            if (!apiKeyRow) {
                // check master key.
                const masterKeyGlobalConfig = await GlobalConfigService.findOneBy({
                    query: {
                        _id: ObjectID.getZeroObjectID().toString(),
                        isMasterApiKeyEnabled: true,
                        masterApiKey: apiKey,
                    },
                    props: {
                        isRoot: true,
                    },
                    select: {
                        _id: true,
                    },
                });
                if (masterKeyGlobalConfig) {
                    req.userType = UserType.MasterAdmin;
                    // get master admin user
                    const user = await UserService.findOneBy({
                        query: {
                            isMasterAdmin: true,
                        },
                        select: {
                            _id: true,
                            email: true,
                            name: true,
                        },
                        props: {
                            isRoot: true,
                        },
                    });
                    if (!user) {
                        throw new BadDataException("Master Admin user not found. Please make sure you have created a master admin user.");
                    }
                    req.userAuthorization = {
                        userId: user.id,
                        isMasterAdmin: true,
                        email: user.email,
                        name: user.name,
                        isGlobalLogin: true,
                    };
                    return next();
                }
            }
            if (apiKey) {
                // If we have an API key but no tenant ID, we throw an error.
                throw new BadDataException("Invalid API Key");
            }
            if (!tenantId) {
                throw new BadDataException("ProjectID not found in the request header.");
            }
            throw new BadDataException("Invalid Project ID or API Key");
        }
        catch (err) {
            next(err);
        }
    }
}
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Object)
], ProjectMiddleware, "getProjectId", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Object)
], ProjectMiddleware, "getApiKey", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Boolean)
], ProjectMiddleware, "hasApiKey", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Boolean)
], ProjectMiddleware, "hasProjectID", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object, Function]),
    __metadata("design:returntype", Promise)
], ProjectMiddleware, "isValidProjectIdAndApiKeyMiddleware", null);
//# sourceMappingURL=ProjectAuthorization.js.map