"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.withResponseLogging = exports.withRequestLogging = exports.getApiGatewayEventHttpPath = exports.getApiGatewayEventHttpMethod = exports.isApiGatewayResult = exports.isApiGatewayV2Event = exports.isApiGatewayV1Event = exports.isSQSEvent = exports.isDfnsCronJob = exports.isRabbitMqEvent = exports.getApiGatewayEventSourceApi = exports.getIncomingEventSourceKind = void 0;
const logging_1 = require("../logging");
const types_1 = require("../types");
const utils_1 = require("../utils");
const getIncomingEventSourceKind = (event) => {
    if ((0, exports.isRabbitMqEvent)(event)) {
        return { sourceKind: types_1.LambdaEventSourceKind.RabbitMq, event };
    }
    else if ((0, exports.isSQSEvent)(event)) {
        return { sourceKind: types_1.LambdaEventSourceKind.Sqs, event };
    }
    else if ((0, exports.isApiGatewayV1Event)(event)) {
        return { sourceKind: types_1.LambdaEventSourceKind.ApiGateway, event };
    }
    else if ((0, exports.isApiGatewayV2Event)(event)) {
        return { sourceKind: types_1.LambdaEventSourceKind.ApiGatewayV2, event };
    }
    else if ((0, exports.isDfnsCronJob)(event)) {
        return { sourceKind: types_1.LambdaEventSourceKind.CronJob, event };
    }
    throw Error(`Event cannot be handled ${JSON.stringify(event)}`);
};
exports.getIncomingEventSourceKind = getIncomingEventSourceKind;
const getApiGatewayEventSourceApi = (event) => {
    var _a;
    const apiRef = (_a = event.stageVariables) === null || _a === void 0 ? void 0 : _a['apiRef'];
    //TODO: implement "apiRef" in orgs api & staff api gateway stageVariables, to be able to distinguish between the two
    switch (apiRef) {
        case types_1.DfnsApiKind.PrivateApi:
            return types_1.DfnsApiKind.PrivateApi;
        default:
            return types_1.DfnsApiKind.OrgsApi;
    }
};
exports.getApiGatewayEventSourceApi = getApiGatewayEventSourceApi;
const isRabbitMqEvent = (candidate) => (0, utils_1.isObject)(candidate) && (candidate === null || candidate === void 0 ? void 0 : candidate.eventSource) === 'aws:rmq';
exports.isRabbitMqEvent = isRabbitMqEvent;
const isDfnsCronJob = (candidate) => {
    return (0, utils_1.isObject)(candidate) && (candidate === null || candidate === void 0 ? void 0 : candidate.eventType) === 'dfns:cron';
};
exports.isDfnsCronJob = isDfnsCronJob;
const isSQSEvent = (candidate) => {
    var _a, _b;
    return (0, utils_1.isObject)(candidate) &&
        (0, utils_1.isNonEmptyArray)(candidate.Records) &&
        ((_b = (_a = candidate.Records) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.eventSource) === 'aws:sqs';
};
exports.isSQSEvent = isSQSEvent;
const isApiGatewayV1Event = (candidate) => !!candidate &&
    (0, utils_1.isStringAndNonEmpty)(candidate.path) &&
    (0, utils_1.isStringAndNonEmpty)(candidate.httpMethod) &&
    (0, utils_1.isObject)(candidate.requestContext);
exports.isApiGatewayV1Event = isApiGatewayV1Event;
const isApiGatewayV2Event = (candidate) => {
    return (!!candidate &&
        (0, utils_1.isStringAndNonEmpty)(candidate.routeKey) &&
        (0, utils_1.isStringAndNonEmpty)(candidate.rawPath) &&
        (0, utils_1.isObject)(candidate.requestContext) &&
        (0, utils_1.isObject)(candidate.requestContext.http));
};
exports.isApiGatewayV2Event = isApiGatewayV2Event;
const isApiGatewayResult = (res) => (0, utils_1.isObject)(res) && 'body' in res && 'statusCode' in res;
exports.isApiGatewayResult = isApiGatewayResult;
const getApiGatewayEventHttpMethod = (event) => {
    if ((0, exports.isApiGatewayV1Event)(event)) {
        return event.httpMethod.toUpperCase();
    }
    else if ((0, exports.isApiGatewayV2Event)(event)) {
        return event.requestContext.http.method.toUpperCase();
    }
    return 'UNKNOWN';
};
exports.getApiGatewayEventHttpMethod = getApiGatewayEventHttpMethod;
const getApiGatewayEventHttpPath = (event) => {
    if ((0, exports.isApiGatewayV1Event)(event)) {
        return event.path;
    }
    else if ((0, exports.isApiGatewayV2Event)(event)) {
        return event.requestContext.http.path;
    }
    return 'unknown-path';
};
exports.getApiGatewayEventHttpPath = getApiGatewayEventHttpPath;
const withRequestLogging = (handler) => async (event, context) => {
    const httpMethod = (0, exports.getApiGatewayEventHttpMethod)(event);
    const httpPath = (0, exports.getApiGatewayEventHttpPath)(event);
    const sourceIp = event.headers['X-Forwarded-For'] || event.headers['x-forwarded-for'];
    let logMessage = `${httpMethod} ${httpPath}`;
    if (sourceIp) {
        logMessage = `${sourceIp} ${logMessage}`;
    }
    logging_1.logger.info(logMessage, { payload: event.body });
    return handler(event, context);
};
exports.withRequestLogging = withRequestLogging;
const withResponseLogging = (eventHandler) => async (event, context) => {
    const res = await eventHandler(event, context);
    const httpMethod = (0, exports.getApiGatewayEventHttpMethod)(event);
    const httpPath = (0, exports.getApiGatewayEventHttpPath)(event);
    const payload = (0, exports.isApiGatewayResult)(res) ? res.body : res;
    let responseLog = `${httpMethod} ${httpPath}`;
    if ((0, exports.isApiGatewayResult)(res)) {
        responseLog += ` ${res.statusCode}`;
    }
    logging_1.logger.info(responseLog, { payload });
    return res;
};
exports.withResponseLogging = withResponseLogging;
//# sourceMappingURL=incomingEvents.js.map