import { isNothing, isSome } from "@jet/environment";
import * as validation from "@jet/environment/json/validation";
import { FetchTimingMetricsBuilder } from "@jet/environment/metrics";
import * as models from "../../api/models";
import * as impressionDemotion from "../../common/personalization/on-device-impression-demotion";
import { asArrayOrEmpty, asBoolean, asString, isDefinedNonNull, isDefinedNonNullNonEmpty, isNullOrEmpty, } from "../../foundation/json-parsing/server-data";
import { hasAttributes } from "../../foundation/media/attributes";
import * as mediaDataFetching from "../../foundation/media/data-fetching";
import * as mediaDataStructure from "../../foundation/media/data-structure";
import { fetchData } from "../../foundation/media/network";
import { Parameters, Path } from "../../foundation/network/url-constants";
import { URL } from "../../foundation/network/urls";
import { optional, required } from "../../foundation/util/promise-util";
import { AppEventsAttributes } from "../../gameservicesui/src/foundation/media-api/requests/recommendation-request-types";
import { applySearchAdMissedOpportunityToShelvesIfNeeded, eligibleSlotPositionsForAdPlacement, iadInfoFromOnDeviceAdResponse, isAdPlacementEnabled, } from "../ads/ad-common";
import * as adIncidents from "../ads/ad-incident-recorder";
import { fetchAds, parallelOrganicRequestDidFinish } from "../ads/on-device-ad-fetch";
import * as appPromotionsCommon from "../app-promotions/app-promotions-common";
import { fetchPageWithAdditionalPageRequirements } from "../builders/additional-page-requirement-util";
import { pageRouter } from "../builders/routing";
import { shouldUsePrerenderedIconArtwork } from "../content/content";
import { shelfForFooterButtons, shelfForTermsAndConditions, shelfForUnifiedMessage } from "../grouping/grouping-common";
import { newLocationTracker } from "../metrics/helpers/location";
import { iAdInformationFromMediaApiResponse } from "../metrics/helpers/models";
import { addMetricsEventsToPageWithInformation, metricsPageInformationFromMediaApiResponse, } from "../metrics/helpers/page";
import { combinedRecoMetricsDataFromMetricsData } from "../metrics/helpers/util";
import * as onDevicePersonalization from "../personalization/on-device-personalization";
import { fetchTodayRecommendationsWithTimeout, isTodayTabArcadePersonalizationAvailable, } from "../personalization/on-device-recommendations-today";
import { setPreviewPlatform } from "../preview-platform";
import * as productPageVariants from "../product-page/product-page-variants";
import { newPageRefreshControllerFromResponse } from "../refresh/page-refresh-controller";
import { storeCohortIdForUserFromResponse } from "../search/landing/search-landing-cohort";
import { FlattenedTodayItemType, createAdShelfForTodayPageContextIfNecessary, feedPreviewUrlFromFlattenedTodayItems, flattenTodayModules, nextFlattenedItemIsHydrated, todayShelfForEditorialItem, todayShelfForEditorialItemGroup, } from "./today-parse-util";
import { TodayPageContext } from "./today-types";
/**
 * Keys used to manage additional data needed to render the today page.
 *
 * - onboardingCards: key used to fetch the onboarding cards for the feed.
 *
 * - ads: Key used for fetching the today placement ads
 */
