import { isNothing, isSome } from "@jet/environment";
import * as models from "../../../../api/models/index";
import * as serverData from "../../../../foundation/json-parsing/server-data";
import * as ageRatings from "../../../content/age-ratings";
import * as mediaAttributes from "../../../../foundation/media/attributes";
import * as mediaPlatformAttributes from "../../../../foundation/media/platform-attributes";
import * as mediaRelationship from "../../../../foundation/media/relationships";
import * as contentAttributes from "../../../content/attributes";
import * as storefrontContentRatingAnnotation from "./storefront-content-rating-annotation";
import { artworkTemplateForBundleImage, createArtworkForResource } from "../../../content/artwork/artwork";
import { makeRoutableArticlePageIntent } from "../../../../api/intents/routable-article-page-intent";
import { getLocale } from "../../../../common/locale";
/**
 * Attempts to create an age rating annotation, preferring the new "ageRating"
 * MAPI data. Falls back to "contentRatingsBySystem.appsApple" if needed.
 */
export function createAnnotation(objectGraph, data, isFirstPartyHideableApp, isArcadeApp, suppressTitle, shelfMetrics) {
    var _a;
    return ((_a = createModernAnnotation(objectGraph, data, isFirstPartyHideableApp, isArcadeApp, suppressTitle, shelfMetrics)) !== null && _a !== void 0 ? _a : createLegacyAnnotation(objectGraph, data, isFirstPartyHideableApp, isArcadeApp, suppressTitle, shelfMetrics));
}
/**
 * Returns an `Annotation` model from the new style "ageRating" MAPI age rating
 * data.
 */
function createModernAnnotation(objectGraph, data, isFirstPartyHideableApp, isArcadeApp, suppressTitle, shelfMetrics) {
    // The textual name of the rating, e.g. "18+"
    const name = ageRatings.name(objectGraph, data);
    if (isNothing(name)) {
        return null;
    }
    // "Learn More" link
    const learnMoreTitle = objectGraph.loc.string("InfoList.AgeRating.LearnMore");
    const learnMoreAction = createLearnMoreAction(objectGraph, learnMoreTitle);
    let annotationTitle;
    let annotationSummary;
    if (preprocessor.GAMES_TARGET) {
        if (ageRatings.hasInAppControls(objectGraph, data)) {
            annotationTitle = objectGraph.localizer.string("GameDetails.Annotation.AgeRating.Title", {
                ageRating: name,
            });
            annotationSummary = objectGraph.loc.string("GameDetails.Annotation.AgeRating.InAppControls.Summary");
        }
        else {
            annotationTitle = "";
            annotationSummary = objectGraph.localizer.string("GameDetails.Annotation.AgeRating.Title", {
                ageRating: name,
            });
        }
    }
    else {
        annotationTitle = objectGraph.loc.string("InfoList.AgeRating.Title");
        annotationSummary = name;
    }
    const annotation = new models.Annotation(annotationTitle, [], annotationSummary, learnMoreAction);
    // Set text for visionOS collapsed annotation
    if (objectGraph.client.isVision || preprocessor.GAMES_TARGET) {
        annotation.leadingText = name;
    }
    // Push either a pictogram representing the rating (currently just Korea
    // and Brazil use this), or a text encapsulation of the rating name.
    const pictogramResource = ageRatings.pictogramResource(objectGraph, data);
    if (isSome(pictogramResource)) {
        const pictogramArtwork = createArtworkForResource(objectGraph, artworkTemplateForBundleImage(pictogramResource), 30, 30);
        if (preprocessor.GAMES_TARGET) {
            annotation.expandedArtwork = pictogramArtwork;
        }
        else {
            annotation.items_V3.push({
                $kind: "artwork",
                artwork: pictogramArtwork,
            });
        }
    }
    else {
        annotation.items_V3.push({
            $kind: "textEncapsulation",
            text: name,
        });
    }
    // An optional description of the app's rating, potentially with some
    // information about the storefront's rating agency.
    const description = ageRatings.description(objectGraph, data);
    let ageRatingText = "";
    if (isSome(description)) {
        ageRatingText += description;
    }
    const linkedSubstrings = {};
    if ((objectGraph.client.isiOS || objectGraph.client.isMac || objectGraph.client.isVision) &&
        isSome(learnMoreAction)) {
        // iOS, macOS, and visionOS show the "Learn More" link as LinkableText.
        linkedSubstrings[learnMoreTitle] = learnMoreAction;
        if (ageRatingText.length > 0) {
            ageRatingText += "\n";
        }
        ageRatingText += learnMoreTitle;
    }
    const ageRatingLinkableText = new models.LinkableText(new models.StyledText(ageRatingText, "text/markdown"), linkedSubstrings);
    annotation.items_V3.push({
        $kind: "linkableText",
        linkableText: ageRatingLinkableText,
    });
    // Watch and Web use a button for the "Learn More" link.
    if ((objectGraph.client.isWatch || objectGraph.client.isWeb) && isSome(learnMoreAction)) {
        annotation.items_V3.push({
            $kind: "button",
            action: learnMoreAction,
            style: "infer",
        });
    }
    const contentRestrictionsAnnotation = contentRestrictionsAnnotationFromData(objectGraph, data);
    if (isSome(contentRestrictionsAnnotation)) {
        annotation.items_V3.push({
            $kind: "spacer",
        });
        annotation.items_V3.push(contentRestrictionsAnnotation);
    }
    // Optional external website where developer can provide more context on
    // their app's rating and parental controls. This link is omitted for TV
    // since there is no web browser.
    const developerAgeGuidanceURL = ageRatings.developerAgeGuidanceURL(objectGraph, data);
    if (isSome(developerAgeGuidanceURL) && !objectGraph.client.isTV) {
        const openDeveloperAgeGuidanceURLAction = new models.ExternalUrlAction(developerAgeGuidanceURL);
        openDeveloperAgeGuidanceURLAction.title = objectGraph.loc.string("InfoList.AgeRating.DeveloperInfo");
        annotation.items_V3.push({
            $kind: "spacer",
        });
        annotation.items_V3.push({
            $kind: "button",
            action: openDeveloperAgeGuidanceURLAction,
        });
    }
    return annotation;
}
/**
 * Returns an `Annotation` model from the old style
 * "contentRatingsBySystem.appsApple" MAPI data.
 */
