import { isNothing, isSome } from "@jet/environment/types/optional";
import * as serverData from "../../../foundation/json-parsing/server-data";
import { BuyParameters } from "../../../foundation/metrics/buy-parameters";
import { URL } from "../../../foundation/network/urls";
import * as productVariants from "../../product-page/product-page-variants";
import { MetricsReferralContext } from "../metrics-referral-context";
import * as metricsPosting from "../posting";
import * as misc from "./misc";
import { IAdSearchInformation } from "./models";
import * as metricsUtil from "./util";
//* *************************
//* Buy Metrics
//* *************************
/**
 * Adds bag driven metrics fields.
 * @param objectGraph
 * @returns
 */
function addBagMetricsToBuyParams(objectGraph, baseBuyParams) {
    const buyParams = new BuyParameters(baseBuyParams);
    const metricsConfiguration = objectGraph.bag.metricsConfiguration;
    const language = serverData.asString(metricsConfiguration, "metricsBase.language");
    buyParams.set("languageId", language);
    return buyParams.toString();
}
export function addPageMetricsToBuyParams(objectGraph, baseBuyParams, adamId, pageInformation, targetType, kind, metricsPlatformDisplayStyle, productVariantData, inAppEventId, excludeCrossfireAttribution, extRefApp2, extRefUrl2) {
    const buyParams = new BuyParameters(baseBuyParams);
    addPageMetricsToBuyParamsObject(objectGraph, buyParams, adamId, pageInformation, targetType, kind, metricsPlatformDisplayStyle, productVariantData, inAppEventId, excludeCrossfireAttribution, extRefApp2, extRefUrl2);
    addExtraInfoToBuyParamsObject(objectGraph, buyParams, pageInformation);
    return buyParams.toString();
}
export function addPageMetricsToBuyParamsObject(objectGraph, buyParams, adamId, pageInformation, targetType, kind, metricsPlatformDisplayStyle, productVariantData, inAppEventId, excludeCrossfireAttribution, extRefApp2, extRefUrl2) {
    var _a, _b, _c;
    const fields = misc.fieldsFromPageInformation(pageInformation);
    if (targetType) {
        buyParams.set("impressionType", targetType); // impressionType == targetType == locationType.
    }
    if (kind) {
        buyParams.set("kind", kind);
    }
    const pageId = serverData.asString(serverData.asJSONData(fields), "pageId");
    buyParams.set("pageId", pageId);
    const pageType = serverData.asString(serverData.asJSONData(fields), "pageType");
    buyParams.set("pageType", pageType);
    // Ad container id
    const iAdContainerId = serverData.asString(serverData.asJSONData(fields), "iAdContainerId");
    if (isSome(iAdContainerId) && iAdContainerId.length > 0) {
        buyParams.set(adBuyParamKeys.containerId, iAdContainerId, null);
    }
    // we add search terms to the page if the page is for the item we are buying, or if
    // its for a streamlined contingent offer
    const pageIds = (_a = pageId === null || pageId === void 0 ? void 0 : pageId.split("_")) !== null && _a !== void 0 ? _a : [];
    const pageMatchesProduct = pageIds.includes(adamId);
    const isProductPage = pageType === "Software";
    const isStreamlinedContingentOffer = ((_b = buyParams.get("contingentItemId", null)) === null || _b === void 0 ? void 0 : _b.length) > 0;
    if (!isProductPage || pageMatchesProduct || isStreamlinedContingentOffer) {
        // If there is a native search term, it will overwrite this
        // initial value below in `addNativeMetricsToBuyParams`.
        let searchTerm = serverData.asString(serverData.asJSONData(pageInformation), "searchTermContext.resultsTerm");
        // A search term may be attached to the product URL as a means of associating buys with searches.
        if (serverData.isNullOrEmpty(searchTerm)) {
            searchTerm = metricsUtil.searchTermFromProductURL(pageInformation === null || pageInformation === void 0 ? void 0 : pageInformation.pageUrl);
        }
        if (!serverData.isNull(searchTerm)) {
            buyParams.set("searchTerm", searchTerm);
        }
    }
    if (isProductPage && isSome(pageInformation) && isSome(pageInformation.pageUrl)) {
        const pageUrl = new URL(pageInformation.pageUrl);
        if (((_c = pageUrl.query) === null || _c === void 0 ? void 0 : _c["context"]) === "browserChoice") {
            buyParams.set("prevPage", "BrowserChoice");
            buyParams.set("browserChoiceScreenBuy", "1", null);
        }
    }
    productVariants.addProductPageVariantMetricsToBuyParams(buyParams, adamId, pageInformation === null || pageInformation === void 0 ? void 0 : pageInformation.productVariantData, productVariantData !== null && productVariantData !== void 0 ? productVariantData : undefined);
    if (!serverData.isNull(metricsPlatformDisplayStyle) && metricsPlatformDisplayStyle.length > 0) {
        buyParams.set("platformDisplayStyle", metricsPlatformDisplayStyle);
    }
    // App Event ID
    buyParams.set("inAppEventId", inAppEventId);
    // Referrer
    if (!excludeCrossfireAttribution) {
        if (serverData.isDefinedNonNull(MetricsReferralContext.shared.activeReferralData)) {
            buyParams.set("extRefApp2", MetricsReferralContext.shared.activeReferralData.extRefApp2, null);
            buyParams.set("extRefUrl2", MetricsReferralContext.shared.activeReferralData.extRefUrl2, null);
            if (isSome(MetricsReferralContext.shared.activeReferralData.kind)) {
                const extRefAppKindName = MetricsReferralContext.shared.activeReferralData.kind.name;
                if (extRefAppKindName === "clip" || extRefAppKindName === "appClip") {
                    buyParams.set("hostApp", "com.apple.AppStore.clipOverlay");
                }
            }
        }
        else {
            buyParams.set("extRefApp2", extRefApp2, null);
            buyParams.set("extRefUrl2", extRefUrl2, null);
        }
    }
}
function addExtraInfoToBuyParamsObject(objectGraph, buyParams, pageInformation) {
    var _a, _b;
    if (isNothing(pageInformation)) {
        return;
    }
    const extraInfo = [];
    const hasiAdData = isSome((_a = pageInformation.iAdInfo) === null || _a === void 0 ? void 0 : _a.clickFields["hasiAdData"]);
    if (hasiAdData) {
        const iAdExtraInfoKey = isIAdFromCurrentPage(objectGraph, pageInformation) ? "iAdSponsored" : "iAdOriginated";
        extraInfo.push({ key: iAdExtraInfoKey, value: "true" });
    }
    if (serverData.isDefinedNonNullNonEmpty(extraInfo)) {
        const extraInfoParamValue = extraInfo
            .map((extraInfoValue) => `${extraInfoValue.key}=${extraInfoValue.value}`)
            .join(";");
        const encodedValue = (_b = objectGraph.cryptography) === null || _b === void 0 ? void 0 : _b.base64Encode(extraInfoParamValue);
        if (isSome(encodedValue)) {
            buyParams.set("extraInfo", encodedValue);
        }
    }
}
/**
 * Determines if an iAd is from the current page by comparing the iAd's placement type with the page type.
 *
 * This function validates whether an advertisement is correctly placed on the appropriate page type.
 * Different ad placement types are designed for specific page contexts, and this function ensures
 * that the placement matches the current page context.
 *
 * @param objectGraph - The AppStore object graph providing access to app services and utilities
 * @param pageInformation - Information about the current page, including its type and iAd information
 * @returns True if the iAd's placement type matches the current page type, false otherwise
 *          or if pageInformation or iAdInfo is missing
 */
