/**
 * Created by ls on 9/7/2018.
 *
 * This `network.ts` is the NON-MEDIA API arm of network fetch requests.
 * It is built on `Network` object and provides standard functionality, such as:
 *     1. Parsing the body into specific format.
 *     2. Adding timing metrics onto blob.
 *
 * This should *only* be used for objects that should have timing metrics, i.e. requests to Non-MediaAPI endpoints
 * that will ultimately render some whole page. Otherwise, use `objectGraph.network.fetch` directly.
 *
 * @see `src/media/network.ts` for fetching from Media API endpoints
 */
import { isSome } from "@jet/environment/types/optional";
import * as serverData from "../json-parsing/server-data";
/** @public */
// eslint-disable-next-line @typescript-eslint/no-namespace
export var ResponseMetadata;
(function (ResponseMetadata) {
    ResponseMetadata.requestedUrl = "_jet-internal:metricsHelpers_requestedUrl";
    /**
     * Symbol used to place timing metrics values onto fetch responses
     * without interfering with the data returned by the server.
     */
    ResponseMetadata.timingValues = "_jet-internal:metricsHelpers_timingValues";
    /**
     * Key used to access the page information gathered from a response's headers
     */
    ResponseMetadata.pageInformation = "_jet-internal:metricsHelpers_pageInformation";
    /**
     * Key used to access the content max-age gathered from a response's headers.
     */
    ResponseMetadata.contentMaxAge = "_jet-internal:responseMetadata_contentMaxAge";
})(ResponseMetadata || (ResponseMetadata = {}));
/**
 * Module's private fetch implementation built off `net` global.
 *
 * @param {FetchRequest} request describes fetch request.
 * @param {(value: string) => Type} parser Some function parsing response body `string` into specific type.
 * @returns {Promise<Type>} Promise resolving to specific object.
 * @throws {Error} Throws error if status code of request is not 200.
 *
 * @note Similar to `fetchWithToken` in `media` module, but excludes media token specific functionality.
 * Top level data fetches to endpoints that don't do redirects, and can benefit from metrics should
 * call methods that build off of this instead of calling `objectGraph.network.fetch(...)` directly.
 */
async function fetch(objectGraph, request, parser) {
    const response = await objectGraph.network.fetch(request);
    if (!response.ok) {
        throw Error(`Bad Status code ${response.status} for ${request.url}`);
    }
    const parseStartTime = Date.now();
    const result = parser(response.body);
    const parseEndTime = Date.now();
    if (result) {
        // Build full network timing metrics.
        const completeTimingMetrics = networkTimingMetricsWithParseTime(response.metrics, parseStartTime, parseEndTime);
        if (serverData.isDefinedNonNull(completeTimingMetrics)) {
            result[ResponseMetadata.timingValues] = completeTimingMetrics;
        }
    }
    result[ResponseMetadata.requestedUrl] = request.url.toString();
    return result;
}
/**
 * Fetch from an endpoint with JSON response body.
 *
 * @param {FetchRequest} request to fetch from endpoint with JSON response..
 * @returns {Promise<Type>} Promise resolving to body of response parsed as `Type`.
 * @throws {Error} Throws error if status code of request is not 200.
 */
export async function fetchJSON(objectGraph, request) {
    return await fetch(objectGraph, request, (body) => {
        if (isSome(body)) {
            return JSON.parse(body);
        }
        else {
            // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
            return {};
        }
    });
}
/**
 * Fetch from an endpoint with XML response body.
 *
 * @param {FetchRequest} request to fetch from endpoint with XML response.
 * @returns {Promise<Type>} Promise resolving to body of response parsed as `Type`.
 * @throws {Error} Throws error if status code of request is not 200.
 */
export async function fetchPlist(objectGraph, request) {
    return await fetch(objectGraph, request, (body) => {
        if (isSome(body)) {
            return objectGraph.plist.parse(body);
        }
        else {
            throw new Error(`Could not fetch Plist, response body was not defined for ${request.url}`);
        }
    });
}
/**
 * With network requests now being created and parsed in JS, different timing metrics are measured in both Native and JS.
 * This function populates the missing values from `HTTPTimingMetrics`'s native counterpart, `JSNetworkPerformanceMetrics`.
 *
 * @param {HTTPTimingMetrics[] | null} responseMetrics Array of response metrics provided by native.
 * @param {number} parseStartTime Time at which response body string parse began in JS.
 * @param {number} parseEndTime Time at which response body string parse ended in JS.
 * @returns {HTTPTimingMetrics | null} Fully populated timing metrics, or `null` if native response provided no metrics events to build off of.
 */
function networkTimingMetricsWithParseTime(responseMetrics, parseStartTime, parseEndTime) {
    // No metrics events to build from.
    if (serverData.isNull(responseMetrics) || responseMetrics.length === 0) {
        return null;
    }
    // Append parse times to first partial timing metrics from native.
    const firstPartialTimingMetrics = {
        ...responseMetrics[0],
        parseStartTime: parseStartTime,
        parseEndTime: parseEndTime,
    };
    // Timing metrics with all properties populated.
    return firstPartialTimingMetrics;
}
//# sourceMappingURL=network.js.map