function createLegacyAnnotation(objectGraph, data, isFirstPartyHideableApp, isArcadeApp, suppressTitle, shelfMetrics) {
    const contentRating = mediaAttributes.attributeAsDictionary(data, "contentRatingsBySystem.appsApple");
    if (serverData.isNull(contentRating)) {
        return null;
    }
    const name = serverData.asString(contentRating, "name");
    if (serverData.isNull(name)) {
        return null;
    }
    const rank = serverData.asNumber(contentRating, "rank");
    if (rank === 99) {
        // This indicates the app is not yet rated, which should only happen in test environments.
        return null;
    }
    const advisories = serverData.asArrayOrEmpty(contentRating, "advisories");
    // Build the summary.
    let summary;
    const ageBand = mediaPlatformAttributes.platformAttributeAsDictionary(data, contentAttributes.bestAttributePlatformFromData(objectGraph, data), "ageBand");
    const minAge = serverData.asNumber(ageBand, "minAge");
    const maxAge = serverData.asNumber(ageBand, "maxAge");
    if (serverData.isDefinedNonNull(minAge) && serverData.isDefinedNonNull(maxAge)) {
        summary = objectGraph.loc
            .string("InfoList.AgeRating.Summary")
            .replace("{ageRating}", name)
            .replace("{minAgeRating}", objectGraph.loc.decimal(minAge))
            .replace("{maxAgeRating}", objectGraph.loc.decimal(maxAge));
    }
    else {
        summary = name;
    }
    const ageRatingAnnotationItems = [];
    // AnnotationItem will insert vertical space between the summary and each
    // advisory if they are separate items, so keep them as a single item.
    let appleRatingString = "";
    if (isSome(summary)) {
        // Always use the Apple rating summary as our first item.
        appleRatingString += summary;
    }
    for (const advisory of advisories) {
        // Tack on the advisories.
        appleRatingString += "\n";
        appleRatingString += advisory;
    }
    ageRatingAnnotationItems.push(new models.AnnotationItem(appleRatingString));
    // Display the storefront-specific content rating if present under the
    // App Store content rating (currently this is just for South Korea).
    // TV displays the storefront-specific content rating in a separate
    // annotation section.
    if (!objectGraph.client.isTV) {
        const pictogramRow = storefrontContentRatingAnnotation.contentRatingPictogramRowIfNeeded(objectGraph, data);
        if (isSome(pictogramRow)) {
            ageRatingAnnotationItems.push(pictogramRow);
        }
        // Check if we are required to display the age verification annotations (e.g. this is true for the South Korean storefront)
        const ageVerificationAnnotationItem = ageVerificationAnnotationItemIfNeeded(objectGraph, data);
        if (isSome(ageVerificationAnnotationItem)) {
            ageRatingAnnotationItems.push(ageVerificationAnnotationItem);
        }
    }
    let finalSummaryToUse;
    if (objectGraph.client.isVision) {
        finalSummaryToUse = objectGraph.loc.string("InfoList.AgeRating.Years").replace("{age}", name);
    }
    else if (preprocessor.GAMES_TARGET) {
        finalSummaryToUse = objectGraph.loc.string("InfoList.AgeRating.Title");
    }
    else if (ageRatingAnnotationItems.length > 1 || ageRatingAnnotationItems[0].text !== summary) {
        // Use an explicit summary unless we're just showing a simple rating
        // without advisories. E.g. a rating of "4+" does not need a summary.
        finalSummaryToUse = summary;
    }
    const ageRatingTitle = suppressTitle ? "" : objectGraph.loc.string("InfoList.AgeRating.Title");
    // Learn More link
    const learnMoreTitle = objectGraph.loc.string("InfoList.AgeRating.LearnMore");
    const learnMoreAction = createLearnMoreAction(objectGraph, learnMoreTitle);
    const annotation = new models.Annotation(ageRatingTitle, ageRatingAnnotationItems, finalSummaryToUse, learnMoreAction);
    if (objectGraph.client.isVision || preprocessor.GAMES_TARGET) {
        annotation.leadingText = name;
    }
    return annotation;
}
/**
 * Creates an `Action` that navigates to the App Store Age Ratings editorial item.
 * @param objectGraph The App Store Object Graph.
 * @param title The title for the action.
 * @returns A platform-appropriate `Action` linking to the Age Ratings editorial page.
 */