function isIAdFromCurrentPage(objectGraph, pageInformation) {
    const iAdInfo = pageInformation === null || pageInformation === void 0 ? void 0 : pageInformation.iAdInfo;
    if (isNothing(pageInformation) || isNothing(iAdInfo)) {
        return false;
    }
    const pageType = pageInformation.baseFields["pageType"];
    const iAdPlacementType = IAdSearchInformation.placementTypeFromPlacementId(objectGraph, iAdInfo.placementId);
    switch (iAdPlacementType) {
        case "searchLanding":
            return pageType === "SearchLanding";
        case "today":
            return pageType === "Today";
        case "productPageYMAL":
        case "productPageYMALDuringDownload":
            return pageType === "Software" || pageType === "SoftwareBundle";
        default:
            return pageType === "Search";
    }
}
/**
 * Returns a copy of the specified buy parameters enriched with native metrics fields.
 *
 * @param baseBuyParams The buy parameters of an app which have previously been
 * decorated with page metrics. Passing buy parameters that were not decorated with page
 * metrics can result in incorrect search terms being reported.
 * @param adamId The identifier of the app whose buy parameters are being decorated.
 * @param excludeCrossfireAttribution Specifies whether crossfire attribution should be
 * excluded from the decorated buy params.
 * @param nativeMetrics Metrics fields provided by native code.
 * @param osMetrics Metrics fields describing the device's OS provided by native code.
 * @returns A copy of `baseBuyParams` enriched with native metrics fields.
 */
