//
//  product-page.ts
//  AppStoreKit
//
//  Created by Kevin MacWhinnie on 8/17/16.
//  Copyright (c) 2016 Apple Inc. All rights reserved.
//
import { isSome } from "@jet/environment";
import * as validation from "@jet/environment/json/validation";
import * as models from "../../../api/models";
import { AdInteractionAction, SelectAppAction } from "../../../api/models";
import { AdvertActionMetrics, } from "../../../api/models/metrics/advert-action-metrics";
import * as serverData from "../../../foundation/json-parsing/server-data";
import * as mediaAttributes from "../../../foundation/media/attributes";
import * as mediaDataStructure from "../../../foundation/media/data-structure";
import * as mediaRelationship from "../../../foundation/media/relationships";
import { Parameters } from "../../../foundation/network/url-constants";
import * as urls from "../../../foundation/network/urls";
import * as color from "../../../foundation/util/color-util";
import { isAdPlacementEnabled } from "../../ads/ad-common";
import { isNothing } from "@jet/environment/types/optional";
import { makeDeveloperPageIntent } from "../../../api/intents/developer-page-intent";
import { makeGamesResponse } from "../../../gameservicesui/src/api/data-models/game-mapi";
import { deviceFamilyForAccessibilityLabels } from "../../accessibility/accessibility-common";
import * as appPromotion from "../../app-promotions/app-promotion";
import * as appPromotionsShelf from "../../app-promotions/app-promotions-shelf";
import * as contentAttributes from "../../content/attributes";
import * as content from "../../content/content";
import * as filtering from "../../filtering";
import { shelfForUnifiedMessage } from "../../grouping/grouping-common";
import * as externalDeepLink from "../../linking/external-deep-link";
import { getLocale } from "../../locale";
import { attachAdActionMetricsToAction } from "../../lockups/ad-lockups";
import * as metricsHelpersClicks from "../../metrics/helpers/clicks";
import * as metricsHelpersLocation from "../../metrics/helpers/location";
import * as metricsHelpersModels from "../../metrics/helpers/models";
import * as metricsHelpersPage from "../../metrics/helpers/page";
import * as metricsUtil from "../../metrics/helpers/util";
import { MetricsReferralContext } from "../../metrics/metrics-referral-context";
import * as offers from "../../offers/offers";
import * as privacyFooterShelf from "../../privacy/privacy-footer-shelf";
import * as privacyHeaderShelf from "../../privacy/privacy-header-shelf";
import * as privacySuppression from "../../privacy/privacy-suppression";
import * as privacyTypesShelf from "../../privacy/privacy-types-shelf";
import * as refresh from "../../refresh/page-refresh-controller";
import * as sharing from "../../sharing";
import * as productBadges from "../badges/badges";
import * as productBadgesCommon from "../badges/badges-common";
import * as banner from "../banner";
import * as productPageCommon from "../product-page-common";
import { ProductPageShelfMetrics } from "../product-page-shelf-metrics";
import * as productPageUtil from "../product-page-util";
import * as productPageVariants from "../product-page-variants";
import * as reviews from "../reviews";
import * as accessibilityShelves from "../shelves/accessibility-shelves";
import * as achievementsShelf from "../shelves/achievements-shelf";
import * as actionLinksShelf from "../shelves/action-links-shelf";
import * as annotationsShelf from "../shelves/annotations/annotations";
import * as categoryAnnotation from "../shelves/annotations/category-annotation";
import * as compatibilityAnnotation from "../shelves/annotations/compatibility-annotation";
import * as contentRatingAnnotation from "../shelves/annotations/content-rating-annotation";
import * as highMotionAnnotation from "../shelves/annotations/high-motion-annotation";
import * as languageAnnotation from "../shelves/annotations/languages-annotation";
import * as sizeAnnotation from "../shelves/annotations/size-annotation";
import * as bundleChildrenShelf from "../shelves/bundle-children-shelf";
import * as bundleParentsShelf from "../shelves/bundle-parents-shelf";
import * as capabilitiesShelf from "../shelves/capabilities-shelf";
import * as descriptionShelf from "../shelves/description-shelf";
import * as editorialQuoteShelf from "../shelves/editorial-quote-shelf";
import { createEditorsChoiceShelf } from "../shelves/editors-choice-shelf";
import * as featuredInShelf from "../shelves/featured-in-shelf";
import * as friendsPlayingShelf from "../shelves/friends-playing-shelf";
import * as inAppPurchasesShelf from "../shelves/in-app-purchases-shelf";
import * as linksShelf from "../shelves/links-shelf";
import * as moreByDeveloperShelf from "../shelves/more-by-developer-shelf";
import * as productMediaShelf from "../shelves/product-media-shelf";
import * as ribbonShelf from "../shelves/ribbon-shelf";
import * as reviewsShelf from "../shelves/shelf-based-reviews-shelves";
import * as similarItemsShelf from "../shelves/similar-items-shelf";
import * as smallStoryCardShelf from "../shelves/small-story-card-shelf";
import * as textLinksShelf from "../shelves/text-links-shelf";
import * as textCardsShelf from "../shelves/textcard-shelf";
import * as versionHistoryShelves from "../shelves/version-history-shelves";
import * as lockups from "./../../lockups/lockups";
import { productPageShelfIdsFromMappings } from "./product-page-section-mapping";
import * as shelfBasedProductOrdering from "./product-page-shelf-ordering/product-page-shelf-ordering";
import { tryAwait } from "../../../foundation/util/promise-util";
import { withAsyncValidationContext } from "../../../foundation/util/validation-util";
/**
 * Create a side pack using product data.
 *
 * @param response The raw response for a product page.
 * @param options The options to use for the product page configuration.
 * @returns A product page side pack model object.
 */
export function createProductPageSidePackFromResponse(objectGraph, response, options) {
    return validation.context("createProductPageSidePackFromResponse", () => {
        if (!objectGraph.client.isSidepackingEnabled) {
            return null;
        }
        const shelfMetrics = createSidePackShelfMetrics(objectGraph, response, options);
        const sidePack = createProductPageSidePack(objectGraph, response, shelfMetrics, options);
        // Apply back action for the side pack.
        metricsHelpersPage.copyMetricsEventsIntoSidepackedPagewithInformation(objectGraph, sidePack, shelfMetrics.metricsPageInformation);
        return sidePack;
    });
}
/**
 * Creates a full product page using product data (i.e. a product side pack + all other details required to render a product page).
 *
 * @param objectGraph
 * @param response The raw response for a product page.
 * @param options The options to use for the product page configuration.
 * @param additionalPageRequirements Optional additional page requirements for the product page response.
 * @returns A product page model object.
 */
