import * as validation from "@jet/environment/json/validation";
import * as models from "../../api/models";
import * as serverData from "../../foundation/json-parsing/server-data";
import { attributeAsBooleanOrFalse } from "../../foundation/media/attributes";
import { openTVArcadeAppAction } from "../arcade/arcade-common";
import { editorialNotesFromData } from "../content/content";
import * as metricsHelpersLocation from "../metrics/helpers/location";
import { cardDisplayStyleFromData, collapsedHeadingForTodayCard, defaultTodayCardConfiguration, todayCardFromData, } from "./today-card-util";
import { TodayCardDisplayStyle, TodayCardMetricsDisplayStyle, TodayParseContext, } from "./today-types";
const supportedSmallHorizontalCardKinds = new Set([
    "artwork",
    "appIcon",
    "grid",
    "multiApp",
    "video",
]);
const supportedMediumHorizontalCardKinds = new Set([
    "brandedSingleApp",
    "artwork",
    "appIcon",
    "grid",
    "multiApp",
    "video",
]);
const supportedLargeHorizontalCardKinds = new Set([
    "brandedSingleApp",
    "artwork",
    "appIcon",
    "grid",
    "multiApp",
    "video",
]);
const iOSSupportedSmallHorizontalCardKinds = new Set([
    "brandedSingleApp",
    "artwork",
    "grid",
    "video",
]);
const webSupportedSmallHorizontalCardKinds = new Set([
    "brandedSingleApp",
    "artwork",
    "river",
    "appIcon",
    "video",
]);
// MARK: - Horizontal Cards
/**
 * The crop code to use for a card using the provided horizontal card shelf content type.
 * @param {ShelfContentType} contentType The content type of the shelf's items.
 * @returns {CropCode} The crop code to use for the artwork.
 */
