import { isSome } from "@jet/environment";
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 mediaRelationship from "../../foundation/media/relationships";
import * as artworkBuilder from "../content/artwork/artwork";
import * as metricsHelpersClicks from "../metrics/helpers/clicks";
import * as types from "./grouping-types";
import { GroupingAppEventShelfController } from "./shelf-controllers/grouping-app-event-shelf-controller";
import { GroupingArcadeFooterShelfController } from "./shelf-controllers/grouping-arcade-footer-shelf-controller";
import { GroupingBrickShelfController } from "./shelf-controllers/grouping-brick-shelf-controller";
import { GroupingRibbonBarShelfController } from "./shelf-controllers/grouping-ribbon-bar-shelf-controller";
import { GroupingCategoryShelfController } from "./shelf-controllers/grouping-category-shelf-controller";
import { GroupingEditorialCardShelfController } from "./shelf-controllers/grouping-editorial-card-shelf-controller";
import { GroupingEditorialStoryCardShelfController } from "./shelf-controllers/grouping-editorial-story-card-shelf-controller";
import { GroupingGameCenterActivityFeedController } from "./shelf-controllers/grouping-game-center-activity-feed-shelf-controller";
import { GroupingGameCenterContinuePlayingShelfController } from "./shelf-controllers/grouping-game-center-continue-playing-shelf-controller";
import { GroupingGameCenterPopularWithYourFriendsController } from "./shelf-controllers/grouping-game-center-popular-with-your-friends-shelf-controller";
import { GroupingGameCenterReengagementShelfController } from "./shelf-controllers/grouping-game-center-reengagement-shelf-controller";
import { GroupingGameCenterSuggestedFriendsController } from "./shelf-controllers/grouping-game-center-suggested-friends-shelf-controller";
import { GroupingHeroCarouselShelfController } from "./shelf-controllers/grouping-hero-carousel-shelf-controller";
import { GroupingHorizontalCardShelfController } from "./shelf-controllers/grouping-horizontal-card-shelf-controller";
import { GroupingLargeBreakoutShelfController } from "./shelf-controllers/grouping-large-breakout-shelf-controller";
import { GroupingLinkShelfController } from "./shelf-controllers/grouping-link-shelf-controller";
import { GroupingLockupShelfController } from "./shelf-controllers/grouping-lockup-shelf-controller";
import { GroupingPersonalizedLockupShelfController } from "./shelf-controllers/grouping-personalized-lockup-shelf-controller";
import { createShelfAccessibilityMetadata, } from "./shelf-controllers/grouping-shelf-controller";
import * as groupingShelfControllerCommon from "./shelf-controllers/grouping-shelf-controller-common";
import { GroupingSmallBreakoutShelfController } from "./shelf-controllers/grouping-small-breakout-shelf-controller";
import { ArcadeDownloadPackShelfController } from "./shelf-controllers/arcade-download-pack-shelf-controller";
import { flowActionForAccountURL } from "../account/account-links-regex-parser";
import { GroupingMediaPageHeaderShelfController } from "./shelf-controllers/grouping-tags-header-shelf-controller";
import { applySearchAdMissedOpportunityToShelvesIfNeeded } from "../ads/ad-common";
import { GroupingTagBrickShelfController } from "./shelf-controllers/grouping-tag-brick-shelf-controller";
// region Constants
/// The controllers that know how to render specific shelves
const shelfControllers = [
    new GroupingAppEventShelfController(),
    new GroupingArcadeFooterShelfController(),
    new GroupingBrickShelfController(),
    new GroupingRibbonBarShelfController(),
    new GroupingCategoryShelfController(),
    new GroupingEditorialCardShelfController(),
    new GroupingEditorialStoryCardShelfController(),
    new GroupingGameCenterContinuePlayingShelfController(),
    new GroupingGameCenterPopularWithYourFriendsController(),
    new GroupingGameCenterReengagementShelfController(),
    new GroupingGameCenterSuggestedFriendsController(),
    new GroupingGameCenterActivityFeedController(),
    new GroupingHeroCarouselShelfController(),
    new GroupingHorizontalCardShelfController(),
    new GroupingLargeBreakoutShelfController(),
    new GroupingLinkShelfController(),
    new GroupingLockupShelfController(),
    new GroupingPersonalizedLockupShelfController(),
    new GroupingSmallBreakoutShelfController(),
    new ArcadeDownloadPackShelfController(),
    new GroupingMediaPageHeaderShelfController(),
    new GroupingTagBrickShelfController(),
];
/**
 * For a given flattened grouping go through and use our controllers to render the associated shelves, this should be used
 * for the initial page load. The second fetches for these shelves are handled by the routing system and the routed
 * shelf controller. This method will add all the shelves to the current groupingParseContext.
 *
 * @param objectGraph The App Store dependency graph
 * @param flattenedGrouping The original grouping page response data from MAPI flattened into the list of featured content
 * @param groupingParseContext The current parse context for this rendering of the grouping.
 * @protected
 */