export async function createProductPageFromResponse(objectGraph, response, options, additionalPageRequirements, referrerData, isViewOnly = false) {
    return await withAsyncValidationContext("createProductPageFromResponse", async () => {
        var _a;
        const productData = mediaDataStructure.dataFromDataContainer(objectGraph, response);
        if (serverData.isNullOrEmpty(productData)) {
            return null;
        }
        const isBundle = productData.type === "app-bundles";
        if (objectGraph.client.isWatch && isBundle) {
            throw new models.ItemNotAvailableError("Bundles are not supported on watchOS");
        }
        const appEventDataContainer = additionalPageRequirements === null || additionalPageRequirements === void 0 ? void 0 : additionalPageRequirements[productPageCommon.appPromotionRequirementKey];
        const appEventData = mediaDataStructure.dataFromDataContainer(objectGraph, appEventDataContainer);
        // When we are rendering a product page with an AppEventDetails page on we need to make sure the referral goes
        // to the app event not the product page.
        const appEventReferrerData = serverData.isDefinedNonNullNonEmpty(appEventData)
            ? referrerData
            : null;
        const productReferrerData = serverData.isDefinedNonNullNonEmpty(appEventData)
            ? null
            : referrerData;
        const shelfMetrics = createProductPageShelfMetrics(objectGraph, response, options);
        const productPage = createProductPageSidePack(objectGraph, productData, shelfMetrics, options, appEventData, productReferrerData, appEventReferrerData, isViewOnly);
        shelfMetrics.metricsPageInformation.baseFields["platformDisplayStyle"] =
            metricsUtil.metricsPlatformDisplayStyleFromData(objectGraph, productData, productPage.lockup.icon, options === null || options === void 0 ? void 0 : options.clientIdentifierOverride);
        if (isAdPlacementEnabled(objectGraph, "productPageYMAL") ||
            isAdPlacementEnabled(objectGraph, "productPageYMALDuringDownload")) {
            // Create a new empty IAdSearchInfo, as we won't yet have any ad data.
            shelfMetrics.metricsPageInformation.iAdInfo = new metricsHelpersModels.IAdSearchInformation(objectGraph, "productPageYMAL", metricsHelpersModels.IAdSearchInformation.createInitialSlotInfos(objectGraph, "productPageYMAL", null, null));
        }
        const appPlatforms = content.supportedAppPlatformsFromData(objectGraph, productData);
        const isWebBrowserContext = (_a = options === null || options === void 0 ? void 0 : options.webBrowser) !== null && _a !== void 0 ? _a : false;
        if (!isWebBrowserContext) {
            // Add metrics events (including the back button event) for this full product page response.
            metricsHelpersPage.addMetricsEventsToPageWithInformation(objectGraph, productPage, shelfMetrics.metricsPageInformation, (fields) => {
                // <rdar://problem/43026165> Metrics: Add a deviceCompatibility field to the metrics events
                const supportsMacOSCompatibleIOSBinary = content.supportsMacOSCompatibleIOSBinaryFromData(objectGraph, productData, objectGraph.appleSilicon.isSupportEnabled);
                const supportsVisionOSCompatibleIOSBinary = content.supportsVisionOSCompatibleIOSBinaryFromData(objectGraph, productData);
                const isMacOSAppBuyable = content.isMacOSAppBuyableAndRunnableFromData(objectGraph, productData, objectGraph.appleSilicon.isSupportEnabled, objectGraph.appleSilicon.isRosettaAvailable);
                const isBuyable = content.buyableOnDevice(objectGraph, productData, appPlatforms, objectGraph.client.deviceType, supportsMacOSCompatibleIOSBinary, supportsVisionOSCompatibleIOSBinary, isMacOSAppBuyable);
                const isPreorderable = content.preorderableOnDevice(objectGraph, appPlatforms, objectGraph.client.deviceType, supportsMacOSCompatibleIOSBinary, supportsVisionOSCompatibleIOSBinary);
                const isPurchasable = appPlatforms && (isBuyable || isPreorderable);
                const isRunnable = content.runnableOnDeviceWithData(objectGraph, productData, objectGraph.client.deviceType, objectGraph.appleSilicon.isSupportEnabled);
                if (isPurchasable && isRunnable) {
                    fields["deviceCompatibility"] = "runnable";
                }
                else if (isPurchasable) {
                    fields["deviceCompatibility"] = "purchasable";
                }
                else {
                    fields["deviceCompatibility"] = "none";
                }
                if (serverData.isDefinedNonNullNonEmpty(productReferrerData)) {
                    MetricsReferralContext.shared.addReferralContextToMetricsFieldsIfNecessary(fields);
                }
            }, isWebBrowserContext);
        }
        // Create refresh controller to gather information on when we may need to refresh.
        const refreshController = refresh.newPageRefreshControllerFromResponse(response, true);
        await addFullProductShelfMappingToProductPage(objectGraph, productPage, productData, shelfMetrics, options, refreshController, isViewOnly);
        // Apply refresh policy to page.
        productPage.pageRefreshPolicy = refresh.pageRefreshPolicyForController(objectGraph, refreshController);
        productPage.isIncomplete = false;
        productPage.alwaysAllowReviews = reviews.shouldAllowReviewsForSADApp(objectGraph, productData);
        productPage.canonicalURL = mediaAttributes.attributeAsString(productData, "url");
        // Remove interactive elements from view-only product pages.
        if (isViewOnly) {
            productPage.shareAction = null;
            productPage.titleOfferDisplayProperties = null;
            productPage.expandedOfferDetails = null;
            productPage.lockup.offerDisplayProperties = null;
            productPage.banner = null;
        }
        return productPage;
    });
}
/**
 * Creates a side pack model object using JSON data.
 * @param objectGraph
 * @param data The data representing the product page side pack.
 * @param shelfMetrics The metrics that describe the containing shelf.
 * @param options Any options to consider whilst creating this model object.
 * @param appPromotionData The data representing a deep linked app promotion (App Event or Winback Offer).
 * @param productReferrerData The referrerData for the product page
 * @param appEventReferrerData The referrer data for the app event details page
 */