export function addNativeValuesToBuyParams(objectGraph, baseBuyParams, adamId, excludeCrossfireAttribution, isAppInstalled, nativeMetrics, osMetrics) {
    const baseBuyParamsObject = new BuyParameters(baseBuyParams);
    addNativeValuesToBuyParamsObject(objectGraph, baseBuyParamsObject, adamId, excludeCrossfireAttribution, isAppInstalled, nativeMetrics, osMetrics);
    return baseBuyParamsObject.toString();
}
/**
 * Returns a copy of the specified buy parameters enriched with native metrics fields.
 *
 * @param baseBuyParams The buy parameters of an app which have previously been
 * decorated with page metrics. Passing buy parameters that were not decorated with page
 * metrics can result in incorrect search terms being reported.
 * @param adamId The identifier of the app whose buy parameters are being decorated.
 * @param excludeCrossfireAttribution Specifies whether crossfire attribution should be
 * excluded from the decorated buy params.
 * @param nativeMetrics Metrics fields provided by native code.
 * @param osMetrics Metrics fields describing the device's OS provided by native code.
 * @returns A copy of `baseBuyParams` enriched with native metrics fields.
 */
export function addNativeValuesToBuyParamsObject(objectGraph, buyParams, adamId, excludeCrossfireAttribution, isAppInstalled, nativeMetrics, osMetrics) {
    var _a, _b;
    const pageContext = serverData.asString(nativeMetrics, "pageContext");
    buyParams.set("pageContext", pageContext);
    const paymentTopic = objectGraph.props.enabled("paymentTopicFromBag")
        ? objectGraph.bag.metricsPaymentTopic
        : undefined;
    buyParams.set("topic", paymentTopic !== null && paymentTopic !== void 0 ? paymentTopic : objectGraph.bag.metricsTopic);
    metricsPosting.buyDecorator.useNativeValues(nativeMetrics);
    const decoratorParams = metricsPosting.buyDecorator.params;
    for (const key of Object.keys(decoratorParams)) {
        if (key === "prevPage" && isSome(buyParams.get("prevPage"))) {
            // We may have added a `prevPage` param earlier, specifically don't override this value if we have.
            continue;
        }
        const value = serverData.asString(decoratorParams, key);
        buyParams.set(key, value);
    }
    if (!serverData.isNull(osMetrics)) {
        for (const key of Object.keys(osMetrics)) {
            const value = serverData.asString(osMetrics, key);
            buyParams.set(key, value);
            buyParams.set(key, value, null);
        }
    }
    if (!nativeMetrics) {
        // ^^ Is this actually needed?
        buyParams.set("searchTerm", null);
        buyParams.set("platformDisplayStyle", null);
        return;
    }
    const hostApp = serverData.asString(nativeMetrics, "hostApp");
    if (isSome(hostApp) && hostApp.length > 0) {
        buyParams.set("hostApp", hostApp);
    }
    const isContingentOffer = ((_a = buyParams.get("contingentItemId", null)) === null || _a === void 0 ? void 0 : _a.length) > 0;
    const app = serverData.asString(nativeMetrics, "app");
    if (isContingentOffer) {
        // Contingent Offer Streamline buy app install flag
        buyParams.set("app", objectGraph.host.clientIdentifier);
    }
    else if (isSome(app) && app.length > 0) {
        buyParams.set("app", app);
    }
    if (!excludeCrossfireAttribution && !MetricsReferralContext.shared.shouldUseJSReferralData) {
        const extRefUrl = serverData.asString(nativeMetrics, "extRefUrl2");
        const extractedSiriRefApp = metricsUtil.extractSiriRefAppFromRefURL(extRefUrl);
        if (extRefUrl && extractedSiriRefApp) {
            nativeMetrics["refApp"] = extractedSiriRefApp;
        }
        // ^^ Is this actually needed?
        const usageContext = serverData.asString(nativeMetrics, "usageContext");
        if (isSome(usageContext)) {
            switch (usageContext) {
                case "overlay":
                    buyParams.set("hostApp", "com.apple.AppStore.overlay");
                    break;
                case "overlayClip":
                    buyParams.set("hostApp", "com.apple.AppStore.clipOverlay");
                    break;
                default:
                    break;
            }
            buyParams.set("extRefApp2", hostApp, null);
        }
        else {
            const extRefApp2 = serverData.asString(nativeMetrics, "extRefApp2");
            buyParams.set("extRefApp2", extRefApp2, null);
            const extRefUrl2 = serverData.asString(nativeMetrics, "extRefUrl2");
            buyParams.set("extRefUrl2", extRefUrl2, null);
            const extRefAppType = serverData.asString(nativeMetrics, "extRefAppType");
            if (extRefAppType === "clip") {
                buyParams.set("hostApp", "com.apple.AppStore.clipOverlay");
            }
        }
    }
    // we add search terms to the page if the page is for the item we are buying
    const pageId = buyParams.get("pageId");
    const pageType = buyParams.get("pageType");
    const pageIds = (_b = pageId === null || pageId === void 0 ? void 0 : pageId.split("_")) !== null && _b !== void 0 ? _b : [];
    const pageMatchesProduct = pageIds.includes(adamId);
    const isProductPage = pageType === "Software";
    if (!isProductPage || pageMatchesProduct) {
        const searchTerm = metricsUtil.searchTermFromRefURL(serverData.asString(nativeMetrics, "refUrl"));
        if (serverData.isDefinedNonNull(searchTerm)) {
            buyParams.set("searchTerm", searchTerm);
        }
    }
    // Remove ownerDsid from buyParams
    buyParams.set("ownerDsid", null, null);
}
/**
 *
 * @param adamId The identifier of the app whose buy parameters are being decorated.
 * @param buyParams The buy parameters of an app from a Media API response.
 * @param pageInformation The purchase configuration page metrics configuration
 * from an offer action.
 * @param excludeCrossfireAttribution Specifies whether crossfire attribution should be
 * excluded from the decorated buy params.
 * @param targetType The target type that buy occured on
 * @param kind The Kind that buy occured on, if any.
 * @param metricsPlatformDisplayStyle The platform display style from an offer action.
 * @param nativeMetrics Metrics fields provided by native code.
 * @param osMetrics Metrics fields describing the device's OS provided by native code.
 * @returns A copy of `buyParams` decorated with all metrics.
 */