export var TodayControllerAdditionalDataKey;
(function (TodayControllerAdditionalDataKey) {
    TodayControllerAdditionalDataKey["OnboardingCards"] = "onboardingCards";
    TodayControllerAdditionalDataKey["Ads"] = "ads";
    TodayControllerAdditionalDataKey["ODP"] = "ODP";
    TodayControllerAdditionalDataKey["AMDData"] = "amdData";
})(TodayControllerAdditionalDataKey || (TodayControllerAdditionalDataKey = {}));
export function defaultPlatforms(objectGraph) {
    return mediaDataFetching.defaultAdditionalPlatformsForClient(objectGraph);
}
/// Resource attributes to include for `editorial-items` fetched for displaying in today page.
export function defaultAttributes(objectGraph) {
    const attributes = [
        "editorialArtwork",
        "editorialVideo",
        "enrichedEditorialNotes",
        "minimumOSVersion",
        "headerName",
        "headerBadge",
        "headerTagline",
        "editorialClientParams",
        "requiredCapabilities",
        "shortEditorialNotes",
    ];
    if (objectGraph.bag.enableUpdatedAgeRatings) {
        attributes.push("ageRating");
    }
    if (shouldUsePrerenderedIconArtwork(objectGraph)) {
        attributes.push("iconArtwork");
    }
    return attributes;
}
export function prepareRequest(objectGraph, request, isPageRequest) {
    var _a, _b;
    request
        .includingAgeRestrictions()
        .includingAdditionalPlatforms(defaultPlatforms(objectGraph))
        .includingAttributes(defaultAttributes(objectGraph))
        .includingScopedAttributes("editorial-item-groups", ["editorialClientParams"])
        .includingScopedRelationships("editorial-items", ["primary-content", "header-contents"])
        .includingScopedRelationships("editorial-item-groups", ["header-contents"])
        .enablingFeature("editorialItemGroups")
        .usingCustomAttributes(productPageVariants.shouldFetchCustomAttributes(objectGraph))
        .includingRelationshipsForUpsell(true);
    if (isPageRequest) {
        request.includingAssociateKeys("editorial-item-groups", ["recommendations", "editorial-cards"]);
        request.includingAssociateKeys("editorial-items", ["editorial-cards"]);
    }
    if (appPromotionsCommon.appEventsAreEnabled(objectGraph)) {
        request.enablingFeature("appEvents");
        request.addingQuery("meta", "personalizationData");
        request.includingScopedRelationships("app-events", ["app"]);
        request.includingScopedAttributes("app-events", AppEventsAttributes);
    }
    if (appPromotionsCommon.appOfferItemsAreEnabled(objectGraph)) {
        request.enablingFeature("offerItems");
        if (isPageRequest) {
            request.includingKindsKeys("offer-items", ["winback"]);
        }
    }
    if (impressionDemotion.isImpressionDemotionAvailable(objectGraph)) {
        request.enablingFeature("eiGroupEISelectionOnDevice");
    }
    if (isAdPlacementEnabled(objectGraph, "today")) {
        request.enablingFeature("adSupport");
    }
    request.enablingFeature("heroStyles");
    const displayDeviceDrivenContent = (_b = (_a = objectGraph.userDefaults) === null || _a === void 0 ? void 0 : _a.bool("displayDeviceDrivenContent")) !== null && _b !== void 0 ? _b : false;
    if (objectGraph.bag.enableDeviceDrivenDiscoveryContent &&
        displayDeviceDrivenContent &&
        request.resourceType === "today") {
        request.addingQuery("pairedDevices", "visionPro");
    }
}
// MARK: - Page Fetching
export function generateTodayPageRequest(objectGraph) {
    // Note: The sparse limit is now 2 because story groups will include all of their content which means
    // if we continue to use the original 6 count we'll end up with way too many EI's
    // rdar://108635958 ([Network Launch | 283ms | 19%] App Store - Dawn - D33: 21A236 vs 20E245 network-warm-launch:
    // extendedLaunchTime is 1731.0ms vs 1448.0ms)
    const sparseCount = objectGraph.client.isWeb ? 40 : 1;
    const sparseLimit = objectGraph.client.isWeb ? 40 : 2;
    const mediaApiRequest = new mediaDataFetching.Request(objectGraph)
        .forType("today")
        .withSparseCount(sparseCount)
        .withSparseLimit(sparseLimit);
    return setPreviewPlatform(objectGraph, mediaApiRequest);
}
/**
 * @param objectGraph The object graph for the AppStore.
 * @param onboardingCardIds The onboardingCard ids to fetch.
 * @returns The map of additional page requirements.
 */
