"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fetchTimingMetricsBuilderType = exports.FetchTimingMetricsBuilder = void 0;
const optional_1 = require("../types/optional");
const metatype_1 = require("../util/metatype");
const promise_1 = require("../util/promise");
/** Object to collect `FetchTimingMetrics`, in order to decorate a model object with these metrics. */
class FetchTimingMetricsBuilder {
    constructor() {
        this.metrics = [];
    }
    /**
     * Collects the timing metrics from the response,
     * then execute code for parsing while capturing timing points around it,
     * adding those parse times to the first timing metrics.
     */
    measureParsing(response, body) {
        const responseTimingMetrics = response.metrics.length > 0 ? [...response.metrics] : [];
        const parseStartTime = Date.now();
        const result = body(response);
        const parseEndTime = Date.now();
        // MAINTAINERS NOTE:
        //   Follows app store approach to add additional timing points to the first item.
        //   This may not be strictly correct, and we should revisit this later.
        if (responseTimingMetrics.length > 0) {
            responseTimingMetrics[0].parseStartTime = parseStartTime;
            responseTimingMetrics[0].parseEndTime = parseEndTime;
        }
        this.metrics.push(...responseTimingMetrics);
        return result;
    }
    /**
     * Execute code for model construction while capturing timing points around it,
     * adding those model construction times to the first timing metrics.
     *
     * Use this method when model construction is a synchronous operation.
     * Use `measureModelConstructionAsync()` when model construction is an asynchronous operation.
     */
    measureModelConstruction(body) {
        const buildModelStartTime = Date.now();
        const result = body();
        const buildModelEndTime = Date.now();
        this.saveModelConstructionTimes(buildModelStartTime, buildModelEndTime);
        return result;
    }
    /**
     * Execute and await code for an asynchronous model construction operation while capturing timing points around it,
     * adding those model construction times to the first timing metrics.
     *
     * Use this method when model construction is an asynchronous operation.
     * Use `measureModelConstruction()` when model construction is a synchronous operation.
     */
    async measureModelConstructionAsync(body) {
        const buildModelStartTime = Date.now();
        const result = await body();
        const buildModelEndTime = Date.now();
        this.saveModelConstructionTimes(buildModelStartTime, buildModelEndTime);
        return result;
    }
    saveModelConstructionTimes(startTime, endTime) {
        // MAINTAINERS NOTE:
        //   Follows app store approach to add additional timing points to the first item.
        //   This may not be strictly correct, and we should revisit this later.
        if (this.metrics.length > 0) {
            this.metrics[0].modelConstructionStartTime = startTime;
            this.metrics[0].modelConstructionEndTime = endTime;
        }
        else {
            this.metrics.push({
                modelConstructionStartTime: startTime,
                modelConstructionEndTime: endTime,
            });
        }
    }
    /** Add the recorded `FetchTimingMetrics` as an additional property on the model. */
    decorate(model) {
        if ((0, optional_1.isNothing)(model)) {
            throw new Error("Cannot decorate null or undefined");
        }
        if (typeof model !== "object") {
            throw new Error("View model to decorate must be an object");
        }
        if ((0, promise_1.isPromise)(model)) {
            // TypeScript compiler may be able to enforce this at compile time.
            // A newer version of TypeScript which supports `Awaited` type may help.
            throw new Error("Cannot decorate a Promise object");
        }
        if (this.metrics.length > 0) {
            model["$networkPerformance"] = this.metrics;
        }
    }
}
exports.FetchTimingMetricsBuilder = FetchTimingMetricsBuilder;
/** Metatype for the `FetchTimingMetricsBuilder`, for adding to an object graph. */
exports.fetchTimingMetricsBuilderType = (0, metatype_1.makeMetatype)("jet-engine:fetchTimingMetricsBuilder");
//# sourceMappingURL=fetch-timing-metrics-builder.js.map