export function addMetricsToBuyParams(objectGraph, adamId, buyParams, pageInformation, excludeCrossfireAttribution, isAppInstalled, targetType, kind, metricsPlatformDisplayStyle, nativeMetrics, osMetrics, productVariantData, inAppEventId, extRefApp2, extRefUrl2) {
    // Future: Build BuyParameters once, instead of creating it per modification.
    const bagMetricsBuyParams = addBagMetricsToBuyParams(objectGraph, buyParams);
    const pageMetricsBuyParams = addPageMetricsToBuyParams(objectGraph, bagMetricsBuyParams, adamId, pageInformation, targetType, kind, metricsPlatformDisplayStyle, productVariantData, inAppEventId, excludeCrossfireAttribution, extRefApp2, extRefUrl2);
    const nativeMetricsBuyParams = addNativeValuesToBuyParams(objectGraph, pageMetricsBuyParams, adamId, excludeCrossfireAttribution, isAppInstalled, nativeMetrics, osMetrics);
    return nativeMetricsBuyParams;
}
/**
 * Keys used for ad-related buy params.
 */
export const adBuyParamKeys = {
    containerId: "mtContainerId",
    placementId: "mtIadPlacementId",
    templateType: "mtIadTemplateType",
};
/**
 * Copy ad-related buy params to the override buy params.
 * Override buy params are used for updated and redownloads, and in those cases we lose iAd download attribution.
 * If the original buy params had ad fields, we should copy them over here.
 * @param originalBuyParamsString The original buy params attached to the offerAction.
 * @param overrideBuyParamsString The override buy params from the purchase.
 * @returns An updated buy params string with any ad-related fields copied over.
 */
export function copyAdBuyParamsToOverrideBuyParams(originalBuyParamsString, overrideBuyParamsString) {
    const originalBuyParams = new BuyParameters(originalBuyParamsString);
    const overrideBuyParams = new BuyParameters(overrideBuyParamsString);
    const originalPlacementId = originalBuyParams.get(adBuyParamKeys.placementId, null);
    if ((originalPlacementId === null || originalPlacementId === void 0 ? void 0 : originalPlacementId.length) > 0 &&
        serverData.isNullOrEmpty(overrideBuyParams.get(adBuyParamKeys.placementId, null))) {
        overrideBuyParams.set(adBuyParamKeys.placementId, originalPlacementId, null);
    }
    const originalContainerId = originalBuyParams.get(adBuyParamKeys.containerId, null);
    if ((originalContainerId === null || originalContainerId === void 0 ? void 0 : originalContainerId.length) > 0 &&
        serverData.isNullOrEmpty(overrideBuyParams.get(adBuyParamKeys.containerId, null))) {
        overrideBuyParams.set(adBuyParamKeys.containerId, originalContainerId, null);
    }
    const originalTemplateType = originalBuyParams.get(adBuyParamKeys.templateType, null);
    if ((originalTemplateType === null || originalTemplateType === void 0 ? void 0 : originalTemplateType.length) > 0 &&
        serverData.isNullOrEmpty(overrideBuyParams.get(adBuyParamKeys.templateType, null))) {
        overrideBuyParams.set(adBuyParamKeys.templateType, originalTemplateType, null);
    }
    return overrideBuyParams.toString();
}
//# sourceMappingURL=buy.js.map