function generateAdditionalPageRequirements(objectGraph, onboardingCardIds) {
    const additionalRequirements = {};
    /**
     * Currently, to avoid double filtering, the fix for:
     * <rdar://problem/45031644> If an onboarding card is empty don't add it to the request
     * depends on the `Request` object filtering IDs from under caller. The caller is expected to perform some validation to
     * guarantee that this `Request` object is not malformed  after it was processed here, and it can still build a valid URL.
     *
     * This mechanic is undesired, and once this filtering is removed from `Request`, the caller should filter empty onboarding
     * IDs via an explicit method instead before instantiating an malformed `Request`.
     */
    if (isDefinedNonNullNonEmpty(onboardingCardIds)) {
        const onboardingCardsRequest = new mediaDataFetching.Request(objectGraph)
            .withIdsOfType(onboardingCardIds, "editorial-items")
            .includingAdditionalPlatforms(defaultPlatforms(objectGraph))
            .includingAttributes(defaultAttributes(objectGraph));
        additionalRequirements[TodayControllerAdditionalDataKey.OnboardingCards] = optional(fetchData(objectGraph, onboardingCardsRequest, {}));
    }
    if (isAdPlacementEnabled(objectGraph, "today")) {
        additionalRequirements[TodayControllerAdditionalDataKey.Ads] = optional(fetchAds(objectGraph, "today"));
    }
    if (isTodayTabArcadePersonalizationAvailable(objectGraph)) {
        additionalRequirements[TodayControllerAdditionalDataKey.ODP] = optional(fetchTodayRecommendationsWithTimeout(objectGraph, undefined));
    }
    const amsEngagement = objectGraph.amsEngagement;
    if (amsEngagement && impressionDemotion.isImpressionDemotionAvailable(objectGraph)) {
        const request = {
            timeout: 1000,
            eventType: impressionDemotion.AMSEngagementAppStoreEventKey,
            tab: "today",
        };
        additionalRequirements[TodayControllerAdditionalDataKey.AMDData] = optional(amsEngagement.performRequest(request));
    }
    return additionalRequirements;
}
export async function fetchTodayPage(objectGraph, options) {
    const router = objectGraph.required(pageRouter);
    const isTodayTestPage = options.url === "x-as3-internal:/today/test";
    const isTodayCardPreviewPage = options.url.indexOf(Path.todayCardPreview) !== -1;
    if (isTodayTestPage) {
        return await router.fetchPage(objectGraph, options.url, models.TodayPage);
    }
    else if (isTodayCardPreviewPage) {
        const dataFetchUrl = URL.from(options.url);
        dataFetchUrl.param(Parameters.fetchData, "true");
        return await router.fetchPage(objectGraph, dataFetchUrl.build(), models.TodayPage);
    }
    else {
        const request = generateTodayPageRequest(objectGraph);
        prepareRequest(objectGraph, request, true);
        const requestHeaders = isSome(options.experimentIdHeader)
            ? { "X-Apple-User-Experiment-Ids": options.experimentIdHeader }
            : undefined;
        return await buildTodayPageFromRequest(objectGraph, request, requestHeaders, options);
    }
}
export async function buildTodayPageFromRequest(objectGraph, request, requestHeaders, options) {
    var _a;
    const fetchTimingMetricsBuilder = new FetchTimingMetricsBuilder();
    const modifiedObjectGraph = objectGraph.addingFetchTimingMetricsBuilder(fetchTimingMetricsBuilder);
    const primaryDataFetchPromise = fetchData(modifiedObjectGraph, request, {
        headers: requestHeaders !== null && requestHeaders !== void 0 ? requestHeaders : undefined,
    });
    // Should this be needed on web, this should have a .catch() added to avoid
    // an unhandled rejection.
    if (!objectGraph.client.isWeb) {
        void primaryDataFetchPromise.then((response) => {
            if (isAdPlacementEnabled(objectGraph, "today")) {
                parallelOrganicRequestDidFinish(objectGraph, "today");
            }
            storeCohortIdForUserFromResponse(objectGraph, objectGraph.user.dsid, response);
        });
    }
    const primaryDataFetchInput = required(primaryDataFetchPromise);
    const additionalRequirements = generateAdditionalPageRequirements(objectGraph, (_a = options === null || options === void 0 ? void 0 : options.onboardingCardIds) !== null && _a !== void 0 ? _a : []);
    const pageDataRequirements = await fetchPageWithAdditionalPageRequirements(objectGraph, primaryDataFetchInput, additionalRequirements);
    return fetchTimingMetricsBuilder.measureModelConstruction(() => {
        var _a, _b;
        const onboardingCardsResponse = pageDataRequirements.additionalData[TodayControllerAdditionalDataKey.OnboardingCards];
        const onboardingCards = mediaDataStructure.dataCollectionFromDataContainer(onboardingCardsResponse);
        const adsResponse = pageDataRequirements.additionalData[TodayControllerAdditionalDataKey.Ads];
        const todayRecommendations = pageDataRequirements.additionalData[TodayControllerAdditionalDataKey.ODP];
        const amdData = pageDataRequirements.additionalData[TodayControllerAdditionalDataKey.AMDData];
        const flattenedTodayItems = flattenTodayModules(objectGraph, (_b = (_a = pageDataRequirements.primaryPageData.results) === null || _a === void 0 ? void 0 : _a.data) !== null && _b !== void 0 ? _b : [], todayRecommendations, onboardingCards, adsResponse);
        return buildTodayPage(modifiedObjectGraph, flattenedTodayItems, pageDataRequirements.primaryPageData, adsResponse, amdData);
    });
}
// MARK: - Today Page Creation
/**
 * @param objectGraph The dependency graph for the App Store
 * @param flattenedTodayItems The flattened Today items used to render the page
 * @param primaryPageData The primary page data for the Today page
 * @param adsResponse The response from ad platforms
 * @returns A TodayPage model
 */