function createLearnMoreAction(objectGraph, title) {
    let learnMoreAction;
    if (isSome(objectGraph.bag.ageRatingLearnMoreEditorialItemId) &&
        objectGraph.bag.ageRatingLearnMoreEditorialItemId.length > 0) {
        const flowAction = new models.FlowAction("article");
        flowAction.title = title;
        flowAction.pageUrl = `https://apps.apple.com/story/id${objectGraph.bag.ageRatingLearnMoreEditorialItemId}`;
        const routableArticlePageIntent = makeRoutableArticlePageIntent({
            ...getLocale(objectGraph),
            id: objectGraph.bag.ageRatingLearnMoreEditorialItemId,
        });
        flowAction.destination = routableArticlePageIntent;
        if (objectGraph.client.isVision) {
            const dismissAction = new models.FlowBackAction("sheetDismiss");
            learnMoreAction = new models.CompoundAction([dismissAction, flowAction]);
            learnMoreAction.title = title;
        }
        else {
            learnMoreAction = flowAction;
        }
    }
    return learnMoreAction;
}
// #region Age Verification
/**
 * Returns a special annotation item when age verification is necessary to download an app.
 * @param objectGraph The App Store object graph.
 * @param data Media API data representing an app.
 */
export function ageVerificationAnnotationItemIfNeeded(objectGraph, data) {
    if (objectGraph.bag.requireAgeVerification &&
        checkContentRating(objectGraph, data, "seventeenPlus") &&
        isProductGenreGame(objectGraph, data)) {
        let ageVerificationString;
        const isBundle = data.type === "app-bundles";
        if (isBundle) {
            // If this bundle contains a GRAC-registered product, show a message for GRAC bundles.
            // Search through the bundle's apps and stop if a GRAC-registered app is found.
            const childrenRelationship = mediaRelationship.relationship(data, "apps");
            if (serverData.isDefinedNonNull(childrenRelationship)) {
                for (const childApp of childrenRelationship.data) {
                    const gracRegistrationNumber = mediaAttributes.attributeAsString(childApp, "gracRegistrationNumber");
                    if (serverData.isDefinedNonNull(gracRegistrationNumber)) {
                        ageVerificationString = objectGraph.loc.string("AgeVerification.ProductPage.Rating.BundleUnsuitableForJuveniles");
                        break;
                    }
                }
            }
        }
        else if (serverData.isDefinedNonNull(mediaAttributes.attributeAsString(data, "gracRegistrationNumber"))) {
            // If this product is GRAC-registered, show a message for GRAC products.
            ageVerificationString = objectGraph.loc.string("AgeVerification.ProductPage.Rating.UnsuitableForJuveniles");
        }
        if (isNothing(ageVerificationString)) {
            return null;
        }
        return new models.AnnotationItem(ageVerificationString);
    }
    else {
        return null;
    }
}
/**
 * Returns a boolean indicating if a content rating is at least as high as
 * the supplied rating rank.
 * @param data Media API data representing an app.
 * @param isAtLeast A content rating rank name.
 */