export function insertInitialShelvesIntoGroupingParseContext(objectGraph, flattenedGrouping, groupingParseContext) {
    validation.catchingContext(`parseGrouping`, () => {
        for (const mediaApiData of flattenedGrouping.data) {
            const featuredContentId = mediaAttributes.attributeAsNumber(mediaApiData, "editorialElementKind");
            if (types.isTopChart(featuredContentId)) {
                const editorialId = serverData.asString(mediaApiData, "id");
                groupingParseContext.chartSet = lookupChartSetForEditorialId(editorialId, flattenedGrouping.editorialChartSets);
            }
            else {
                groupingParseContext.chartSet = null;
            }
            const baseRequirements = groupingShelfControllerCommon.createBaseShelfRequirements(objectGraph, mediaApiData, groupingParseContext);
            const token = baseRequirements.shelfToken;
            const baseMetricsOptions = baseRequirements.metricsOptions;
            let shelf;
            for (const shelfController of shelfControllers) {
                if (shelfController.supports(objectGraph, mediaApiData, featuredContentId)) {
                    shelf = validation.catchingContext(`parseGroupingShelf`, () => {
                        return shelfController.createShelf(objectGraph, mediaApiData, groupingParseContext, token, baseMetricsOptions);
                    });
                    break;
                }
            }
            if (serverData.isDefinedNonNull(shelf)) {
                groupingParseContext.shelves.push(shelf);
                applySearchAdMissedOpportunityToShelvesIfNeeded(objectGraph, groupingParseContext.shelves, "searchLanding", baseMetricsOptions.id, groupingParseContext.metricsPageInformation);
            }
        }
    });
}
/**
 * Parse a single editorially programmed chart from media API data.
 * @returns The chart model or null.
 */
function makeEditorialChartFromMediaApiData(chartData) {
    const fcKind = mediaAttributes.attributeAsNumber(chartData, "editorialElementKind");
    if (!types.isTopChart(fcKind)) {
        return null;
    }
    return {
        id: serverData.asString(chartData, "id"),
        href: mediaAttributes.attributeAsString(chartData, "chartHref"),
        name: mediaAttributes.attributeAsString(chartData, "name"),
        type: mediaAttributes.attributeAsString(chartData, "chart"),
    };
}
/**
 * Parse a collection of charts, programmed by editorial, from media api data.
 * @returns The chart set model, or null.
 */
function makeEditorialChartSetFromMediaApiData(chartSetData) {
    const fcKind = mediaAttributes.attributeAsNumber(chartSetData, "editorialElementKind");
    if (fcKind !== 424 /* types.FeaturedContentID.AppStore_ChartSet */) {
        return null;
    }
    return {
        id: serverData.asString(chartSetData, "id"),
        name: mediaAttributes.attributeAsString(chartSetData, "name"),
        editorialCharts: mediaRelationship
            .relationshipCollection(chartSetData, "children")
            .map((chartData) => makeEditorialChartFromMediaApiData(chartData))
            .filter((chart) => isSome(chart)),
    };
}
/**
 * Given a list of chart sets, find the chart set that has the provided editorial identifier.
 *
 * @param editorialId The chart or chart set identifier from editorial.
 * @param chartSets The list of all chart sets from the grouping.
 * @returns The charts associated with the editorial item from the grouping.
 */