export function buildTodayPage(objectGraph, flattenedTodayItems, primaryPageData, adsResponse, amdResponse) {
    return validation.context("renderPage", () => {
        if (isNullOrEmpty(flattenedTodayItems)) {
            return null;
        }
        const pageContext = createTodayPageContext(objectGraph, flattenedTodayItems, primaryPageData, adsResponse, amdResponse);
        const todayPage = todayPageFromPageContext(objectGraph, pageContext);
        todayPage.shelves.splice(0, 0, shelfForUnifiedMessage(objectGraph, "todayPageHeader"));
        return todayPage;
    });
}
/**
 * From the provided today page context, create a new today page with the hydrated content
 * @param objectGraph The dependency graph for the App Store
 * @param pageContext The page context for the Today page
 */
export function todayPageFromPageContext(objectGraph, pageContext) {
    var _a;
    const shelves = [];
    const feedPreviewUrl = feedPreviewUrlFromFlattenedTodayItems(objectGraph, pageContext.remainingContent);
    let hasMoreHydratedContent = nextFlattenedItemIsHydrated(pageContext.remainingContent);
    const isPageLoadNotPaginated = (_a = pageContext.remainingContent[0]) === null || _a === void 0 ? void 0 : _a.isFirstItemInModule;
    while (hasMoreHydratedContent) {
        const todayItem = pageContext.remainingContent.shift();
        if (isNothing(todayItem)) {
            hasMoreHydratedContent = false;
            break;
        }
        const preItemAdShelf = createAdShelfForTodayPageContextIfNecessary(objectGraph, pageContext);
        if (isSome(preItemAdShelf)) {
            shelves.push(preItemAdShelf);
        }
        pageContext.currentTodayItem = todayItem;
        let todayItemShelf = null;
        switch (todayItem.type) {
            case FlattenedTodayItemType.EditorialItem:
                todayItemShelf = todayShelfForEditorialItem(objectGraph, todayItem, pageContext);
                break;
            case FlattenedTodayItemType.EditorialItemGroup:
                todayItemShelf = todayShelfForEditorialItemGroup(objectGraph, todayItem, pageContext);
                break;
            default:
                break;
        }
        pageContext.currentTodayItem = undefined;
        if (isSome(todayItemShelf)) {
            shelves.push(todayItemShelf);
        }
        const postItemAdShelf = createAdShelfForTodayPageContextIfNecessary(objectGraph, pageContext);
        if (isSome(postItemAdShelf)) {
            shelves.push(postItemAdShelf);
        }
        hasMoreHydratedContent = nextFlattenedItemIsHydrated(pageContext.remainingContent);
    }
    if (isPageLoadNotPaginated) {
        applySearchAdMissedOpportunityToShelvesIfNeeded(objectGraph, shelves, "today", "today", pageContext.pageInformation);
    }
    const todayPage = new models.TodayPage(shelves);
    const todayTab = objectGraph.bag.tabsStandard.find((tab) => tab.id === "today");
    const todayTabTitle = asString(todayTab, "title");
    const tabImageIdentifier = asString(todayTab, "image-identifier");
    const includeTitleDetail = isNothing(tabImageIdentifier) || tabImageIdentifier === "doc.text.image";
    const todayTitle = todayTabTitle !== null && todayTabTitle !== void 0 ? todayTabTitle : objectGraph.loc.string("PAGE_TITLE_TODAY");
    todayPage.title = todayTitle;
    todayPage.tabTitle = todayTitle;
    todayPage.titleDetail = includeTitleDetail ? todayPageTitleDetail(objectGraph) : undefined;
    todayPage.shortTitleDetail = includeTitleDetail ? todayPageShortTitleDetail(objectGraph) : undefined;
    todayPage.longTitle = includeTitleDetail ? todayPageLongTitle(objectGraph) : undefined;
    todayPage.feedPreviewUrl = feedPreviewUrl;
    if (isDefinedNonNullNonEmpty(pageContext.remainingContent)) {
        pageContext.pageHasDisplayedContent =
            pageContext.pageHasDisplayedContent ||
                shelves.some((shelf) => {
                    isDefinedNonNullNonEmpty(shelf.items);
                });
        todayPage.nextPage = pageContext;
    }
    else if (!objectGraph.client.isWeb) {
        footerShelvesForTodayPage(objectGraph, pageContext.pageInformation, pageContext.locationTracker).forEach((shelf) => {
            todayPage.shelves.push(shelf);
        });
    }
    if (isAdPlacementEnabled(objectGraph, "today")) {
        // Ad Incidents
        todayPage.adIncidents = adIncidents.recordedIncidents(objectGraph, pageContext.adIncidentRecorder);
    }
    addMetricsEventsToPageWithInformation(objectGraph, todayPage, pageContext.pageInformation);
    return todayPage;
}
/**
 * Fetch the next batch of content for the Today page, and hydrate the page context
 * @param objectGraph The dependency graph for the App Store
 * @param pageContext The page context for the Today page
 * @returns
 */
