import * as validation from "@jet/environment/json/validation";
import * as models from "../../../api/models";
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 mediaNetwork from "../../../foundation/media/network";
import * as mediaRelationship from "../../../foundation/media/relationships";
import { ResponseMetadata } from "../../../foundation/network/network";
import { Parameters, Path, Protocol } from "../../../foundation/network/url-constants";
import * as urls from "../../../foundation/network/urls";
import * as metricsHelpersImpressions from "../../metrics/helpers/impressions";
import * as metricsHelpersLocation from "../../metrics/helpers/location";
import * as odpCommon from "../../personalization/on-device-recommendations-common";
import { defaultRoomShelfContentType } from "../../room/room-page";
import { platformPrefersLargeTitles } from "../../room/room-common";
import * as groupingTypes from "../grouping-types";
import { createLockupShelf, lockupShelfTokenFromBaseTokenAndMediaApiData, } from "./grouping-lockup-shelf-controller-common";
import { GroupingShelfController, routesForFeaturedContentIds } from "./grouping-shelf-controller";
import * as groupingShelfControllerCommon from "./grouping-shelf-controller-common";
import { isNothing, isSome } from "@jet/environment";
export class GroupingPersonalizedLockupShelfController extends GroupingShelfController {
    // region Constructors
    constructor() {
        super("GroupingPersonalizedLockupShelfController");
        this.supportedFeaturedContentIds = groupingTypes.recommendationsLockupShelfFeaturedContentIds;
    }
    // endregion
    // region Shelf Builder
    shelfRoute(objectGraph) {
        return routesForFeaturedContentIds(this.supportedFeaturedContentIds, [
            `${Parameters.isOnDeviceRecommendationsShelf}?`,
            `${Parameters.onDeviceRecommendationsUseCase}?`,
        ]);
    }
    // endregion
    // region Shelf Creation Prerequisites
    /**
     * For a given mediaApiData extract the actual shelfContents array needed to render this shelf
     *
     * @param mediaApiData The outer shelfContents object containing the shelf contents
     */
    initialShelfDataFromGroupingMediaApiData(objectGraph, mediaApiData) {
        const shelfContents = mediaRelationship.relationship(mediaApiData, "contents");
        let shelfData = shelfContents ? shelfContents.data : null;
        if (!shelfData || shelfData.length === 0) {
            shelfData = mediaRelationship.relationshipCollection(mediaApiData, "children");
        }
        const recoMetrics = mediaDataStructure.metricsFromMediaApiObject(shelfContents);
        return {
            shelfContents: shelfData || [],
            containsODPShelfContents: false,
            recoMetrics: recoMetrics,
            candidates: null,
            isHiddenShelf: objectGraph.client.isWeb,
            responseTimingValues: null,
        };
    }
    /**
     * For a given url that this controller handles, we should return a promise that will result in the `ShelfData`
     * needed to render this shelf
     *
     * @param objectGraph The App Store dependency graph
     * @param shelfUrl The url that this controller handled on a secondary fetch
     * @param parameters The extracted parameters from the shelf url
     */
    async secondaryShelfDataForShelfUrl(objectGraph, shelfUrl, shelfToken, parameters) {
        var _a;
        const onDeviceRecommendationsUseCase = parameters[Parameters.onDeviceRecommendationsUseCase];
        if ((onDeviceRecommendationsUseCase === null || onDeviceRecommendationsUseCase === void 0 ? void 0 : onDeviceRecommendationsUseCase.length) > 0) {
            return await odpCommon
                .recommendedAppsForUseCase(objectGraph, onDeviceRecommendationsUseCase, "shelf")
                .then((response) => {
                return {
                    shelfContents: mediaDataStructure.dataCollectionFromDataContainer(response.dataContainer),
                    containsODPShelfContents: true,
                    recoMetrics: response.recoMetrics,
                    candidates: response.candidates,
                    isHiddenShelf: false,
                };
            })
                .catch(async (error) => {
                if (error instanceof odpCommon.NoODPCandidatesError) {
                    return await GroupingPersonalizedLockupShelfController.fetchODPFallbackContent(objectGraph, shelfUrl, shelfToken, parameters).catch((fallbackError) => {
                        return GroupingPersonalizedLockupShelfController.makeHiddenShelfData(shelfToken);
                    });
                }
                else {
                    return GroupingPersonalizedLockupShelfController.makeHiddenShelfData(shelfToken);
                }
            });
        }
        else if (((_a = shelfToken.recommendationsHref) === null || _a === void 0 ? void 0 : _a.length) > 0) {
            return await GroupingShelfController.secondaryGroupingShelfMediaApiData(objectGraph, shelfUrl, shelfToken, parameters).then((mediaApiData) => {
                const personalizedFeaturedContentData = mediaDataStructure.dataFromDataContainer(objectGraph, mediaApiData);
                const personalizedLockupShelfData = this.initialShelfDataFromGroupingMediaApiData(objectGraph, personalizedFeaturedContentData);
                personalizedLockupShelfData.responseTimingValues = mediaApiData[ResponseMetadata.timingValues];
                personalizedLockupShelfData.shelfTitle = mediaAttributes.attributeAsString(personalizedFeaturedContentData, "name");
                return personalizedLockupShelfData;
            });
        }
        else {
            return await GroupingShelfController.secondaryGroupingShelfMediaApiData(objectGraph, shelfUrl, shelfToken, parameters).then((mediaApiData) => {
                const personalizedFeaturedContentData = mediaDataStructure.dataCollectionFromDataContainer(mediaApiData);
                const personalizedLockupShelfData = {
                    shelfContents: personalizedFeaturedContentData || [],
                    containsODPShelfContents: false,
                    recoMetrics: null,
                    candidates: null,
                    isHiddenShelf: false,
                    responseTimingValues: mediaApiData[ResponseMetadata.timingValues],
                };
                personalizedLockupShelfData.shelfTitle = shelfToken.title;
                return personalizedLockupShelfData;
            });
        }
    }
    /**
     * For a given mediaApiData create an updated shelf token that contains all the additional data for this specific shelf type
     *
     * @param objectGraph The App Store dependency graph
     * @param baseShelfToken The base grouping shelf token created by the grouping-controller
     * @param mediaApiData The outer data object containing the FC properties and data
     * @param groupingParseContext The parse context for the grouping page so far
     */
    shelfTokenFromBaseTokenAndMediaApiData(objectGraph, mediaApiData, baseShelfToken, groupingParseContext) {
        const personalizedLockupShelfToken = lockupShelfTokenFromBaseTokenAndMediaApiData(objectGraph, mediaApiData, baseShelfToken, groupingParseContext);
        this.addPersonalizationValuesToShelfToken(objectGraph, personalizedLockupShelfToken, mediaApiData, groupingParseContext);
        return personalizedLockupShelfToken;
    }
    // endregion
    // region Shelf Creation
    /**
     *
     * @param objectGraph The App Store dependency graph
     * @param shelfToken The shelf shelfToken for this current shelf creation request
     * @param shelfData The media api shelfContents array for this shelf
     * @param groupingParseContext The parse context used to generate the grouping page on the initial page load,
     * this will be missing when this controller renders a secondary or incomplete shelf fetch.
     */
    _createShelf(objectGraph, shelfToken, shelfData, groupingParseContext) {
        var _a, _b;
        if (!shelfToken.isValidRecommendationsShelf) {
            return null;
        }
        let shelf = null;
        if (isNothing(shelfToken.title)) {
            // If we've fetched the title in a secondary lookup, update the title here
            // in the token, since other places may rely on it.
            shelfToken.title = shelfData.shelfTitle;
        }
        if (shelfData.containsODPShelfContents) {
            shelf = this.personalizedShelf(objectGraph, shelfData, shelfToken, groupingParseContext);
            const seeAllUrl = new urls.URL()
                .set("protocol", Protocol.internal)
                .path(`${Path.onDeviceRecommendations}`)
                .param(Parameters.onDeviceRecommendationsUseCase, shelfToken.onDeviceRecommendationsUseCase)
                .param(Parameters.token, JSON.stringify(shelfToken))
                .build();
            const seeAllAction = new models.FlowAction("page", seeAllUrl);
            seeAllAction.title = objectGraph.loc.string("ACTION_SEE_ALL");
            seeAllAction.pageData = this.odpSeeAllPage(objectGraph, shelfData.shelfTitle, defaultRoomShelfContentType);
            groupingShelfControllerCommon.replaceShelfSeeAllAction(objectGraph, shelf, seeAllAction);
            shelf.mergeWhenFetched = false;
        }
        else if (shelfData.isHiddenShelf) {
            shelf = GroupingPersonalizedLockupShelfController.makeHiddenShelf(shelfToken);
        }
        else if (serverData.isDefinedNonNull(shelfToken.recommendationsHref)) {
            shelf = this.personalizedShelf(objectGraph, shelfData, shelfToken, groupingParseContext);
            shelf.url = this.addOnDeviceQueryParamsIfNecessary(objectGraph, shelf.url, shelfToken);
        }
        else {
            shelf = createLockupShelf(objectGraph, shelfToken, shelfData, groupingParseContext);
            shelf.url = this.addOnDeviceQueryParamsIfNecessary(objectGraph, shelf.url, shelfToken);
        }
        const isUsingHeader = isSome(shelf.header);
        const isMissingHeaderTitle = isUsingHeader && serverData.isNullOrEmpty((_a = shelf.header) === null || _a === void 0 ? void 0 : _a.title);
        const isMissingLegacyShelfTitle = !isUsingHeader && serverData.isNullOrEmpty(shelf.title);
        const hasShelfDataTitle = ((_b = shelfData.shelfTitle) === null || _b === void 0 ? void 0 : _b.length) > 0;
        if (isMissingHeaderTitle && hasShelfDataTitle) {
            shelf.header.title = shelfData.shelfTitle;
        }
        else if (isMissingLegacyShelfTitle && hasShelfDataTitle) {
            shelf.title = shelfData.shelfTitle;
        }
        return shelf;
    }
    // endregion
    // region Helpers
    /**
     *
     * @param objectGraph The App Store dependency graph
     * @param shelfData The media api shelfContents array for this shelf
     * @param shelfToken The shelf shelfToken for this current shelf creation request
     * @param groupingParseContext The parse context used to generate the grouping page on the initial page load,
     * @private
     */
    personalizedShelf(objectGraph, shelfData, shelfToken, groupingParseContext) {
        /**
         * Update shelf impressions for personalized shelves.
         * <rdar://problem/69308786> reco_algo_id doesn't get passed to Figaro for out of band personalization marker
         *
         * By happenstance, the location tracker encoded in the shelf token usually contains the swoosh location, given the happy path fetches *more* items.
         * For Personalized shelves, we need to pop the "empty" shelf location and replace it with the fully populated one.
         */
        const location = metricsHelpersLocation.currentLocation(shelfToken.metricsLocationTracker);
        if (location && location.fcKind === shelfToken.featuredContentId) {
            metricsHelpersLocation.popLocation(shelfToken.metricsLocationTracker);
        }
        const shelfMetricsOptions = {
            id: shelfToken.id,
            kind: null,
            softwareType: serverData.asBooleanOrFalse(groupingParseContext === null || groupingParseContext === void 0 ? void 0 : groupingParseContext.isArcadePage) ? "Arcade" : null,
            targetType: "swoosh",
            title: shelfToken.title,
            pageInformation: shelfToken.metricsPageInformation,
            locationTracker: shelfToken.metricsLocationTracker,
            idType: "its_contentId",
            fcKind: shelfToken.featuredContentId,
            recoMetricsData: shelfData.recoMetrics,
            displayStyle: shelfToken.shelfStyle,
        };
        metricsHelpersLocation.pushContentLocation(objectGraph, shelfMetricsOptions, shelfToken.title);
        const shelf = createLockupShelf(objectGraph, shelfToken, shelfData, groupingParseContext);
        metricsHelpersLocation.popLocation(shelfToken.metricsLocationTracker);
        metricsHelpersImpressions.addImpressionFields(objectGraph, shelf, shelfMetricsOptions);
        return shelf;
    }
    /**
     * Check in the media api data for this shelf and add any of the necessary personalization fields to the shelfToken.
     *
     * @param objectGrpah
     * @param shelfToken The shelf token in its current state
     * @param mediaApiData The media api data for this section of the grouping page
     * @param groupingParseContext The parse context for the grouping page so far
     * @private
     */
    addPersonalizationValuesToShelfToken(objectGrpah, shelfToken, mediaApiData, groupingParseContext) {
        const isPersonalizedShelfMarker = shelfToken.featuredContentId === 476 /* groupingTypes.FeaturedContentID.AppStore_PersonalizedShelfMarker */;
        // If we don't have a logged in user don't show personalized shelves
        // For search grouping we allow these shelves even if there is no logged in user.
        // For the personalized shelf markers we are going to allow reco to send back a fallback list of ids so that
        // even logged out users can see these shelves.
        // rdar://64005675 (Client to not drop personalized marker response for non-signed users (dsId - 0))
        if (!groupingParseContext.hasAuthenticatedUser &&
            !shelfToken.isSearchLandingPage &&
            !isPersonalizedShelfMarker) {
            objectGrpah.console.log(`Skipping recommendations shelf with fcID ${shelfToken.featuredContentId}: No user logged-in`);
            return;
        }
        const onDevicePersonalizationUseCase = mediaAttributes.attributeAsString(mediaApiData, "onDevicePersonalizationUseCase");
        const usingOnDevicePersonalization = (onDevicePersonalizationUseCase === null || onDevicePersonalizationUseCase === void 0 ? void 0 : onDevicePersonalizationUseCase.length) > 0;
        if (usingOnDevicePersonalization) {
            shelfToken.onDeviceRecommendationsUseCase = onDevicePersonalizationUseCase;
            shelfToken.recommendationsHref = mediaApiData.href;
            shelfToken.isValidRecommendationsShelf = true;
            return;
        }
        const shelfContents = mediaRelationship.relationshipCollection(mediaApiData, "contents");
        const hasContents = serverData.isDefinedNonNullNonEmpty(shelfContents);
        const shelfPersonalizationAvailable = !mediaAttributes.attributeAsBooleanOrFalse(mediaApiData, "noPersonalizationAvailable");
        if (!hasContents && shelfPersonalizationAvailable) {
            shelfToken.recommendationsHref = mediaApiData.href;
            shelfToken.isValidRecommendationsShelf = true;
            // tslint:disable-next-line:no-redundant-jump
        }
        else {
            shelfToken.isValidRecommendationsShelf = hasContents;
        }
    }
    /**
     * For a given shelf url, add the on device personalization query param if its needed
     *
     * @param objectGraph
     * @param urlString The original url string for this shelf
     * @param shelfToken The shelf shelfToken for this current shelf creation request
     */
    addOnDeviceQueryParamsIfNecessary(objectGraph, urlString, shelfToken) {
        var _a;
        if (serverData.isNullOrEmpty(urlString)) {
            return null;
        }
        const isOnDeviceRecommendationsGamesForYouEnabled = objectGraph.host.isiOS;
        if (!isOnDeviceRecommendationsGamesForYouEnabled) {
            return urlString;
        }
        if (((_a = shelfToken.onDeviceRecommendationsUseCase) === null || _a === void 0 ? void 0 : _a.length) > 0) {
            const url = new urls.URL(urlString);
            url.param(Parameters.isOnDeviceRecommendationsShelf, "true");
            url.param(Parameters.onDeviceRecommendationsUseCase, shelfToken.onDeviceRecommendationsUseCase);
            return url.build();
        }
        else {
            return urlString;
        }
    }
    /**
     * Creates a page that can be used for side-packing see all pages into a room.
     *
     * @param objectGraph
     * @param {string} title The title of the destination page
     * @param {ShelfContentType} preferredShelfContentType The content type to use for the page
     * @returns {GenericPage} A GenericPage which will use the parentShelfItems from the see all to render the initial room
     */
    odpSeeAllPage(objectGraph, title, preferredShelfContentType) {
        const shelf = new models.Shelf(preferredShelfContentType || defaultRoomShelfContentType);
        shelf.isHorizontal = false;
        shelf.items = "parentShelfItems";
        const page = new models.GenericPage([shelf]);
        page.isIncomplete = true;
        page.title = title;
        if (platformPrefersLargeTitles(objectGraph)) {
            page.presentationOptions = ["prefersLargeTitle"];
        }
        return page;
    }
    // endregion
    // region ODP Fallback
    static async fetchODPFallbackContent(objectGraph, url, shelfToken, parameters) {
        return await new Promise((resolve, reject) => {
            const fallbackRequest = groupingShelfControllerCommon.generateShelfRequest(objectGraph, shelfToken, parameters);
            if (!fallbackRequest) {
                const errorMessage = `OnDeviceRecommendationsShelfController: Could not construct media API request for: ${url}`;
                validation.unexpectedType("defaultValue", errorMessage, null);
                reject(new Error(errorMessage));
                return;
            }
            groupingShelfControllerCommon.prepareGroupingShelfRequest(objectGraph, fallbackRequest);
            fallbackRequest.attributingTo(url.build());
            mediaNetwork
                .fetchData(objectGraph, fallbackRequest)
                .then((dataContainer) => {
                const shelfData = mediaDataStructure.dataFromDataContainer(objectGraph, dataContainer);
                const shelfContents = mediaRelationship.relationship(shelfData, "contents");
                const recoMetrics = mediaDataStructure.metricsFromMediaApiObject(shelfContents);
                const fallbackShelfData = {
                    shelfContents: mediaDataStructure.dataCollectionFromDataContainer(shelfContents),
                    containsODPShelfContents: false,
                    recoMetrics: recoMetrics,
                    candidates: null,
                    responseTimingValues: dataContainer[ResponseMetadata.timingValues],
                };
                resolve(fallbackShelfData);
            })
                .catch((error) => {
                const errorMessage = `OnDeviceRecommendationsShelfController: Failed to fetch fallback shelf contents: ${url}`;
                validation.unexpectedType("defaultValue", errorMessage, null);
                reject(error);
            });
        });
    }
    static makeHiddenShelfData(shelfToken) {
        const hiddenShelfData = {
            shelfContents: [],
            containsODPShelfContents: false,
            recoMetrics: null,
            candidates: null,
            isHiddenShelf: true,
        };
        return hiddenShelfData;
    }
    static makeHiddenShelf(shelfToken) {
        const hiddenShelf = new models.Shelf(shelfToken.shelfStyle);
        hiddenShelf.isHidden = true;
        return hiddenShelf;
    }
}
//# sourceMappingURL=grouping-personalized-lockup-shelf-controller.js.map