function horizontalCardCropCodeForContentType(objectGraph, contentType, cardDisplayStyle) {
    switch (contentType) {
        case "smallStoryCard":
            if (objectGraph.host.isTV) {
                return cardDisplayStyle === TodayCardDisplayStyle.Video ? null : { defaultCrop: "fo" };
            }
            else if (objectGraph.host.isiOS) {
                return null;
            }
            else if (objectGraph.client.isWeb) {
                return { defaultCrop: "sr" };
            }
            else {
                return { defaultCrop: "em" };
            }
        case "mediumStoryCard":
            return { defaultCrop: "el" };
        case "largeStoryCard":
            return cardDisplayStyle === TodayCardDisplayStyle.Video ? { defaultCrop: "sr" } : { defaultCrop: "ek" };
        default:
            return null;
    }
}
export function isHorizontalCardSupportedForKind(objectGraph, kind, contentType) {
    switch (contentType) {
        case "smallStoryCard":
            if (objectGraph.host.isiOS) {
                return iOSSupportedSmallHorizontalCardKinds.has(kind);
            }
            else if (objectGraph.client.isWeb) {
                return webSupportedSmallHorizontalCardKinds.has(kind);
            }
            else {
                return supportedSmallHorizontalCardKinds.has(kind);
            }
        case "mediumStoryCard":
            return supportedMediumHorizontalCardKinds.has(kind);
        case "largeStoryCard":
            return supportedLargeHorizontalCardKinds.has(kind);
        case "todayCard":
            return objectGraph.client.isWatch;
        default:
            return false;
    }
}
export function horizontalCardItemsFromCards(objectGraph, cards, contentType, context, contentUnavailable, horizontalShelfCardConfig) {
    const items = [];
    for (const cardData of cards) {
        const todayCard = horizontalCardItemFromCard(objectGraph, cardData, contentType, context, contentUnavailable, horizontalShelfCardConfig);
        if (serverData.isNullOrEmpty(todayCard)) {
            continue;
        }
        items.push(todayCard);
        metricsHelpersLocation.nextPosition(context.metricsLocationTracker);
    }
    return items;
}
export function horizontalCardItemFromCard(objectGraph, cardData, contentType, context, contentUnavailable, horizontalShelfCardConfig) {
    const parseContext = new TodayParseContext(context.metricsPageInformation, context.metricsLocationTracker);
    if (horizontalShelfCardConfig === null || horizontalShelfCardConfig === undefined) {
        horizontalShelfCardConfig = defaultTodayCardConfiguration(objectGraph);
        horizontalShelfCardConfig.isHorizontalShelfContext = true;
    }
    if (objectGraph.client.deviceType !== "watch") {
        // All today cards are deserialized through this code path on watchOS.
        // We support all substyles, so we need to not specify this override.
        horizontalShelfCardConfig.coercedCollectionTodayCardDisplayStyle = TodayCardDisplayStyle.Grid;
    }
    const cardDisplayStyle = cardDisplayStyleFromData(cardData, horizontalShelfCardConfig.coercedCollectionTodayCardDisplayStyle);
    horizontalShelfCardConfig.prevailingCropCodes = horizontalCardCropCodeForContentType(objectGraph, contentType, cardDisplayStyle);
    horizontalShelfCardConfig.horizontalCardContentType = contentType;
    if (!serverData.isDefinedNonNull(cardData.attributes)) {
        if (contentUnavailable) {
            contentUnavailable(cardData);
        }
        return null;
    }
    const todayCard = todayCardFromData(objectGraph, cardData, horizontalShelfCardConfig, parseContext, context.augmentingData);
    // Ignore the Date here, as we don't care about using it as a refresh signal when embedded in a page other than Today for now.
    if (serverData.isNull(todayCard)) {
        return null;
    }
    if (objectGraph.client.isiOS) {
        todayCard.collapsedHeading = collapsedHeadingForTodayCard(objectGraph, todayCard);
        todayCard.inlineDescription = featuredInDescriptionForCard(objectGraph, todayCard, cardData);
        // In certain fallback cases, todayCardFromData() will make title and heading the same.
        // If our generated heading and description are the same, we just show the heading.
        if (todayCard.inlineDescription === todayCard.collapsedHeading) {
            todayCard.inlineDescription = null;
        }
        // We want to avoid displaying the branded title over AotD/GotD cards, but only when they are not using
        // the fallback art.
        const brandedMedia = todayCard.media;
        if (brandedMedia && brandedMedia.kind === "brandedSingleApp") {
            // <rdar://problem/37249620> LOC: GLOBAL: App Store on iOS: Word wrapping in App/Game of the...
            // Branded text on inline today cards is kind of a mess visually, so rely on the inline
            // description.
            todayCard.title = null;
        }
    }
    if (contentType === "largeStoryCard") {
        const heroMedia = todayCard.heroMedia;
        if (!serverData.isDefinedNonNull(heroMedia) ||
            (heroMedia.artworks.length === 0 && heroMedia.videos.length === 0)) {
            return null;
        }
    }
    if (isHorizontalCardSupportedForKind(objectGraph, todayCard.media.kind, contentType)) {
        if (serverData.isDefinedNonNull(context.filterOutMediaCardKinds) &&
            context.filterOutMediaCardKinds.has(todayCard.media.kind)) {
            return null;
        }
    }
    // Override `todayCard.clickAction` for some special cards.
    overrideClickActionForTVAcquisitionCardIfNeeded(objectGraph, todayCard, cardData);
    return todayCard;
}
export function shelfForHorizontalCardItems(objectGraph, cards, contentType, title, subtitle, context, contentUnavailable) {
    if (!serverData.isDefinedNonNull(contentType)) {
        return null;
    }
    const shelf = new models.Shelf(contentType);
    if (title) {
        shelf.title = title;
    }
    shelf.subtitle = subtitle;
    shelf.isHorizontal = true;
    switch (contentType) {
        case "todayBrick": // As iOS doesn't support horizontalCardItemsFromCards, we map the small/medium/large story cards to todayBricks instead.
            shelf.items = [
                featuredInTodayCardsFromData(objectGraph, cards, context.metricsPageInformation, context.metricsLocationTracker, () => true, contentUnavailable),
            ];
            break;
        default:
            shelf.items = horizontalCardItemsFromCards(objectGraph, cards, contentType, context, contentUnavailable);
            break;
    }
    return shelf;
}
/**
 * Creates a shelf for mini today cards.
 *
 * @param objectGraph - The application store object graph.
 * @param cards - An array of media data structures.
 * @param contentType - The type of content for the shelf.
 * @param title - The title of the shelf.
 * @param subtitle - The subtitle of the shelf.
 * @param context - The context for parsing today data.
 * @param contentUnavailable - Optional handler for unavailable content.
 * @returns A shelf containing today cards.
 */
export function shelfForMiniTodayCards(objectGraph, cards, title, subtitle, context, contentUnavailable) {
    const shelf = new models.Shelf("miniTodayCard");
    if (title) {
        shelf.title = title;
    }
    shelf.subtitle = subtitle;
    shelf.isHorizontal = true;
    const items = [];
    const cardConfig = defaultTodayCardConfiguration(objectGraph);
    cardConfig.metricsDisplayStyle = TodayCardMetricsDisplayStyle.SmallCard;
    cardConfig.alwaysShowBadgeInSmallCards = true;
    cardConfig.alwaysUseMaterialBlur = true;
    for (const cardData of cards) {
        if (!serverData.isDefinedNonNull(cardData.attributes)) {
            if (contentUnavailable) {
                contentUnavailable(cardData);
            }
            continue;
        }
        const todayCard = todayCardFromData(objectGraph, cardData, cardConfig, context);
        if (serverData.isNullOrEmpty(todayCard)) {
            continue;
        }
        items.push(todayCard);
        metricsHelpersLocation.nextPosition(context.locationTracker);
    }
    shelf.items = items;
    return shelf;
}
// MARK: - Featured In
/**
 * Determines the description for the card, were it to appear inline.
 * @param {TodayCard} card The card in question (for legacy support)
 * @param {Data} data the card data to get the description from
 * @returns {string} The description text to use for the card.
 */