export async function hydrateNextBatchOfContent(objectGraph, pageContext) {
    const batchLoadSize = pageContext.pageHasDisplayedContent ? 6 : 12;
    let continueAddingContent = true;
    let unhydratedItemIndex = 0;
    let unhydratedContents = [];
    while (continueAddingContent) {
        const nextContent = pageContext.remainingContent[unhydratedItemIndex];
        switch (nextContent.type) {
            case FlattenedTodayItemType.EditorialItem:
                unhydratedContents.push(nextContent.data);
                break;
            case FlattenedTodayItemType.EditorialItemGroup:
                unhydratedContents.push(nextContent.data);
                const groupItems = asArrayOrEmpty(nextContent.data, "meta.associations.recommendations.data");
                unhydratedContents = [...unhydratedContents, ...groupItems];
                break;
            default:
                break;
        }
        unhydratedItemIndex++;
        continueAddingContent =
            unhydratedContents.length < batchLoadSize && unhydratedItemIndex < pageContext.remainingContent.length;
    }
    // MAPI request for module slice's contents
    const requestedContentIds = new Set(unhydratedContents.map((content) => content.id));
    const contentsFetchRequest = new mediaDataFetching.Request(objectGraph, unhydratedContents, true, [
        "recommendations",
        "editorial-cards",
    ]);
    prepareRequest(objectGraph, contentsFetchRequest, false);
    const fetchedData = await fetchData(objectGraph, contentsFetchRequest, { allowEmptyDataResponse: true });
    const fetchedDataMap = {};
    for (const data of fetchedData.data) {
        fetchedDataMap[data.id] = data;
    }
    // Hydrate the page context with the fetched data
    for (const content of pageContext.remainingContent) {
        hydrateFlattenedItemWithFetchedDataMap(content, fetchedDataMap);
    }
    /// Now take a pass and remove any items that are still unhydrated after performing the fetch
    pageContext.remainingContent = pageContext.remainingContent.filter((content) => {
        return content.isDataHydrated || !requestedContentIds.has(content.data.id);
    });
    return pageContext;
}
/**
 * For a given today item, take the fetched MAPI data and apply that to the item.
 *
 * @param flattenedItem The today item we're going to be hydrating
 * @param fetchedDataMap The mapping from id to fetched media api data.
 */