function lookupChartSetForEditorialId(editorialId, editorialChartSets) {
    for (const chartSet of editorialChartSets) {
        if (chartSet.id === editorialId) {
            return chartSet; // editorialId is for a chart set itself
        }
        for (const chart of chartSet.editorialCharts) {
            if (chart.id === editorialId) {
                return chartSet; // / editorialId is for a specific chart from the chart set.
            }
        }
    }
    return null;
}
/**
 * Take the media API data for a single grouping, and flatten that tree structure into a single list of media api data objects.
 *
 * @param mediaApiGroupingData The original media API data for a single grouping
 */
export function flattenMediaApiGroupingData(objectGraph, mediaApiGroupingData) {
    const groupingData = [];
    const chartSets = [];
    function addMediaApiDataToGroupingData(mediaApiData) {
        const featuredContentId = mediaAttributes.attributeAsNumber(mediaApiData, "editorialElementKind");
        validation.catchingContext(`flattenGroupingTree.addMediaApiDataToGroupingData: ${featuredContentId}`, () => {
            const groupingTabData = mediaRelationship.relationshipData(objectGraph, mediaApiData, "tabs");
            if (serverData.isDefinedNonNull(groupingTabData)) {
                addMediaApiDataToGroupingData(groupingTabData);
            }
            else if (types.shouldContinueToWalkChildren(featuredContentId)) {
                const featuredContentChildren = mediaRelationship.relationshipCollection(mediaApiData, "children");
                for (const featuredContentChild of featuredContentChildren) {
                    addMediaApiDataToGroupingData(featuredContentChild);
                }
            }
            else if (featuredContentId === 424 /* types.FeaturedContentID.AppStore_ChartSet */) {
                // Keep track of chartSets programmed by editorial, e.g. "Top Charts" includes "Top Free Apps" and "Top Paid Apps".
                const editorialChartSet = makeEditorialChartSetFromMediaApiData(mediaApiData);
                if (isSome(editorialChartSet)) {
                    chartSets.push(editorialChartSet);
                }
                // Add charts from the chartSet, as defined by editorial, to grouping page data.
                const chartSetChildren = mediaRelationship.relationshipCollection(mediaApiData, "children");
                for (const chartSetChild of chartSetChildren) {
                    addMediaApiDataToGroupingData(chartSetChild);
                }
            }
            else {
                groupingData.push(mediaApiData);
            }
        });
    }
    addMediaApiDataToGroupingData(mediaApiGroupingData);
    return {
        data: groupingData,
        editorialChartSets: chartSets,
        originalGroupingData: mediaApiGroupingData,
    };
}
// endregion
// region Shelves
/**
 * Create a shelf for footer buttons, e.g "Send Gift" and "Redeem".
 *
 * @return Shelf configured to display `FooterButtons`s.
 */