function featuredInDescriptionForCard(objectGraph, card, data) {
    const isSmallStoryCardsSupported = objectGraph.host.isiOS || objectGraph.host.isMac || objectGraph.host.isWeb;
    if (isSmallStoryCardsSupported) {
        let editorialName = editorialNotesFromData(objectGraph, data, "name");
        if (serverData.isDefinedNonNull(editorialName)) {
            editorialName = editorialName.replace(/\n/g, " ");
        }
        switch (card.media.kind) {
            case "brandedSingleApp":
                if (card.overlay instanceof models.TodayCardMarketingLockupOverlay &&
                    serverData.isDefinedNonNull(card.overlay.lockup)) {
                    return card.overlay.lockup.title;
                }
                else {
                    return editorialName;
                }
            default:
                return editorialName;
        }
    }
    switch (card.media.kind) {
        case "brandedSingleApp":
            if (card.overlay instanceof models.TodayCardThreeLineOverlay) {
                return card.overlay.heading;
            }
            else if (serverData.isDefinedNonNull(card.title)) {
                return card.title.replace(/\n/g, " ");
            }
            return null;
        default:
            const unformattedDescription = objectGraph.loc.string("TODAY_BRICK_STANDARD_DESCRIPTION");
            let heading;
            let title;
            if (card.overlay instanceof models.TodayCardThreeLineOverlay) {
                heading = card.overlay.heading;
                title = card.overlay.title;
            }
            else {
                heading = card.heading;
                title = card.title;
            }
            if (!unformattedDescription || !heading || !title) {
                return null;
            }
            return unformattedDescription.replace("{heading}", heading).replace("{title}", title);
    }
}
export function featuredInTodayCardsFromData(objectGraph, dataArray, metricsPageInformation, metricsLocationTracker, isIncluded, contentUnavailable) {
    return validation.context("todayCardsFromPlatformData", () => {
        if (!dataArray) {
            return null;
        }
        const featuredInCardConfig = defaultTodayCardConfiguration(objectGraph);
        featuredInCardConfig.enableFullScreenVideo = false;
        featuredInCardConfig.coercedCollectionTodayCardDisplayStyle = TodayCardDisplayStyle.Grid;
        featuredInCardConfig.prevailingCropCodes = { defaultCrop: "fo" };
        featuredInCardConfig.isHorizontalShelfContext = true;
        const context = new TodayParseContext(metricsPageInformation, metricsLocationTracker);
        const todayCards = [];
        for (const data of dataArray) {
            if (!serverData.isDefinedNonNull(data.attributes)) {
                if (contentUnavailable) {
                    contentUnavailable(data);
                }
                continue;
            }
            const todayCard = todayCardFromData(objectGraph, data, featuredInCardConfig, context);
            // Ignore the Date here, as we don't care about using it as a refresh signal when embedded in a page other than Today for now.
            if (serverData.isNull(todayCard)) {
                continue;
            }
            if (isIncluded(todayCard)) {
                todayCard.collapsedHeading = collapsedHeadingForTodayCard(objectGraph, todayCard);
                todayCard.inlineDescription = featuredInDescriptionForCard(objectGraph, todayCard, data);
                // In certain fallback cases, todayCardFromData() will make title and heading the same.
                // If our generated heading and description are the same, we just show the heading.
                const isSmallStoryCardsSupported = objectGraph.host.isiOS || objectGraph.host.isMac || objectGraph.host.isWeb;
                if (isSmallStoryCardsSupported && todayCard.inlineDescription === todayCard.collapsedHeading) {
                    todayCard.inlineDescription = null;
                }
                // We want to avoid displaying the branded title over AotD/GotD cards, but only when they are not using
                // the fallback art.
                const brandedMedia = todayCard.media;
                if (brandedMedia && brandedMedia.kind === "brandedSingleApp") {
                    // <rdar://problem/37249620> LOC: GLOBAL: App Store on iOS: Word wrapping in App/Game of the...
                    // Branded text on inline today cards is kind of a mess visually, so rely on the inline
                    // description.
                    todayCard.title = null;
                }
                todayCards.push(todayCard);
            }
        }
        if (!todayCards.length) {
            return null;
        }
        return new models.InlineTodayCards(todayCards);
    });
}
// MARK: - tvOS Acquisition EI Card
/**
 * On tvOS, some special editorial items are supposed to link directly into the Apple Arcade app.
 * This is to override the click action if needed.
 * @param card Today card to potentially modify.
 * @param data Data that card was built from.
 */
function overrideClickActionForTVAcquisitionCardIfNeeded(objectGraph, card, data) {
    if (objectGraph.client.deviceType !== "tv" || !attributeAsBooleanOrFalse(data, "isAcquisition")) {
        return; // Only override on acquisition stories on tvOS.
    }
    const openArcadeAppAction = openTVArcadeAppAction(objectGraph);
    card.clickAction = openArcadeAppAction;
}
// endregion
//# sourceMappingURL=today-horizontal-card-util.js.map