function hydrateFlattenedItemWithFetchedDataMap(flattenedItem, fetchedDataMap) {
    var _a, _b, _c;
    switch (flattenedItem.type) {
        case FlattenedTodayItemType.EditorialItem:
            if (isDefinedNonNullNonEmpty(fetchedDataMap[flattenedItem.data.id])) {
                flattenedItem.data = {
                    ...flattenedItem.data,
                    ...fetchedDataMap[flattenedItem.data.id],
                };
            }
            flattenedItem.isDataHydrated = hasAttributes(flattenedItem.data);
            break;
        case FlattenedTodayItemType.EditorialItemGroup:
            if (isDefinedNonNullNonEmpty(fetchedDataMap[flattenedItem.data.id])) {
                flattenedItem.data = {
                    ...flattenedItem.data,
                    attributes: (_a = fetchedDataMap[flattenedItem.data.id]) === null || _a === void 0 ? void 0 : _a.attributes,
                    relationships: (_b = fetchedDataMap[flattenedItem.data.id]) === null || _b === void 0 ? void 0 : _b.relationships,
                    meta: {
                        ...flattenedItem.data.meta,
                        ...(_c = fetchedDataMap[flattenedItem.data.id]) === null || _c === void 0 ? void 0 : _c.meta,
                    },
                };
            }
            flattenedItem.isDataHydrated = hasAttributes(flattenedItem.data);
            break;
        default:
            break;
    }
}
/**
 * @param objectGraph The dependency graph for the App Store
 * @param todayItems The list of all the items displayed on the today page.
 * @param todayResponse The response from the today endpoint
 * @param adResponse The response from the ads service
 * @returns The context to use when parsing today cards
 */
function createTodayPageContext(objectGraph, todayItems, todayResponse, adsResponse, amdResponse) {
    var _a, _b, _c;
    const pageInformation = metricsPageInformationFromMediaApiResponse(objectGraph, "Today", "today", todayResponse, null, (_a = iadInfoFromOnDeviceAdResponse(objectGraph, "today", adsResponse, todayItems)) !== null && _a !== void 0 ? _a : iAdInformationFromMediaApiResponse(objectGraph, "today", todayResponse, (_b = adsResponse === null || adsResponse === void 0 ? void 0 : adsResponse.onDeviceAd) === null || _b === void 0 ? void 0 : _b.positionInfo, todayItems));
    const onDevicePersonalizationMetricsData = onDevicePersonalization.metricsData(objectGraph);
    pageInformation.recoMetricsData = combinedRecoMetricsDataFromMetricsData(pageInformation.recoMetricsData, null, onDevicePersonalizationMetricsData);
    const context = new TodayPageContext(todayItems, pageInformation, newLocationTracker(), newPageRefreshControllerFromResponse(todayResponse), impressionDemotion.impressionEventsFromData(objectGraph, amdResponse));
    if (isAdPlacementEnabled(objectGraph, "today")) {
        const eligibleAdPositions = eligibleSlotPositionsForAdPlacement(objectGraph, "today");
        if (isSome(eligibleAdPositions)) {
            // The slot as provided by ad platforms is one-based - adjust it so we're working with zero-based numbers.
            context.eligibleAdLocations = eligibleAdPositions.map((position) => position.slot);
        }
        const adIncidentRecorder = adIncidents.newRecorder(objectGraph, pageInformation.iAdInfo);
        adIncidents.recordAdResponseEventsIfNeeded(objectGraph, adIncidentRecorder, adsResponse);
        context.adIncidentRecorder = adIncidentRecorder;
        context.adPlacementBehavior = getAdPlacementBehaviorForPage(todayItems);
        if (isNothing(adsResponse === null || adsResponse === void 0 ? void 0 : adsResponse.failureReason)) {
            context.adData = mediaDataStructure.dataFromDataContainer(objectGraph, adsResponse === null || adsResponse === void 0 ? void 0 : adsResponse.mediaResponse);
            const rawPositionInfo = (_c = adsResponse === null || adsResponse === void 0 ? void 0 : adsResponse.onDeviceAd) === null || _c === void 0 ? void 0 : _c.positionInfo;
            if (isDefinedNonNullNonEmpty(rawPositionInfo)) {
                // The slot as provided by ad platforms is one-based - adjust it so we're working with zero-based numbers.
                const adjustedAdLocation = rawPositionInfo.slot - 1;
                context.adLocation = adjustedAdLocation;
            }
        }
    }
    return context;
}
function getAdPlacementBehaviorForPage(todayItems) {
    let adPlacementBehavior = models.AdPlacementBehavior.insertIntoShelf;
    for (const todayItem of todayItems) {
        let todayItemAdPlacementBehavior = adPlacementBehavior;
        switch (todayItem.type) {
            case FlattenedTodayItemType.EditorialItem:
                todayItemAdPlacementBehavior = getAdPlacementBehaviorForData(todayItem.data);
                break;
            case FlattenedTodayItemType.EditorialItemGroup:
                const groupItems = asArrayOrEmpty(todayItem.data, "meta.associations.recommendations.data");
                if (isDefinedNonNullNonEmpty(groupItems)) {
                    for (const groupItem of groupItems) {
                        todayItemAdPlacementBehavior = getAdPlacementBehaviorForData(groupItem);
                        if (todayItemAdPlacementBehavior !== models.AdPlacementBehavior.insertIntoShelf) {
                            break;
                        }
                    }
                }
                break;
            default:
                break;
        }
        if (todayItemAdPlacementBehavior !== models.AdPlacementBehavior.insertIntoShelf) {
            adPlacementBehavior = todayItemAdPlacementBehavior;
            break;
        }
    }
    return adPlacementBehavior;
}
function getAdPlacementBehaviorForData(data) {
    const replaceIfAdPresent = asBoolean(data, "meta.personalizationData.replaceIfAdPresent");
    if (isDefinedNonNull(replaceIfAdPresent) && replaceIfAdPresent) {
        return models.AdPlacementBehavior.replaceOrganic;
    }
    else if (isDefinedNonNull(replaceIfAdPresent) && !replaceIfAdPresent) {
        return models.AdPlacementBehavior.dropAd;
    }
    else {
        return models.AdPlacementBehavior.insertIntoShelf;
    }
}
/**
 * Return the first shelf title for the today page. This is used to generate the tab title.
 * @param objectGraph The dependency graph of the app store
 */