function checkContentRating(objectGraph, data, isAtLeast) {
    const rating = mediaAttributes.attributeAsNumber(data, "contentRatingsBySystem.appsApple.rank");
    if (isNothing(rating)) {
        return false;
    }
    let contentRatingRankValue;
    switch (isAtLeast) {
        case "twelvePlus":
            contentRatingRankValue = 3;
            break;
        case "seventeenPlus":
            contentRatingRankValue = 4;
            break;
        case "adultOnly":
            contentRatingRankValue = 5;
            break;
        default:
            contentRatingRankValue = 1;
    }
    return rating >= contentRatingRankValue;
}
/**
 * Returns a boolean indicating if the product is classified as game.
 * @param data The product data.
 */
function isProductGenreGame(objectGraph, data) {
    var _a;
    const genreDicts = (_a = mediaRelationship.relationshipCollection(data, "genres")) !== null && _a !== void 0 ? _a : [];
    for (const candidateDict of genreDicts) {
        if (serverData.asString(candidateDict, "id") === 6014 /* constants.GenreIds.Games */.toString()) {
            return true;
        }
    }
    return false;
}
/**
 * Returns an `AnnotationItemLinkableText` model representing the content descriptors.
 * @param objectGraph The App Store object graph
 * @param data The age rating object pulled from the app data.
 */
function contentRestrictionsAnnotationFromData(objectGraph, data) {
    const contentLevels = mediaAttributes.attributeAsArrayOrEmpty(data, "ageRating.contentLevels");
    let contentDescriptorsString = "";
    for (const contentLevel of contentLevels) {
        const contentLevelHeading = serverData.asString(contentLevel, "level");
        const contentDescriptors = serverData.asArrayOrEmpty(contentLevel, "contentDescriptors");
        // Skip this content level if it somehow doesn't have descriptors.
        if (contentDescriptors.length === 0) {
            continue;
        }
        // Add newline between proceeding content level
        if (contentDescriptorsString.length > 0) {
            contentDescriptorsString += "\n\n";
        }
        // Heading
        contentDescriptorsString += `**${contentLevelHeading}**`;
        // Descriptors
        for (const contentDescriptor of contentDescriptors) {
            const description = serverData.asString(contentDescriptor, "description");
            if (isSome(description)) {
                contentDescriptorsString += "\n";
                contentDescriptorsString += description;
            }
        }
    }
    if (contentDescriptorsString.length === 0) {
        return undefined;
    }
    const linkableText = new models.LinkableText(new models.StyledText(contentDescriptorsString, "text/markdown"));
    return {
        $kind: "linkableText",
        linkableText: linkableText,
    };
}
// #endregion
//# sourceMappingURL=content-rating-annotation.js.map