import { __assign, __awaiter, __generator, __rest } from "tslib";
import { performance } from "node:perf_hooks";
import crypto from "crypto";
var defaultMeta = { datadog: true };
var Profiler = /** @class */ (function () {
    /**
     * Initializes a new instance of the Profiler class.
     * @param logger The logger instance for logging performance data.
     * @param at A string identifier for where the profiler is used.
     * @param detail Optional additional detail data.
     */
    function Profiler(_a) {
        var logger = _a.logger, at = _a.at, logLevel = _a.logLevel, detail = __rest(_a, ["logger", "at", "logLevel"]);
        this.marks = new Map();
        this.logger = logger;
        this.at = at;
        this.detail = detail;
    }
    Profiler.prototype.warn = function (data) {
        this.logger.warn(__assign({ at: this.at }, data));
    };
    Profiler.prototype.logMeasure = function (data) {
        this.logger.debug(__assign(__assign({ at: this.at }, defaultMeta), data));
    };
    /**
     * Starts a profiling session for a task.
     * @param task The name of the task being measured.
     * @param detail Optional detail data to merge.
     * @returns An object containing the start time and a stop function.
     */
    Profiler.prototype.start = function (task, detail) {
        var _this = this;
        var start = crypto.randomUUID();
        var startTime = this.mark(start, detail);
        return {
            startTime: startTime,
            stop: function (_detail) { return _this.measure(task, __assign(__assign({ from: start }, (detail !== null && detail !== void 0 ? detail : {})), (_detail !== null && _detail !== void 0 ? _detail : {}))); },
        };
    };
    /**
     * Records a mark with a label and optional detail.
     * @param label The label for the mark.
     * @param detail Optional detail data to merge.
     * @returns The current timestamp in milliseconds.
     */
    Profiler.prototype.mark = function (label, detail) {
        var _a;
        var currentTime = performance.now();
        // Merge additional data
        this.detail = __assign(__assign({}, ((_a = this.detail) !== null && _a !== void 0 ? _a : {})), (detail !== null && detail !== void 0 ? detail : {}));
        // Store the mark
        this.marks.set(label, { time: currentTime, detail: detail });
        return currentTime;
    };
    /**
     * Measures the duration between two marks and logs the performance data.
     * @param task The name of the task for this measurement.
     * @param params An object containing:
     *  - `from`: The label of the starting mark.
     *  - `to` (optional): The label of the ending mark.
     *  - Additional detail data to merge.
     * @returns The duration in milliseconds, or undefined if the start mark is not found.
     */
    Profiler.prototype.measure = function (task, params) {
        var _a, _b;
        var from = params.from, to = params.to, detail = __rest(params, ["from", "to"]);
        var startMark = this.marks.get(from);
        var endMark = to ? this.marks.get(to) : undefined;
        if (!startMark) {
            this.warn(__assign({ message: "Cannot find start mark for label \"".concat(from, "\".") }, this.detail));
            return;
        }
        var endTime = (_a = endMark === null || endMark === void 0 ? void 0 : endMark.time) !== null && _a !== void 0 ? _a : performance.now();
        var duration = endTime - startMark.time;
        // Merge detail
        var _c = __assign(__assign({}, ((_b = this.detail) !== null && _b !== void 0 ? _b : {})), (detail !== null && detail !== void 0 ? detail : {})), message = _c.message, combinedDetail = __rest(_c, ["message"]);
        var defaultMessage = "Profiler Log: ".concat(task);
        this.logMeasure({
            task: task,
            duration: duration,
            message: message !== null && message !== void 0 ? message : defaultMessage,
            data: combinedDetail,
        });
        return duration;
    };
    /**
     * Measures the performance of an asynchronous operation represented by a promise.
     * @param pr The promise representing the asynchronous operation to measure.
     * @param task The name of the task for this measurement.
     * @param detail Optional detail data to merge.
     * @returns A promise that resolves with the result of the asynchronous operation.
     */
    Profiler.prototype.measureAsync = function (pr, task, detail) {
        return __awaiter(this, void 0, void 0, function () {
            var startTime, result, endTime, duration, _a, message, combinedDetail, defaultMessage;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        startTime = performance.now();
                        _b.label = 1;
                    case 1:
                        _b.trys.push([1, , 3, 4]);
                        return [4 /*yield*/, pr];
                    case 2:
                        result = _b.sent();
                        return [2 /*return*/, result];
                    case 3:
                        endTime = performance.now();
                        duration = endTime - startTime;
                        _a = __assign({}, detail), message = _a.message, combinedDetail = __rest(_a, ["message"]);
                        defaultMessage = "Profiler Log: ".concat(task);
                        this.logMeasure({
                            task: task,
                            duration: duration,
                            message: message !== null && message !== void 0 ? message : defaultMessage,
                            data: combinedDetail,
                        });
                        return [7 /*endfinally*/];
                    case 4: return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Measures the performance of a synchronous function by wrapping it.
     * @param fn The synchronous function to measure.
     * @param task The name of the task for this measurement.
     * @param detail Optional detail data to merge.
     * @returns The result of the synchronous function.
     */
    Profiler.prototype.measureSync = function (fn, task, detail) {
        var startTime = performance.now();
        try {
            var result = fn();
            return result;
        }
        finally {
            var endTime = performance.now();
            var duration = endTime - startTime;
            var _a = __assign({}, detail), message = _a.message, combinedDetail = __rest(_a, ["message"]);
            var defaultMessage = "Profiler Log: ".concat(task);
            this.logMeasure({
                task: task,
                duration: duration,
                message: message !== null && message !== void 0 ? message : defaultMessage,
                data: combinedDetail,
            });
        }
    };
    return Profiler;
}());
export { Profiler };
//# sourceMappingURL=Profiler.js.map