function todayPageTitleDetail(objectGraph) {
    const now = new Date();
    const dateFormat = objectGraph.loc.string("Today.ShelfTitle.DateFormat");
    return objectGraph.loc.formatDate(dateFormat, now);
}
/**
 * Return the first shelf title for the today page on iPad. This is used to generate the tab title.
 * @param objectGraph The dependency graph of the app store
 */
function todayPageLongTitle(objectGraph) {
    if (!objectGraph.client.isPad) {
        return undefined;
    }
    const now = new Date();
    const dateFormat = objectGraph.loc.string("Today.ShelfTitle.DateFormat.IPad");
    return objectGraph.loc.formatDate(dateFormat, now);
}
/**
 * Return a short version of the first shelf title for the today page. This is used to generate the tab title,
 * and is used where less horizontal space is available.
 * @param objectGraph The dependency graph of the app store
 */
export function todayPageShortTitleDetail(objectGraph) {
    const now = new Date();
    return objectGraph.loc.formatDate("MMM d", now);
}
/**
 * Generate the last shelves of the today page
 * @param objectGraph The dependency graph for the app
 * @param pageInformation The page information for the today page
 * @param locationTracker The Location tracker for the current today page
 * @returns The shelves that appear tha the bottom of the today page
 */
function footerShelvesForTodayPage(objectGraph, pageInformation, locationTracker) {
    const shelves = [];
    // Add Footer Buttons
    const footerButtonShelf = shelfForFooterButtons(objectGraph, pageInformation, locationTracker);
    if (isDefinedNonNull(footerButtonShelf)) {
        shelves.push(footerButtonShelf);
    }
    // Add T&C
    const url = objectGraph.bag.termsAndConditionsURL;
    if (isDefinedNonNull(url)) {
        const termsAndConditionsShelf = shelfForTermsAndConditions(objectGraph, url);
        shelves.push(termsAndConditionsShelf);
    }
    return shelves;
}
//# sourceMappingURL=today-controller-util.js.map