export function shelfForFooterButtons(objectGraph, metricsPageInformation, metricsLocationTracker) {
    var _a, _b, _c, _d, _e, _f;
    if (objectGraph.user && objectGraph.user.isManagedAppleID) {
        return null;
    }
    // Watch App Store does not support titled button stacks,
    // and has different footer buttons.
    if (objectGraph.client.isWatch) {
        const shelf = new models.Shelf("action");
        const items = [];
        const accountFlowAction = new models.FlowAction("account");
        accountFlowAction.title = objectGraph.loc.string("ACCOUNT", "Account");
        accountFlowAction.artwork = artworkBuilder.createArtworkForResource(objectGraph, "systemimage://person.crop.circle");
        const accountFlowClickOptions = {
            targetType: "button",
            id: "account",
            pageInformation: metricsPageInformation,
            locationTracker: metricsLocationTracker,
        };
        metricsHelpersClicks.addClickEventToAction(objectGraph, accountFlowAction, accountFlowClickOptions);
        items.push(accountFlowAction);
        shelf.items = items;
        shelf.accessibilityMetadata = createShelfAccessibilityMetadata(objectGraph, shelf);
        return shelf;
    }
    else {
        const items = [];
        const redeemTitle = objectGraph.loc.string("FOOTER_REDEEM", "Redeem");
        const redeemActionUrl = objectGraph.client.isVision
            ? objectGraph.bag.redeemCodeLanding
            : objectGraph.bag.redeemUrl;
        const redeemFlowAction = flowActionForAccountURL(objectGraph, redeemActionUrl);
        const redeemButton = new models.TitledButton(redeemTitle, redeemFlowAction);
        redeemButton.id = "redeem";
        items.push(redeemButton);
        if (objectGraph.bag.isMonetaryGiftingEnabled) {
            const giftTitle = objectGraph.loc.string("FOOTER_SEND_GIFT", "Send Gift");
            const giftActionUrl = "gift";
            const giftFlowAction = flowActionForAccountURL(objectGraph, giftActionUrl);
            const giftButton = new models.TitledButton(giftTitle, giftFlowAction);
            giftButton.id = "gift";
            items.push(giftButton);
        }
        const topUpUrl = objectGraph.bag.accountTopUpURL;
        if (isSome(topUpUrl)) {
            const topUpTitle = (_a = objectGraph.bag.accountTopUpTitle) !== null && _a !== void 0 ? _a : objectGraph.loc.string("FOOTER_ADD_MONEY");
            const topUpFlowAction = flowActionForAccountURL(objectGraph, topUpUrl);
            const topUpButton = new models.TitledButton(topUpTitle, topUpFlowAction);
            topUpButton.id = "topUp";
            items.push(topUpButton);
        }
        let shelf;
        if (objectGraph.client.isVision) {
            shelf = new models.Shelf("titledButton");
            shelf.items = items;
        }
        else {
            shelf = new models.Shelf("titledButtonStack");
            const stack = new models.TitledButtonStack(items);
            // On compact width, we want to place a line break after each button.
            stack.compactLineBreaks = stack.buttons.map((value, index) => index);
            shelf.items = [stack];
            const accessibilityLabel = objectGraph.loc.string("Shelves.Accessibility.Label");
            const roleDescription = objectGraph.loc.string("Shelves.Accessibility.RoleDescription");
            shelf.accessibilityMetadata = {
                label: (_d = (_b = shelf.title) !== null && _b !== void 0 ? _b : (_c = shelf.header) === null || _c === void 0 ? void 0 : _c.title) !== null && _d !== void 0 ? _d : accessibilityLabel,
                roleDescription: roleDescription.replace("%d", `${(_f = (_e = stack.buttons) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : 0}`),
            };
        }
        return shelf;
    }
}
/**
 * Create a T&C shelf that on click opens an external url.
 *
 * @param objectGraph
 * @param destinationUrl Url to open when terms and conditions is tapped.
 * @param hasSeparator Whether the footnote has a separator above it.
 * @return Shelf configured to display Terms and Conditions.
 */
export function shelfForTermsAndConditions(objectGraph, destinationUrl, hasSeparator = true) {
    const urlAction = new models.ExternalUrlAction(destinationUrl);
    const termsAndConditionTitle = objectGraph.loc.string("TermsAndConditions.Title");
    const footnote = new models.Footnote(termsAndConditionTitle);
    footnote.clickAction = urlAction;
    footnote.presentationStyle = ["hasChevron", "textLightensOnHighlight"];
    if (hasSeparator) {
        footnote.presentationStyle.push("hasSeparator");
    }
    const shelf = new models.Shelf("footnote");
    shelf.items = [footnote];
    if (objectGraph.bag.emailSupportLinkURL) {
        const emailSupportAction = new models.ExternalUrlAction(objectGraph.bag.emailSupportLinkURL);
        const emailSupport = new models.Footnote("Email Support");
        emailSupport.clickAction = emailSupportAction;
        emailSupport.presentationStyle = ["hasChevron", "textLightensOnHighlight"];
        if (hasSeparator) {
            emailSupport.presentationStyle.push("hasSeparator");
        }
        shelf.items.push(emailSupport);
    }
    return shelf;
}
export function shelfForUnifiedMessage(objectGraph, placement, context, deliveryMethod) {
    const shelf = new models.Shelf("unifiedMessage");
    shelf.id = placement;
    shelf.items = [new models.UnifiedMessage(placement, context, deliveryMethod)];
    shelf.isHidden = true;
    return shelf;
}
// endregion
//# sourceMappingURL=grouping-common.js.map