import * as models from "../../../api/models";
import * as serverData from "../../../foundation/json-parsing/server-data";
import * as mediaAttributes from "../../../foundation/media/attributes";
import * as mediaDataFetching from "../../../foundation/media/data-fetching";
import * as mediaDataStructure from "../../../foundation/media/data-structure";
import * as mediaNetwork from "../../../foundation/media/network";
import { ResponseMetadata } from "../../../foundation/network/network";
import { Parameters, Path, Protocol } from "../../../foundation/network/url-constants";
import * as urls from "../../../foundation/network/urls";
import * as contentAttributes from "../../content/attributes";
import * as content from "../../content/content";
import * as lockups from "../../lockups/lockups";
import * as metricsHelpersClicks from "../../metrics/helpers/clicks";
import * as metricsHelpersLocation from "../../metrics/helpers/location";
import { GroupingShelfController } from "./grouping-shelf-controller";
import * as groupingShelfControllerCommon from "./grouping-shelf-controller-common";
import { makeGameCenterHeader, openGamesUIAction } from "../../arcade/arcade-common";
export class GroupingGameCenterPopularWithYourFriendsController extends GroupingShelfController {
    // region Constructors
    constructor() {
        super("GroupingGameCenterPopularWithYourFriendsController");
        this.batchGroupKey = "gameCenter";
        this.supportedFeaturedContentIds = new Set([
            495 /* groupingTypes.FeaturedContentID.AppStore_PopularWithYourFriendsMarker */,
        ]);
    }
    // endregion
    // region Shelf Builder
    shelfRoute(objectGraph) {
        return [
            ...super.shelfRoute(objectGraph),
            {
                protocol: Protocol.internal,
                path: `/${Path.grouping}/${Path.shelf}/{token}`,
                query: [Parameters.isGameCenterPopularWithYourFriendsShelf],
            },
        ];
    }
    // 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) {
        return {
            shelfContents: [],
        };
    }
    /**
     * 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) {
        const popularWithYourFriendsPromise = objectGraph.gameCenter.fetchGamesPopularWithFriends(this.gameCategoryFilter(shelfToken.gamesFilter), 30);
        return await popularWithYourFriendsPromise.then(async (response) => {
            const gameplayRecords = response
                .map((item) => this.gameplayHistoryFromData(item))
                .sort((a, b) => b.records.length - a.records.length);
            const adamIds = gameplayRecords
                .filter((record) => this.isCompatibleGameCenterPlatform(objectGraph, record.platformId))
                .map((record) => record.adamId);
            if (adamIds.length === 0) {
                // One of the few exceptions where TS minifiers cannot derive data container type
                // without some help, in this case using explicit type for the value passed to promise.
                const emptyShelfData = { shelfContents: [] };
                return await Promise.resolve(emptyShelfData);
            }
            // <rdar://problem/62490641> Send payload to MAPI to allow reco to reorder the "Popular with friends" shelf.
            const request = new mediaDataFetching.Request(objectGraph)
                // MAPI will refuse to serve this request if there are more than 100 items.
                .withIdsOfType(adamIds.slice(0, 100), "apps")
                .includingAgeRestrictions();
            groupingShelfControllerCommon.prepareGroupingShelfRequest(objectGraph, request);
            return await mediaNetwork
                .fetchData(objectGraph, request, {})
                .then((dataContainer) => {
                const shelfData = {
                    shelfContents: dataContainer.data,
                    responseTimingValues: dataContainer[ResponseMetadata.timingValues],
                };
                return shelfData;
            });
        });
    }
    /**
     * 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) {
        return baseShelfToken;
    }
    incompleteShelfFetchStrategy(objectGraph) {
        return models.IncompleteShelfFetchStrategy.OnPageLoad;
    }
    // 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) {
        if (shelfToken.isFirstRender) {
            return this.pendingPopularWithFriendsShelfForGrouping(objectGraph, shelfData, shelfToken);
        }
        else {
            return this.popularWithFriendsShelfForGrouping(objectGraph, shelfData, shelfToken);
        }
    }
    pendingPopularWithFriendsShelfForGrouping(objectGraph, shelfData, shelfToken) {
        const shelf = this.popularWithFriendsShelfForGrouping(objectGraph, shelfData, shelfToken);
        const groupingShelfUrl = urls.URL.from(groupingShelfControllerCommon.groupingShelfUrl(shelfToken));
        shelf.url = groupingShelfUrl.param(Parameters.isGameCenterPopularWithYourFriendsShelf, "true").build();
        return shelf;
    }
    popularWithFriendsShelfForGrouping(objectGraph, shelfData, shelfToken) {
        const shelf = this.popularWithFriendsShelf(objectGraph, shelfData.shelfContents, shelfToken);
        shelf.mergeWhenFetched = true;
        shelf.batchGroup = this.batchGroupKey;
        // Hide when empty.
        shelf.isHidden = shelf.items.length === 0;
        // Configure header
        shelf.header.title = shelfToken.title;
        shelf.header.subtitle = shelfToken.subtitle;
        return shelf;
    }
    popularWithFriendsShelf(objectGraph, shelfContents, shelfToken) {
        const shelfStyle = shelfToken.shelfStyle || "mediumLockup";
        const shelf = new models.Shelf(shelfStyle);
        shelf.isHorizontal = true;
        const maxNumberOfPlayersBeforeSeeAll = objectGraph.client.isTV ? 20 : 12;
        const items = [];
        for (let index = 0; index < shelfContents.length; index++) {
            const data = shelfContents[index];
            const lockupOptions = {
                metricsOptions: {
                    pageInformation: shelfToken.metricsPageInformation,
                    locationTracker: shelfToken.metricsLocationTracker,
                    recoMetricsData: mediaDataStructure.metricsFromMediaApiObject(data),
                    anonymizationOptions: {
                        anonymizationString: `"GAME"${index + 1}`,
                    },
                },
                artworkUseCase: content.artworkUseCaseFromShelfStyle(objectGraph, shelfStyle),
                canDisplayArcadeOfferButton: content.shelfContentTypeCanDisplayArcadeOfferButtons(objectGraph, shelfStyle),
                shouldHideArcadeHeader: objectGraph.featureFlags.isEnabled("hide_arcade_header_on_arcade_tab") && shelfToken.isArcadePage,
                shouldShowFriendsPlayingShowcase: true,
            };
            // GameCenter should *not* be sending us IDs for non-GameCenter apps, but in the odd case that they do, we
            // we check against the app's metadata to make sure we are displaying GC apps only here.
            const isGameCenterEnabled = contentAttributes.contentAttributeAsBooleanOrFalse(objectGraph, data, "isGameCenterEnabled");
            // It's possible that a pre-order has become available to friends, but not you yet (due to CDN/timezone reasons).
            const isPreorder = mediaAttributes.attributeAsBooleanOrFalse(data, "isPreorder");
            if (isPreorder || !isGameCenterEnabled) {
                continue;
            }
            const lockup = lockups.lockupFromData(objectGraph, data, lockupOptions);
            lockup.clickAction = injectCrossfireFlowForGameCenter(objectGraph, lockup.clickAction);
            if (serverData.isDefinedNonNull(lockup)) {
                items.push(lockup);
                metricsHelpersLocation.nextPosition(lockupOptions.metricsOptions.locationTracker);
            }
        }
        let thresholdForPlatform;
        switch (objectGraph.client.deviceType) {
            case "phone":
                thresholdForPlatform = 2;
                break;
            case "pad":
                thresholdForPlatform = 6;
                break;
            case "mac":
                thresholdForPlatform = 6;
                break;
            case "tv":
                thresholdForPlatform = 6;
                break;
            default:
                thresholdForPlatform = 0;
        }
        shelf.header = makeGameCenterHeader(objectGraph);
        if (items.length < thresholdForPlatform) {
            shelf.isHidden = true;
            return shelf;
        }
        shelf.items = items.slice(0, maxNumberOfPlayersBeforeSeeAll);
        shelf.isHidden = false;
        shelf.batchGroup = "gameCenter";
        if (items.length > maxNumberOfPlayersBeforeSeeAll) {
            // The shelf for the see all page
            const shelfForSeeAllItems = new models.Shelf("mediumLockup");
            shelfForSeeAllItems.items = items;
            shelfForSeeAllItems.rowsPerColumn = 1;
            // See all page
            const seeAllPage = new models.GenericPage([shelfForSeeAllItems]);
            seeAllPage.title = shelfToken.title;
            // The action that opens the see all page
            const seeAllAction = new models.FlowAction("page");
            seeAllAction.title = objectGraph.loc.string("ACTION_SEE_ALL");
            seeAllAction.pageData = seeAllPage;
            // Metrics
            metricsHelpersClicks.addClickEventToSeeAllAction(objectGraph, seeAllAction, null, {
                pageInformation: shelfToken.metricsPageInformation,
                locationTracker: shelfToken.metricsLocationTracker,
            });
            // Connect the shelf's seeAllAction
            groupingShelfControllerCommon.replaceShelfSeeAllAction(objectGraph, shelf, seeAllAction);
        }
        shelf.footerTitle = objectGraph.loc.string("Lockup.Footer.GamesApp");
        shelf.footerAction = openGamesUIAction(objectGraph);
        shelf.footerStyle = {
            $kind: "games",
            bundleID: "com.apple.games",
            width: 16,
            height: 16,
        };
        return shelf;
    }
    // endregion
    // region Helpers
    /**
     * Maps GKGamePlatform to client's `deviceType`
     * @param objectGraph
     * @param platformId The platform ID as defined by GameCenter's GKGamePlatform
     */
    isCompatibleGameCenterPlatform(objectGraph, platformId) {
        switch (platformId) {
            case 1:
                return objectGraph.client.isiOS;
            case 2:
                return objectGraph.client.isMac;
            case 3:
                return objectGraph.client.isTV;
            case 4:
                return objectGraph.client.isWatch;
            default:
                return false;
        }
    }
    gameplayHistoryFromData(data) {
        const adamId = serverData.asString(data, "adamId");
        const platformId = serverData.asNumber(data, "platformId");
        const isArcade = serverData.asBooleanOrFalse(data, "isArcade");
        const records = this.gameplayHistoryRecordFromData(serverData.asArrayOrEmpty(data, "records"));
        return new models.GameCenterGameplayHistory(adamId, platformId, isArcade, records);
    }
    gameplayHistoryRecordFromData(data) {
        return data.map((recordData) => {
            const playerId = serverData.asString(recordData, "playerId");
            const timestamp = serverData.asNumber(recordData, "timestamp");
            return new models.GameCenterGameplayHistoryRecord(playerId, timestamp);
        });
    }
    /**
     * Convert GameCategoryFilter to GamesFilter. Ideally these would be the same, but seed 1 has already left the station.
     * @param gamesFilter
     */
    gameCategoryFilter(gamesFilter) {
        if (gamesFilter === "nonArcade") {
            return "nonarcade";
        }
        return gamesFilter;
    }
    // endregion
    // region Metrics
    shelfMetricsOptionsFromBaseMetricsOptions(objectGraph, shelfToken, baseMetricsOptions) {
        return {
            ...baseMetricsOptions,
            badges: {
                gameCenter: true,
            },
            idType: "its_contentId",
        };
    }
}
/**
 * For evaluating how we attribute referral from Game Center shelves to the product page
 * We going to inject a hardcoded refApp `com.apple.gamecenter.from.browse` through crossfire pipeline for tracking the page event and buy action
 *
 * - Modify the FlowAction to include the GameCenter ReferrerData.
 * - Replace the click action with a compound action of CrossfireReferralAction + FlowAction
 */
export function injectCrossfireFlowForGameCenter(objectGraph, clickAction) {
    if (["iOS", "macOS", "tvOS"].includes(objectGraph.host.platform) && clickAction instanceof models.FlowAction) {
        const gameCenterCrossfireReferrerData = {
            app: "com.apple.gamecenter.from.browse",
            kind: {
                name: "gameCenter",
            },
        };
        clickAction.referrerData = gameCenterCrossfireReferrerData;
        return new models.CompoundAction([
            new models.CrossfireReferralAction(gameCenterCrossfireReferrerData),
            clickAction,
        ]);
    }
    else {
        return clickAction;
    }
}
//# sourceMappingURL=grouping-game-center-popular-with-your-friends-shelf-controller.js.map