function createProductPageSidePack(objectGraph, data, shelfMetrics, options, appPromotionData, productReferrerData, appEventReferrerData, isViewOnly = false) {
    return validation.context("createProductPageSidePack", () => {
        var _a;
        let clientIdentifierOverride;
        if (serverData.isDefinedNonNull(options)) {
            clientIdentifierOverride = options.clientIdentifierOverride;
        }
        const id = data.id;
        const name = mediaAttributes.attributeAsString(data, "name");
        const isFirstPartyHideableApp = mediaAttributes.attributeAsBooleanOrFalse(data, "isFirstPartyHideableApp");
        const shouldSuppressReviews = reviews.shouldSuppressReviews(objectGraph, data);
        const supportsArcade = content.isArcadeSupported(objectGraph, data);
        const metricsOptions = {
            pageInformation: shelfMetrics.metricsPageInformation,
            locationTracker: shelfMetrics.locationTracker,
            id: id,
            isAdvert: shelfMetrics.metricsPageInformation.iAdInfo
                ? shelfMetrics.metricsPageInformation.iAdInfo.iAdIsPresent
                : false,
        };
        const productPage = new models.ShelfBasedProductPage();
        const productLockup = new models.Lockup();
        // Add metrics information
        const isPreorder = mediaAttributes.attributeAsBoolean(data, "isPreorder");
        if (isPreorder &&
            serverData.isDefinedNonNull(shelfMetrics) &&
            serverData.isDefinedNonNull(shelfMetrics.metricsPageInformation)) {
            shelfMetrics.metricsPageInformation.offerType = "preorder";
            shelfMetrics.metricsPageInformation.offerReleaseDate = offers.expectedReleaseDateFromData(objectGraph, data);
        }
        productLockup.adamId = id;
        productLockup.bundleId = contentAttributes.contentAttributeAsString(objectGraph, data, "bundleId");
        productPage.uber = createUber(objectGraph, data, clientIdentifierOverride);
        const useInlineUberStyle = productPage.uber && productPage.uber.style === "inline";
        productLockup.icon = content.iconFromData(objectGraph, data, {
            useCase: 10 /* content.ArtworkUseCase.ProductPageIcon */,
            withJoeColorPlaceholder: preprocessor.GAMES_TARGET || undefined,
        }, clientIdentifierOverride);
        productPage.title = name;
        productPage.isIncomplete = true;
        productLockup.title = name;
        productLockup.subtitle = lockups.subtitleFromData(objectGraph, data);
        productLockup.developerTagline = contentAttributes.contentAttributeAsString(objectGraph, data, "subtitle");
        productPage.regularPriceFormatted = mediaAttributes.attributeAsString(data, "regularPriceFormatted");
        productPage.logoArtwork = content.productLogoArtworkFromData(objectGraph, data);
        productPage.navigationBarIconArtwork = createNavigationBarIconArtwork(objectGraph, data, clientIdentifierOverride);
        if (!shouldSuppressReviews) {
            productLockup.rating = mediaAttributes.attributeAsNumber(data, "userRating.value");
        }
        // For the web client, we show an "Open in Mac App Store" button, which is shown on by basis of whether
        // the app's binary is compatible with macOS, so we need to pas this attribute.
        if (objectGraph.client.isWeb) {
            productLockup.isIOSBinaryMacOSCompatible = mediaAttributes.attributeAsBooleanOrFalse(data, "isIOSBinaryMacOSCompatible");
            productLockup.clickAction = lockups.actionFromData(objectGraph, data, metricsOptions, null);
        }
        // Add primary text color for tvOS
        if (objectGraph.client.isTV && serverData.isDefinedNonNullNonEmpty(productPage.uber)) {
            let backgroundColor;
            if (serverData.isDefinedNonNull(productPage.uber.video) &&
                serverData.isDefinedNonNull(productPage.uber.video.preview)) {
                backgroundColor = productPage.uber.video.preview.backgroundColor;
            }
            else if (serverData.isDefinedNonNull(productPage.uber.artwork)) {
                backgroundColor = productPage.uber.artwork.backgroundColor;
            }
            else if (serverData.isDefinedNonNull(productPage.uber.iconArtwork)) {
                backgroundColor = productPage.uber.iconArtwork.backgroundColor;
            }
            productPage.hasDarkUserInterfaceStyle = serverData.isDefinedNonNull(backgroundColor)
                ? color.isDarkColor(backgroundColor, 50)
                : false;
        }
        productLockup.children = lockups.childrenFromLockupData(objectGraph, data, {
            metricsOptions: metricsOptions,
            artworkUseCase: 1 /* content.ArtworkUseCase.LockupIconSmall */,
        });
        const productButtonAction = createProductLockupButtonAction(objectGraph, data, productLockup.icon, shelfMetrics, metricsOptions, options, productReferrerData);
        productLockup.buttonAction = productButtonAction.buttonAction;
        // Release date and pre-order treatment
        if (isPreorder) {
            // Apply theme
            productPage.theme = "blue";
            // Create expanded offer
            let expandedOfferTitle;
            let expandedOfferSubtitle = null;
            if (supportsArcade) {
                expandedOfferTitle = "";
                expandedOfferSubtitle = objectGraph.loc.uppercased(content.dynamicPreorderDateFromData(objectGraph, data, objectGraph.loc.string("Offer.Expanded.Title.ComingSoon")));
            }
            else {
                expandedOfferTitle = objectGraph.loc.string("Offer.Expanded.Title.ComingSoon");
                if (serverData.isDefinedNonNull(productButtonAction.offerAction.expectedReleaseDate)) {
                    const dateFormat = "MMM d, yyyy";
                    const formattedReleaseDate = objectGraph.loc.formatDate(dateFormat, productButtonAction.offerAction.expectedReleaseDate);
                    const fallbackLabel = objectGraph.loc
                        .string("PREORDER_EXPANDED_OFFER_SUBTITLE")
                        .replace("{releaseDate}", formattedReleaseDate);
                    expandedOfferSubtitle = content.dynamicPreorderDateFromData(objectGraph, data, fallbackLabel);
                }
                else if (objectGraph.client.isTV) {
                    // The top lockup for tvOS does not display the expandedOfferTitle on the product page,
                    // so populate the subtitle with `Coming Soon` instead if there is no expected release date.
                    expandedOfferSubtitle = objectGraph.loc.string("Offer.Expanded.Title.ComingSoon");
                }
            }
            productPage.expandedOfferDetails = new models.ProductPageExpandedOfferDetails(expandedOfferTitle, expandedOfferSubtitle);
        }
        if (useInlineUberStyle && supportsArcade) {
            productPage.theme = "white";
        }
        // Buy Offer
        let offerStyle;
        let offerEnvironment;
        if (useInlineUberStyle && supportsArcade) {
            offerStyle = "white";
            offerEnvironment = "arcadeProductPage";
        }
        else {
            offerStyle = "colored";
            offerEnvironment = "productPage";
        }
        const titleOfferEnvironment = objectGraph.client.isVision || objectGraph.client.isiOS ? "navigationBar" : "productPage";
        const titleOfferStyle = "colored";
        const offerType = supportsArcade ? "arcadeApp" : "app";
        const offerContext = ((_a = options === null || options === void 0 ? void 0 : options.webBrowser) !== null && _a !== void 0 ? _a : false) ? "productPageBrowserChoice" : "productPage";
        productLockup.offerDisplayProperties = offers.displayPropertiesFromOfferAction(objectGraph, productButtonAction.offerAction, offerType, data, isPreorder, false, offerStyle, offerEnvironment, null, null, offerContext, false, false, clientIdentifierOverride);
        productPage.titleOfferDisplayProperties = offers.displayPropertiesFromOfferAction(objectGraph, productButtonAction.offerAction, offerType, data, isPreorder, false, titleOfferStyle, titleOfferEnvironment, null, null, offerContext);
        // Developer
        let developerAction;
        const developer = mediaRelationship.relationshipData(objectGraph, data, "developer");
        const developerUrl = content.developerUrlFromDeveloperData(objectGraph, developer);
        if (serverData.isDefinedNonNull(developerUrl)) {
            developerAction = new models.FlowAction("page");
            developerAction.title = mediaAttributes.attributeAsString(data, "artistName");
            developerAction.pageUrl = developerUrl;
            metricsHelpersClicks.addClickEventToAction(objectGraph, developerAction, {
                targetType: "button",
                id: developer.id,
                actionType: "navigate",
                pageInformation: shelfMetrics.metricsPageInformation,
                locationTracker: shelfMetrics.locationTracker,
            });
            if (objectGraph.client.isWeb) {
                developerAction.destination = makeDeveloperPageIntent({
                    ...getLocale(objectGraph),
                    id: developer.id,
                });
            }
        }
        productPage.developerAction = developerAction;
        // Add share action
        productPage.shareAction = sharing.shareProductActionFromData(objectGraph, data, shelfMetrics.metricsPageInformation, shelfMetrics.locationTracker, clientIdentifierOverride);
        // Tertiary badge
        productLockup.tertiaryTitle = lockups.badgeFromData(objectGraph, data);
        productLockup.tertiaryTitleAction = lockups.badgeActionFromData(objectGraph, data);
        productLockup.tertiaryTitleArtwork = lockups.badgeArtworkFromData(objectGraph, data);
        // Banner Context
        const appPlatforms = content.supportedAppPlatformsFromData(objectGraph, data);
        const bannerContext = {
            appPlatforms: appPlatforms,
            clientIdentifierOverride: clientIdentifierOverride,
            offerButtonShouldBeDisabled: false,
            metricsPageInformation: shelfMetrics.metricsPageInformation,
            metricsLocationTracker: shelfMetrics.locationTracker,
            webBrowser: options === null || options === void 0 ? void 0 : options.webBrowser,
        };
        // Show Banner if present, otherwise show AppStateBanner.
        const bannerToDisplay = banner.create(objectGraph, data, bannerContext);
        if (bannerToDisplay instanceof models.Banner) {
            productPage.banner = bannerToDisplay;
        }
        else if (bannerToDisplay instanceof models.AppStateBanner) {
            productPage.appStateBanner = bannerToDisplay;
        }
        const offerDisplayProperties = productLockup.offerDisplayProperties;
        if (bannerContext.offerButtonShouldBeDisabled && serverData.isDefinedNonNullNonEmpty(offerDisplayProperties)) {
            productLockup.offerDisplayProperties = offerDisplayProperties.newOfferDisplayPropertiesChangingAppearance(false, "disabled");
        }
        // Configure in-line updates for product page
        const isMininimumOSRequirementMet = !filtering.shouldFilter(objectGraph, data, 512 /* filtering.Filter.MinimumOSRequirement */);
        if (!isFirstPartyHideableApp && !bannerContext.offerButtonShouldBeDisabled && isMininimumOSRequirementMet) {
            const updateOfferData = offers.updateOfferDataFromData(objectGraph, data);
            productPage.updateBuyParams = serverData.asString(updateOfferData, "buyParams");
            productPage.externalVersionIdentifier = contentAttributes.contentAttributeAsNumber(objectGraph, data, "externalVersionId");
        }
        // Description header
        if (objectGraph.client.isTV) {
            if (productLockup.developerTagline) {
                productPage.descriptionHeader = objectGraph.loc
                    .string("PRODUCT_DESCRIPTION_HEADER")
                    .replace("{title}", productPage.title)
                    .replace("{subtitle}", productLockup.developerTagline);
            }
            else {
                productPage.descriptionHeader = productPage.title;
            }
            productPage.description = descriptionShelf.paragraphFromData(objectGraph, data);
        }
        if (supportsArcade) {
            productLockup.editorialTagline = objectGraph.loc.string("APPLE_ARCADE");
        }
        // Badges
        if (objectGraph.client.isTV || objectGraph.client.isWatch || objectGraph.client.isVision) {
            const embeddedInRibbon = objectGraph.client.isVision;
            productPage.badges = productBadges.badgesFromResponse(objectGraph, data, embeddedInRibbon, {
                locationTracker: shelfMetrics.locationTracker,
                pageInformation: shelfMetrics.metricsPageInformation,
            });
        }
        productPage.lockup = productLockup;
        productPage.appPlatforms = content.supportedAppPlatformsFromData(objectGraph, data);
        // App Promotion
        if (serverData.isDefinedNonNull(appPromotionData)) {
            const appPromotionOrDate = appPromotion.appPromotionOrDateFromData(objectGraph, appPromotionData, data, false, false, "dark", "white", true, metricsOptions, true, false, null, false, false);
            if (serverData.isDefinedNonNull(appPromotionData) && appPromotionOrDate instanceof models.AppPromotion) {
                const appPromotionItem = appPromotionOrDate;
                productPage.appPromotionDetailPageFlowAction = appPromotion.detailPageFlowActionFromData(objectGraph, appPromotionData, data, appPromotionItem, metricsOptions, "never", false, appEventReferrerData);
            }
        }
        addSidePackShelfMappingToProductPage(objectGraph, productPage, data, shelfMetrics, options, isViewOnly);
        if (productPage.uber && !objectGraph.client.isVision) {
            productPage.presentationOptions.push("prefersOverlayedPageHeader");
            productPage.presentationOptions.push("prefersNonStandardBackButton");
        }
        productPage.alwaysAllowReviews = reviews.shouldAllowReviewsForSADApp(objectGraph, data);
        /**
         * Adverts: Apply metrics to the lockup action and the back button
         */
        const iAdDismissAdActionMetrics = options === null || options === void 0 ? void 0 : options.iAdDismissAdActionMetrics;
        if (isSome(iAdDismissAdActionMetrics)) {
            const dismissActionMetrics = new AdvertActionMetrics(serverData.asString(iAdDismissAdActionMetrics.instanceId), serverData.asString(iAdDismissAdActionMetrics.adamId), serverData.asString(iAdDismissAdActionMetrics.bundleId), serverData.asString(iAdDismissAdActionMetrics.advertType), serverData.asString(iAdDismissAdActionMetrics.invocation), serverData.asString(iAdDismissAdActionMetrics.purchaseType), serverData.asString(iAdDismissAdActionMetrics.reportingDestination));
            const adInteractionAction = new AdInteractionAction(dismissActionMetrics);
            productPage.pageDisappearedAction = adInteractionAction;
            const buyActionMetrics = new AdvertActionMetrics(serverData.asString(iAdDismissAdActionMetrics.instanceId), serverData.asString(iAdDismissAdActionMetrics.adamId), serverData.asString(iAdDismissAdActionMetrics.bundleId), serverData.asString(iAdDismissAdActionMetrics.advertType), "offerButtonPress", serverData.asString(iAdDismissAdActionMetrics.purchaseType), serverData.asString(iAdDismissAdActionMetrics.reportingDestination));
            productPage.lockup.buttonAction = attachAdActionMetricsToAction(objectGraph, productPage.lockup.buttonAction, buyActionMetrics);
        }
        return productPage;
    });
}
/**
 * Creates the shelf metrics for a side pack.
 * @param data The data describing the side pack.
 * @param options The side pack options.
 */
function createSidePackShelfMetrics(objectGraph, data, options) {
    const productUrl = mediaAttributes.attributeAsString(data, "url");
    const name = mediaAttributes.attributeAsString(data, "name");
    const artistName = mediaAttributes.attributeAsString(data, "artistName");
    let iAdClickInfo = null;
    if (options) {
        iAdClickInfo = options.iAdClickFields;
    }
    const pageInformation = metricsHelpersPage.fakeMetricsPageInformation(objectGraph, "Software", data.id, `${artistName}_${name}`, iAdClickInfo);
    pageInformation.pageUrl = productUrl;
    const locationTracker = metricsHelpersLocation.newLocationTracker();
    return new ProductPageShelfMetrics(pageInformation, locationTracker);
}
/**
 * Creates the shelf metrics for a product page response.
 * @param response The product page response.
 * @param options The product page options.
 */
function createProductPageShelfMetrics(objectGraph, response, options) {
    var _a;
    const productData = mediaDataStructure.dataFromDataContainer(objectGraph, response);
    const isBundle = productData.type === "app-bundles";
    // Add the toro data for the click to the page data
    if (serverData.isDefinedNonNull(options)) {
        if (options.iAdClickFields) {
            response[metricsHelpersModels.iAdURLParameterStringToken] = JSON.stringify(options.iAdClickFields);
        }
        if (options.iAdLineItem) {
            response[metricsHelpersModels.iAdURLLineItemParameterStringToken] = options.iAdLineItem;
        }
    }
    // <rdar://problem/33764430> Toro: iAd is missing AD_OPEN figaro event when tapping on ad and pressing OPEN through the product page
    const pageType = isBundle ? "SoftwareBundle" : "Software";
    const pageInformation = metricsHelpersPage.metricsPageInformationFromMediaApiResponse(objectGraph, pageType, productData.id, response);
    const pageUrl = new urls.URL(pageInformation.pageUrl);
    const isWebBrowserContext = (_a = options === null || options === void 0 ? void 0 : options.webBrowser) !== null && _a !== void 0 ? _a : false;
    if (isWebBrowserContext) {
        // If this is the web browser context, swap the `webBrowser=1` param with `context=browserChoice`.
        pageUrl.param("context", "browserChoice");
        pageUrl.removeParam("webBrowser");
        pageInformation.pageUrl = pageUrl.build();
    }
    const locationTracker = metricsHelpersLocation.newLocationTracker();
    return new ProductPageShelfMetrics(pageInformation, locationTracker);
}
/**
 * When configuring a product page, it might be the case that we are doing so with
 * the intention of 'spotlighting' a particular section. This essentially means
 * that the context of the product page presentation dictates a particular section
 * appear at the top (just underneath the top lockup). This function applies these
 * spotlighting options to the product page.
 * @param options   The options for the product page.
 * @param productPage
 */
function applySpotlightOptions(objectGraph, options, productPage) {
    if (options && options.spotlightSection) {
        const spotlightId = options.spotlightInAppProductIdentifier;
        if (spotlightId && options.spotlightSection) {
            const shelf = productPage.shelfMapping[options.spotlightSection.shelfId];
            if (!shelf) {
                return;
            }
            // Apply Presentation Hints
            shelf.presentationHints = { isInProductPageSpotlight: true };
            // Shelf Items
            productPageCommon.moveLockupToFront(objectGraph, spotlightId, shelf.items);
            // Shelf URL
            if (shelf.url) {
                const url = new urls.URL(shelf.url);
                if (url) {
                    shelf.url = url.param(Parameters.offerName, spotlightId).build();
                }
            }
        }
    }
}
function addSidePackShelfMappingToProductPage(objectGraph, productPage, data, shelfMetrics, options, isViewOnly) {
    productPage.shelfMapping["topLockup"] = new models.Shelf("marker", "productTopLockup");
    if (objectGraph.client.deviceType !== "tv" && !objectGraph.client.isVision) {
        const descriptionShelfContext = {
            developerAction: productPage.developerAction,
        };
        productPage.shelfMapping["description"] = descriptionShelf.create(objectGraph, data, shelfMetrics, descriptionShelfContext);
    }
    // Badges
    if (objectGraph.client.isWeb || objectGraph.client.isiOS || objectGraph.client.isMac) {
        const ribbonShelfContext = {
            useInlineUberStyle: productPage.uber && productPage.uber.style === "inline",
        };
        productPage.shelfMapping["informationRibbon"] = ribbonShelf.create(objectGraph, data, shelfMetrics, ribbonShelfContext);
    }
    addShelfOrderingToProductPage(objectGraph, productPage, [], content.isArcadeSupported(objectGraph, data), options);
}
async function addFullProductShelfMappingToProductPage(objectGraph, productPage, data, shelfMetrics, options, refreshController, isViewOnly) {
    var _a, _b, _c;
    const appPlatforms = content.supportedAppPlatformsFromData(objectGraph, data);
    const isBundle = data.type === "app-bundles";
    const isPreorder = mediaAttributes.attributeAsBoolean(data, "isPreorder");
    const macOnlyApp = appPlatforms.length === 1 && appPlatforms[0] === "mac";
    const shouldShowMacOnlyReviews = !macOnlyApp || objectGraph.client.isMac;
    const shouldSuppressReviews = reviews.shouldSuppressReviews(objectGraph, data);
    const shouldShowRatingsAndReviews = (shouldShowMacOnlyReviews || objectGraph.client.isWeb) && !isPreorder && !shouldSuppressReviews;
    const clientIdentifierOverride = serverData.isDefinedNonNullNonEmpty(options)
        ? options.clientIdentifierOverride
        : null;
    const isFirstPartyHideableApp = mediaAttributes.attributeAsBooleanOrFalse(data, "isFirstPartyHideableApp");
    const offerDisplayProperties = productPage.lockup.offerDisplayProperties;
    const isFreeProduct = serverData.isDefinedNonNull(offerDisplayProperties) ? offerDisplayProperties.isFree : true;
    // Bundle Children
    let bundleChildren;
    if (isBundle) {
        const childrenRelationship = mediaRelationship.relationship(data, "apps");
        bundleChildren = bundleChildrenShelf.create(objectGraph, data, childrenRelationship, shelfMetrics);
    }
    if (bundleChildren) {
        productPage.shelfMapping["bundleChildren"] = bundleChildren;
    }
    // Bundles This App Is Part Of
    const bundleParentRelationship = mediaRelationship.relationship(data, "app-bundles");
    const bundleParents = bundleParentsShelf.create(objectGraph, data, bundleParentRelationship, shelfMetrics);
    if (bundleParents) {
        productPage.shelfMapping["bundleParents"] = bundleParents;
    }
    if (preprocessor.GAMES_TARGET) {
        productPage.gamesResponse = makeGamesResponse(objectGraph, data);
    }
    const ratingsAndReviewsShelfContext = {
        productTitle: productPage.title,
        shouldShowRatingsAndReviews: shouldShowRatingsAndReviews,
        isFirstPartyHideableApp: isFirstPartyHideableApp,
        isBundle: isBundle,
        isPreorder: isPreorder,
    };
    const ratingsAndReviewsShelves = reviewsShelf.createReviewsShelves(objectGraph, data, shelfMetrics, ratingsAndReviewsShelfContext, productPage.lockup.subtitle);
    if (serverData.isDefinedNonNullNonEmpty(ratingsAndReviewsShelves)) {
        productPage.shelfMapping["purchasedRatingsAndReviews"] =
            ratingsAndReviewsShelves.purchasedRatingsAndReviewsComponentShelf;
        productPage.shelfMapping["notPurchasedRatingsAndReviews"] =
            ratingsAndReviewsShelves.notPurchasedRatingsAndReviewsComponentShelf;
        productPage.shelfMapping["productRatings"] = ratingsAndReviewsShelves.ratingsShelf;
        productPage.shelfMapping["allProductReviewActions"] = ratingsAndReviewsShelves.allReviewActionsShelf;
        productPage.shelfMapping["allProductReviews"] = ratingsAndReviewsShelves.allProductReviewsShelf;
        productPage.shelfMapping["userProductReviews"] = ratingsAndReviewsShelves.userProductReviewsShelf;
        if (objectGraph.client.isiOS) {
            productPage.shelfMapping["editorsChoice"] = createEditorsChoiceShelf(objectGraph, data);
        }
        else {
            productPage.shelfMapping["editorsChoiceProductReviews"] =
                ratingsAndReviewsShelves.editorsChoiceProductReviewsShelf;
        }
        productPage.shelfMapping["tapToRateProductReviewAction"] = ratingsAndReviewsShelves.tapToRateActionsShelf;
        productPage.shelfMapping["writeAReviewProductReviewAction"] = ratingsAndReviewsShelves.writeAReviewActionsShelf;
        productPage.shelfMapping["productReviewsHeader"] = ratingsAndReviewsShelves.productReviewsHeader;
    }
    if (objectGraph.client.isiOS) {
        const productReviewsFooter = reviewsShelf.createProductReviewsLearnMoreShelf(objectGraph);
        if (isSome(productReviewsFooter)) {
            productPage.shelfMapping["productReviewsFooter"] = productReviewsFooter;
        }
    }
    const reviewSummary = reviewsShelf.createReviewSummary(objectGraph, data, shelfMetrics);
    if (isSome(reviewSummary) && objectGraph.client.isiOS) {
        productPage.shelfMapping["reviewSummary"] = reviewSummary;
    }
    // Most Recent Version
    const versionHistoryShelfContext = {
        isFirstPartyHideableApp: isFirstPartyHideableApp,
        isBundle: isBundle,
        isPreorder: isPreorder,
    };
    const mostRecentVersion = versionHistoryShelves.create(objectGraph, data, shelfMetrics, versionHistoryShelfContext);
    if (mostRecentVersion) {
        productPage.shelfMapping["mostRecentVersion"] = mostRecentVersion;
    }
    productPage.shelfMapping["textCards"] = textCardsShelf.create(objectGraph, data, shelfMetrics);
    // Privacy
    const bundleId = contentAttributes.contentAttributeAsString(objectGraph, data, "bundleId");
    if (objectGraph.bag.enablePrivacyNutritionLabels &&
        !privacySuppression.shouldSuppressPrivacyInformationForAdamId(objectGraph, data.id) &&
        !privacySuppression.shouldSuppressPrivacyInformationForBundleId(objectGraph, bundleId)) {
        const privacyHeader = privacyHeaderShelf.create(objectGraph, data, shelfMetrics.metricsPageInformation, shelfMetrics.locationTracker);
        const privacyTypes = privacyTypesShelf.create(objectGraph, data, shelfMetrics);
        if (serverData.isDefinedNonNull(privacyHeader) &&
            (serverData.isDefinedNonNull(privacyTypes) || objectGraph.client.isWatch)) {
            productPage.shelfMapping["privacyHeader"] = privacyHeader;
            if (serverData.isDefinedNonNull(privacyTypes)) {
                productPage.shelfMapping["privacyTypes"] = privacyTypes;
            }
            const privacyFooter = privacyFooterShelf.create(objectGraph, data, shelfMetrics.metricsPageInformation, shelfMetrics.locationTracker);
            if (serverData.isDefinedNonNull(privacyFooter)) {
                productPage.shelfMapping["privacyFooter"] = privacyFooter;
            }
        }
    }
    // Information
    const ageRatingBadgeActionMetadata = new productBadgesCommon.BadgeActionMetadata();
    const languageBadgeActionMetadata = new productBadgesCommon.BadgeActionMetadata();
    const sizeBadgeActionMetadata = new productBadgesCommon.BadgeActionMetadata();
    const categoryBadgeActionMetadata = new productBadgesCommon.BadgeActionMetadata();
    const highMotionBadgeActionMetadata = new productBadgesCommon.BadgeActionMetadata();
    const metadataHandler = (factory, annotation, currentIndex) => {
        var _a, _b;
        if (factory === contentRatingAnnotation.createAnnotation) {
            ageRatingBadgeActionMetadata.setShelfId("information", currentIndex);
            ageRatingBadgeActionMetadata.annotation = annotation;
            productPage.ageRatingAction = new models.ShelfBasedPageScrollAction("information", null, null, null, currentIndex, true);
            productPage.ageRatingAction.title = objectGraph.loc.string("ProductPage.Banner.AskForException.Review.ViewAgeRatingLink");
        }
        // If we have a product page banner which needs to scroll to a particular information section index, populate the index here
        if (factory === compatibilityAnnotation.createAnnotation && serverData.isDefinedNonNull(productPage.banner)) {
            // This banner has a variant that mentions the Support (Information) section. Since we now have a Support section,
            // overwrite the original `action` with the `fullProductAction`
            if (serverData.isDefinedNonNull(productPage.banner.fullProductAction)) {
                productPage.banner.action = productPage.banner.fullProductAction;
            }
            const action = productPage.banner.action;
            if (serverData.isDefinedNonNull(action)) {
                if (productPageUtil.isShelfBased(objectGraph)) {
                    if (action instanceof models.ShelfBasedPageScrollAction &&
                        ((_a = action.shelfId) === null || _a === void 0 ? void 0 : _a.length) > 0 &&
                        action.shelfId === "information" &&
                        action.indexId === "compatibilityAnnotation") {
                        action.index = currentIndex;
                    }
                }
                else {
                    if (action instanceof models.ProductPageScrollAction &&
                        ((_b = action.section.shelfId) === null || _b === void 0 ? void 0 : _b.length) > 0 &&
                        action.section.shelfId === "information" &&
                        action.indexId === "compatibilityAnnotation") {
                        action.index = currentIndex;
                    }
                }
            }
        }
        if (factory === languageAnnotation.createAnnotation) {
            languageBadgeActionMetadata.setShelfId("information", currentIndex);
            languageBadgeActionMetadata.annotation = annotation;
        }
        if (factory === sizeAnnotation.createAnnotation) {
            sizeBadgeActionMetadata.setShelfId("information", currentIndex);
            sizeBadgeActionMetadata.annotation = annotation;
        }
        if (factory === categoryAnnotation.createAnnotation) {
            categoryBadgeActionMetadata.setShelfId("information", currentIndex);
            categoryBadgeActionMetadata.annotation = annotation;
        }
        if (factory === highMotionAnnotation.createAnnotation) {
            highMotionBadgeActionMetadata.setShelfId("information", currentIndex);
            highMotionBadgeActionMetadata.annotation = annotation;
        }
    };
    const supportsArcade = content.isArcadeSupported(objectGraph, data);
    const information = annotationsShelf.create(objectGraph, data, isFirstPartyHideableApp, shelfMetrics, metadataHandler, supportsArcade, isFreeProduct, false);
    if (information) {
        productPage.shelfMapping["information"] = information;
    }
    // App Events
    const appEvents = appPromotionsShelf.appPromotionsShelfForProductPage(objectGraph, data, shelfMetrics, refreshController);
    if (serverData.isDefinedNonNull(appEvents)) {
        productPage.shelfMapping["appEvents"] = appEvents;
    }
    // Editorial Quote
    if (supportsArcade) {
        const editorialQuote = editorialQuoteShelf.create(objectGraph, data, shelfMetrics);
        if (editorialQuote) {
            productPage.shelfMapping["editorialQuote"] = editorialQuote;
        }
    }
    // Links
    // If the app is purchased, we will show the link for report a problem
    productPage.shelfMapping["notPurchasedLinks"] = linksShelf.create(objectGraph, data, shelfMetrics, false, isFreeProduct, supportsArcade);
    productPage.shelfMapping["purchasedLinks"] = linksShelf.create(objectGraph, data, shelfMetrics, true, isFreeProduct, supportsArcade);
    productPage.shelfMapping["textLinksShelf"] = textLinksShelf.create(objectGraph, data, shelfMetrics);
    // Capabilities
    const capabilities = capabilitiesShelf.create(objectGraph, data, isFreeProduct, shelfMetrics);
    if (capabilities) {
        productPage.shelfMapping["capabilities"] = capabilities;
    }
    const isWebBrowserContext = (_a = options === null || options === void 0 ? void 0 : options.webBrowser) !== null && _a !== void 0 ? _a : false;
    // Featured In
    if (!objectGraph.client.isVision && !isWebBrowserContext) {
        const featuredInContainer = mediaRelationship.relationship(data, "related-editorial-items");
        if (serverData.isDefinedNonNullNonEmpty(featuredInContainer)) {
            const isSmallStoryCardsSupported = objectGraph.host.isiOS || objectGraph.host.isMac || objectGraph.host.isWeb;
            const featuredIn = isSmallStoryCardsSupported
                ? smallStoryCardShelf.createInitialShelf(objectGraph, data, featuredInContainer.data, shelfMetrics)
                : featuredInShelf.create(objectGraph, data, featuredInContainer, shelfMetrics);
            if (featuredIn) {
                productPage.shelfMapping["featuredIn"] = featuredIn;
            }
        }
    }
    // Friends Playing
    const friendsPlayingShelfContext = {
        isPreorder: isPreorder,
    };
    const friendsPlayingBadgeActionMetadata = new productBadgesCommon.BadgeActionMetadata();
    const friendsPlaying = friendsPlayingShelf.create(objectGraph, data, shelfMetrics, friendsPlayingShelfContext);
    if (friendsPlaying) {
        productPage.shelfMapping["friendsPlaying"] = friendsPlaying;
        friendsPlayingBadgeActionMetadata.setShelfId("friendsPlaying");
    }
    // Achievements
    const achievementsShelfContext = {
        isPreorder: isPreorder,
    };
    const achievements = achievementsShelf.create(objectGraph, data, shelfMetrics, achievementsShelfContext);
    if (achievements) {
        productPage.shelfMapping["achievements"] = achievements;
    }
    // More by Developer
    if (!isViewOnly && !isWebBrowserContext) {
        const moreByDeveloper = moreByDeveloperShelf.createInitialShelf(objectGraph, data, shelfMetrics);
        if (isSome(moreByDeveloper)) {
            productPage.shelfMapping["moreByDeveloper"] = moreByDeveloper;
        }
    }
    // Similar Items
    if (!isViewOnly && !isWebBrowserContext) {
        const similarItems = similarItemsShelf.createInitialShelf(objectGraph, data, shelfMetrics);
        if (isSome(similarItems)) {
            productPage.shelfMapping["similarItems"] = similarItems;
        }
    }
    // Subscriptions
    const subscriptionsShelfContext = {
        isForSubscriptions: true,
        options: options,
    };
    const subscriptionsResult = await tryAwait(inAppPurchasesShelf.create(objectGraph, data, shelfMetrics, subscriptionsShelfContext));
    if (subscriptionsResult.success && isSome(subscriptionsResult.value)) {
        productPage.shelfMapping["subscriptions"] = subscriptionsResult.value;
    }
    // In-App Purchases
    const inAppPurchaseShelfContext = {
        isForSubscriptions: false,
        options: options,
    };
    const inAppPurchasesResult = await tryAwait(inAppPurchasesShelf.create(objectGraph, data, shelfMetrics, inAppPurchaseShelfContext));
    if (inAppPurchasesResult.success && isSome(inAppPurchasesResult.value)) {
        productPage.shelfMapping["inAppPurchases"] = inAppPurchasesResult.value;
    }
    const productMediaShelves = productMediaShelf.create(objectGraph, data, clientIdentifierOverride, shelfMetrics);
    productPage.shelfMapping = {
        ...productPage.shelfMapping,
        ...productMediaShelves.shelfMapping,
    };
    // We need to extract the device family that matches the screenshots we display, for the accesssibility shelves
    const firstMediaAppPlatform = (_b = productMediaShelves === null || productMediaShelves === void 0 ? void 0 : productMediaShelves.allProductMedia[0]) === null || _b === void 0 ? void 0 : _b.mediaPlatform.appPlatform;
    const deviceFamily = deviceFamilyForAccessibilityLabels(firstMediaAppPlatform);
    const actionLinksShelfContext = {
        productTitle: productPage.title,
        shouldShowRatingsAndReviews: shouldShowRatingsAndReviews,
        isFirstPartyHideableApp: isFirstPartyHideableApp,
        isBundle: isBundle,
        isPreorder: isPreorder,
        isArcadeApp: supportsArcade,
        isFreeProduct: isFreeProduct,
        deviceFamily: deviceFamily,
    };
    const actionLinks = actionLinksShelf.create(objectGraph, data, shelfMetrics, actionLinksShelfContext);
    if (actionLinks) {
        productPage.shelfMapping["actionLinks"] = actionLinks;
    }
    // Accessibility Support
    const isWebViewingWatch = objectGraph.client.isWeb && ((_c = objectGraph.activeIntent) === null || _c === void 0 ? void 0 : _c.platform) === "watch";
    if (!objectGraph.client.isWatch &&
        !isWebViewingWatch &&
        isSome(deviceFamily) &&
        accessibilityShelves.shouldShowAccessibilitySection(objectGraph, data, deviceFamily)) {
        const accessibilityHeader = accessibilityShelves.createHeaderShelf(objectGraph, data, deviceFamily, false, shelfMetrics, shelfMetrics.metricsPageInformation, shelfMetrics.locationTracker);
        productPage.shelfMapping["accessibilityHeader"] = accessibilityHeader;
        const accessibilityFeatures = accessibilityShelves.createFeaturesShelf(objectGraph, data, deviceFamily, false, shelfMetrics, shelfMetrics.metricsPageInformation, shelfMetrics.locationTracker);
        if (isSome(accessibilityFeatures)) {
            productPage.shelfMapping["accessibilityFeatures"] = accessibilityFeatures;
        }
        const accessibilityDeveloperLink = accessibilityShelves.createDeveloperLinkShelf(objectGraph, data, false, shelfMetrics.metricsPageInformation, shelfMetrics.locationTracker);
        if (isSome(accessibilityDeveloperLink)) {
            productPage.shelfMapping["accessibilityDeveloperLink"] = accessibilityDeveloperLink;
        }
    }
    if (objectGraph.client.isiOS) {
        const placementId = supportsArcade
            ? "arcadeProductPageInlineMessage"
            : "productPageInlineMessage";
        const unifiedMessageShelf = shelfForUnifiedMessage(objectGraph, placementId);
        productPage.shelfMapping[placementId] = unifiedMessageShelf;
    }
    applySpotlightOptions(objectGraph, options, productPage);
    const badgeActionMetadataByKey = {};
    const contentRatingKey = "contentRating";
    const storefrontContentRatingKey = "storefrontContentRating";
    const languageKey = "languages";
    const sizeKey = "size";
    const categoryKey = "category";
    const friendsPlayingType = "friendsPlaying";
    const highMotionType = "highMotion";
    badgeActionMetadataByKey[contentRatingKey] = ageRatingBadgeActionMetadata;
    badgeActionMetadataByKey[storefrontContentRatingKey] = ageRatingBadgeActionMetadata;
    badgeActionMetadataByKey[languageKey] = languageBadgeActionMetadata;
    badgeActionMetadataByKey[sizeKey] = sizeBadgeActionMetadata;
    badgeActionMetadataByKey[categoryKey] = categoryBadgeActionMetadata;
    badgeActionMetadataByKey[friendsPlayingType] = friendsPlayingBadgeActionMetadata;
    badgeActionMetadataByKey[highMotionType] = highMotionBadgeActionMetadata;
    if (productPage.badges) {
        productBadgesCommon.applyActionMetadataToBadges(objectGraph, productPage.badges, badgeActionMetadataByKey, shelfMetrics);
    }
    // If we have an info ribbon, we need to apply actions to badges there too.
    if (productPage.shelfMapping["informationRibbon"] != null) {
        productBadgesCommon.applyActionMetadataToBadges(objectGraph, productPageUtil.badgesFromInfoRibbonShelf(objectGraph, productPage.shelfMapping["informationRibbon"]), badgeActionMetadataByKey, shelfMetrics);
    }
    addShelfOrderingToProductPage(objectGraph, productPage, productMediaShelves.sectionMappings, supportsArcade, options);
}
function addShelfOrderingToProductPage(objectGraph, productPage, productMediaSectionMappings, supportsArcade, options) {
    const mapShelfOrderings = function (originalShelfOrdering, mediaSection, isMediaExpanded) {
        const updatedSectionMappings = originalShelfOrdering
            .map((sectionMapping) => {
            if (sectionMapping.shelfId === "screenshots" && isMediaExpanded) {
                return productMediaSectionMappings;
            }
            else if (sectionMapping.shelfId === "screenshots") {
                return productMediaSectionMappings[0] ? [productMediaSectionMappings[0]] : [];
            }
            else {
                return [sectionMapping];
            }
        })
            .reduce((previousValue, currentValue) => {
            return previousValue.concat(currentValue);
        });
        return productPageShelfIdsFromMappings(updatedSectionMappings);
    };
    const purchasedOrdering = shelfBasedProductOrdering.sectionOrdering(objectGraph, true, objectGraph.host.platform, supportsArcade, false, false, options);
    const notPurchasedOrdering = shelfBasedProductOrdering.sectionOrdering(objectGraph, false, objectGraph.host.platform, supportsArcade, false, false, options);
    const purchasedOrderingCompact = shelfBasedProductOrdering.sectionOrdering(objectGraph, true, objectGraph.host.platform, supportsArcade, true, false, options);
    const notPurchasedOrderingCompact = shelfBasedProductOrdering.sectionOrdering(objectGraph, false, objectGraph.host.platform, supportsArcade, true, false, options);
    const downloadingOrdering = shelfBasedProductOrdering.sectionOrdering(objectGraph, false, objectGraph.host.platform, supportsArcade, false, true, options);
    const downloadingOrderingCompact = shelfBasedProductOrdering.sectionOrdering(objectGraph, false, objectGraph.host.platform, supportsArcade, true, true, options);
    productPage.shelfOrderings[models.shelfBasedProductPageOrderingIdPurcahsed] = mapShelfOrderings(purchasedOrdering, productMediaSectionMappings, false);
    productPage.shelfOrderings[models.shelfBasedProductPageOrderingIdPurcahsedExpandedMedia] = mapShelfOrderings(purchasedOrdering, productMediaSectionMappings, true);
    productPage.shelfOrderings[models.shelfBasedProductPageOrderingIdNotPurcahsed] = mapShelfOrderings(notPurchasedOrdering, productMediaSectionMappings, false);
    productPage.shelfOrderings[models.shelfBasedProductPageOrderingIdNotPurcahsedExpandedMedia] = mapShelfOrderings(notPurchasedOrdering, productMediaSectionMappings, true);
    productPage.shelfOrderings[models.shelfBasedProductPageOrderingIdPurcahsedCompact] = mapShelfOrderings(purchasedOrderingCompact, productMediaSectionMappings, false);
    productPage.shelfOrderings[models.shelfBasedProductPageOrderingIdPurcahsedExpandedMediaCompact] = mapShelfOrderings(purchasedOrderingCompact, productMediaSectionMappings, true);
    productPage.shelfOrderings[models.shelfBasedProductPageOrderingIdNotPurcahsedCompact] = mapShelfOrderings(notPurchasedOrderingCompact, productMediaSectionMappings, false);
    productPage.shelfOrderings[models.shelfBasedProductPageOrderingIdNotPurcahsedExpandedMediaCompact] =
        mapShelfOrderings(notPurchasedOrderingCompact, productMediaSectionMappings, true);
    productPage.shelfOrderings[models.shelfBasedProductPageOrderingIdDownloading] = mapShelfOrderings(downloadingOrdering, productMediaSectionMappings, false);
    productPage.shelfOrderings[models.shelfBasedProductPageOrderingIdDownloadingExpandedMedia] = mapShelfOrderings(downloadingOrdering, productMediaSectionMappings, true);
    productPage.shelfOrderings[models.shelfBasedProductPageOrderingIdDownloadingCompact] = mapShelfOrderings(downloadingOrderingCompact, productMediaSectionMappings, false);
    productPage.shelfOrderings[models.shelfBasedProductPageOrderingIdDownloadingExpandedMediaCompact] =
        mapShelfOrderings(downloadingOrderingCompact, productMediaSectionMappings, true);
    productPage.defaultShelfOrdering = models.shelfBasedProductPageOrderingIdNotPurcahsed;
    for (const shelfId of Object.keys(productPage.shelfMapping)) {
        if (serverData.isDefinedNonNullNonEmpty(productPage.shelfMapping[shelfId])) {
            productPage.shelfMapping[shelfId].id = shelfId;
        }
    }
}
function productUberVideoPlaybackIdForProduct(data) {
    return `ProductPage.${data.id}.productUberVideoPlaybackId`;
}
export function createUber(objectGraph, data, clientIdentifierOverride) {
    const attributePlatform = content.iconAttributePlatform(objectGraph, data, clientIdentifierOverride);
    if (objectGraph.client.isVision && attributePlatform !== "xros") {
        // Ubers are reserved for native apps only
        return null;
    }
    const supportsArcade = content.isArcadeSupported(objectGraph, data);
    const uberStyle = shouldUseInlineUberStyle(objectGraph, supportsArcade) ? "inline" : "above";
    const uber = new models.Uber(uberStyle);
    uber.artwork = content.productUberFromData(objectGraph, data, {
        supportsArcade: supportsArcade,
    });
    if (objectGraph.client.isiOS) {
        uber.compactArtwork = content.productUberFromData(objectGraph, data, {
            supportsArcade: supportsArcade,
            prefersCompactVariant: true,
        });
    }
    uber.video = content.productEditorialVideoFromData(objectGraph, data, 21 /* content.ArtworkUseCase.Uber */);
    if (serverData.isDefinedNonNull(uber.video)) {
        uber.video.playbackId = productUberVideoPlaybackIdForProduct(data);
    }
    if (objectGraph.client.isTV || (objectGraph.client.isVision && attributePlatform === "xros")) {
        uber.iconArtwork = content.iconFromData(objectGraph, data, {
            useCase: 10 /* content.ArtworkUseCase.ProductPageIcon */,
            withJoeColorPlaceholder: objectGraph.client.isTV,
            allowingTransparency: !objectGraph.client.isTV,
        }, clientIdentifierOverride);
        if (objectGraph.client.isVision && isNothing(uber.artwork) && isNothing(uber.video)) {
            uber.style = "background";
        }
    }
    // If this is an Arcade app, but we don't have an Arcade Uber to show, use the first video/screenshot instead.
    if (supportsArcade &&
        serverData.isNullOrEmpty(uber.video) &&
        serverData.isNullOrEmpty(uber.artwork) &&
        !objectGraph.client.isVision) {
        const includedAppPlatformsForProductMedia = includedAppPlatformsForProductMediaOnDevice(objectGraph, objectGraph.client.deviceType);
        const productVariantData = productPageVariants.productVariantDataForData(objectGraph, data);
        const productMedia = content.productMediaFromData(objectGraph, data, 11 /* content.ArtworkUseCase.ProductPageScreenshots */, includedAppPlatformsForProductMedia, productVariantData, clientIdentifierOverride);
        if (productMedia.length > 0 && productMedia[0].items.length > 0) {
            const topAsset = productMedia[0].items[0];
            uber.video = topAsset.video;
            uber.artwork = topAsset.screenshot;
        }
    }
    // Defer to uberArtwork if no uberArtworkForCompactDisplay exists.
    if (serverData.isNullOrEmpty(uber.compactArtwork) && objectGraph.client.isiOS) {
        uber.compactArtwork = uber.artwork;
    }
    return uber.isValidUber(objectGraph.client.isTV, objectGraph.client.isVision) ? uber : null;
}
/**
 * Creates the icon artwork to display in the navigation bar of the product page. Currently only used on visionOS.
 * @param objectGraph Current object graph.
 * @param data The product data.
 * @param clientIdentifierOverride Any client identifier override.
 * @returns An artwork representing the icon, or null.
 */
function createNavigationBarIconArtwork(objectGraph, data, clientIdentifierOverride) {
    if (!objectGraph.client.isVision) {
        return null;
    }
    const iconArtwork = content.iconFromData(objectGraph, data, {
        useCase: 10 /* content.ArtworkUseCase.ProductPageIcon */,
    }, clientIdentifierOverride);
    return iconArtwork;
}
function createProductLockupButtonAction(objectGraph, data, productIcon, shelfMetrics, metricsOptions, options, referrerData) {
    var _a;
    const offerData = offers.offerDataFromData(objectGraph, data);
    const bundleId = contentAttributes.contentAttributeAsString(objectGraph, data, "bundleId");
    const isPreorder = mediaAttributes.attributeAsBoolean(data, "isPreorder");
    const metricsPlatformDisplayStyle = metricsUtil.metricsPlatformDisplayStyleFromData(objectGraph, data, productIcon, options === null || options === void 0 ? void 0 : options.clientIdentifierOverride);
    const offerAction = offers.offerActionFromOfferData(objectGraph, offerData, data, isPreorder, false, metricsPlatformDisplayStyle, metricsOptions, "productPage", referrerData, options === null || options === void 0 ? void 0 : options.webBrowser);
    if ((_a = options === null || options === void 0 ? void 0 : options.webBrowser) !== null && _a !== void 0 ? _a : false) {
        return {
            buttonAction: new SelectAppAction(data.id),
            offerAction: offerAction,
        };
    }
    let buttonAction;
    if (serverData.isDefinedNonNullNonEmpty(offerAction)) {
        if (serverData.isDefinedNonNull(options)) {
            offerAction.lineItem = options.iAdLineItem;
        }
        const clientIdentifierOverride = serverData.isDefinedNonNullNonEmpty(options)
            ? options.clientIdentifierOverride
            : null;
        buttonAction = offers.wrapOfferActionIfNeeded(objectGraph, offerAction, data, isPreorder, metricsOptions, "productPage", clientIdentifierOverride);
        if (serverData.isDefinedNonNull(options) && serverData.isDefinedNonNullNonEmpty(buttonAction)) {
            const attributePlatform = contentAttributes.defaultAttributePlatform(objectGraph);
            const productVariantData = productPageVariants.productVariantDataForData(objectGraph, data);
            const cppDeepLinkUrl = contentAttributes.customAttributeAsString(objectGraph, data, productVariantData, "customDeepLink", attributePlatform);
            const hasCppDeepLink = serverData.isDefinedNonNullNonEmpty(cppDeepLinkUrl) &&
                !serverData.asBooleanOrFalse(options.isCppDeepLinkDisabled);
            const hasExternalDeepLink = serverData.isDefinedNonNullNonEmpty(options.externalDeepLinkUrl);
            let deepLinkUrl;
            if (preprocessor.CARRY_BUILD || preprocessor.DEBUG_BUILD) {
                const hasAlignedRegionDeepLink = isSome(options.alignedRegionDeepLinkUrl);
                if (hasCppDeepLink || hasExternalDeepLink || hasAlignedRegionDeepLink) {
                    if (hasAlignedRegionDeepLink) {
                        deepLinkUrl = options.alignedRegionDeepLinkUrl;
                    }
                    else if (hasCppDeepLink) {
                        deepLinkUrl = cppDeepLinkUrl;
                    }
                    else {
                        deepLinkUrl = options.externalDeepLinkUrl;
                    }
                    buttonAction = externalDeepLink.deepLinkActionWrappingAction(objectGraph, buttonAction, offerAction.adamId, bundleId, deepLinkUrl, false, metricsOptions);
                }
            }
            else {
                if (hasCppDeepLink || hasExternalDeepLink) {
                    deepLinkUrl = hasCppDeepLink ? cppDeepLinkUrl : options.externalDeepLinkUrl;
                    buttonAction = externalDeepLink.deepLinkActionWrappingAction(objectGraph, buttonAction, offerAction.adamId, bundleId, deepLinkUrl, false, metricsOptions);
                }
            }
        }
    }
    return {
        buttonAction: buttonAction,
        offerAction: offerAction,
    };
}
/**
 * Returns the list of included app platforms for the product media shelves.
 * This is used to constrain some platforms to media type of just that platform, e.g. tvOS can only show tvOS screenshots and video.
 *
 * @param deviceType Device type to find the included app platforms for product media for.
 * @returns models.AppPlatform[] | null An array of supported app platforms for product media, or `null` if there are no constraints and should fallback to sorting logic in content.ts
 */
function includedAppPlatformsForProductMediaOnDevice(objectGraph, deviceType) {
    // We want to return all product media platforms, so that we can generate
    // the appropriate platform selector description text.
    return null;
}
/**
 * Source of truth for the decision on whether or not the product page should be displayed in the inline uber style
 *
 * @param supportsArcade     Does the product say it supports Arcade
 */
function shouldUseInlineUberStyle(objectGraph, supportsArcade) {
    if (objectGraph.client.isVision) {
        return true;
    }
    return supportsArcade && (objectGraph.client.isiOS || objectGraph.client.isMac);
}
//# sourceMappingURL=shelf-based-product-page.js.map