/**
 * Created by km on 10/14/16.
 */
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 mediaRelationship from "../../foundation/media/relationships";
import { Path, Protocol, Parameters } from "../../foundation/network/url-constants";
import * as urls from "../../foundation/network/urls";
import * as objects from "../../foundation/util/objects";
import * as contentAttributes from "../content/attributes";
import * as sad from "../content/sad";
import * as metricsHelpersLocation from "../metrics/helpers/location";
import * as metricsHelpersImpressions from "../metrics/helpers/impressions";
import * as pagination from "../builders/pagination";
import * as artworkBuilder from "../content/artwork/artwork";
import { supportedAppPlatformsFromData } from "../content/content";
import * as flowPreview from "../content/flow-preview";
import * as productPageUtil from "./product-page-util";
import { createProductReviewActions } from "./shelves/shelf-based-reviews-shelves";
import { flowPreviewActionsConfigurationForReviewSummaryFromData } from "../content/flow-preview";
import { isNothing, isSome, unwrapOptional } from "@jet/environment";
import { createEditorsChoiceModel } from "./shelves/editors-choice-shelf";
import { subtitleFromData } from "../lockups/lockups";
import { makeProductPageIntent } from "../../api/intents/product-page-intent";
import { getPlatform } from "../preview-platform";
import { getLocale } from "../locale";
import { actionFor } from "../../foundation/runtime/action-provider";
import { makeSeeAllPageIntent } from "../../api/intents/see-all-page-intent";
import { makeSeeAllPageURL } from "./intent-controller-routing";
import * as metricsHelpersClicks from "../metrics/helpers/clicks";
const displayableKindMobileSoftware = "11";
const displayableKindMobileSoftwareBundle = "43";
const displayableKindMacSoftware = "30";
const displayableKindMacSoftwareBundle = "44";
// Mapping of displayable-kind from software to bundle
const softwareToBundleKindMap = {
    [displayableKindMobileSoftware]: displayableKindMobileSoftwareBundle,
    [displayableKindMacSoftware]: displayableKindMacSoftwareBundle,
};
/// The default sort id to use, `Most Helpful`.
const sortIdDefault = "helpful";
/**
 * Token used to construct a personalized reviews shelf.
 */
export class PersonalizedReviewsShelfToken {
}
/**
 * Creates a pagination url for reviews pagination.
 */
export function reviewsPaginationUrl(objectGraph, adamId, sort) {
    return `${Protocol.internal}:/${Path.reviews}/${Path.shelf}/${adamId}/${sort}`;
}
/**
 * Creates a page url for changing sorting order.
 */
export function sortedReviewsPageUrl(objectGraph, adamId, sort, sortedReviewsPageToken = null) {
    let url = `${Protocol.internal}:/${Path.reviews}/${adamId}/${sort}`;
    if (serverData.isDefinedNonNullNonEmpty(sortedReviewsPageToken)) {
        url = `${url}/?${Parameters.token}=${encodeURIComponent(JSON.stringify(sortedReviewsPageToken))}`;
    }
    return url;
}
/**
 * Creates a pagination token.
 */
export function createReviewsPageToken(objectGraph, adamId, nextHref, sort, remainingContent) {
    return {
        url: reviewsPaginationUrl(objectGraph, adamId, sort),
        remainingContent: remainingContent,
        nextHref: nextHref,
        profile: "lockup",
        maxPerPage: pagination.suggestedMaxPerPage,
        highestOrdinal: 0,
        metricsPageInformation: null,
        metricsLocationTracker: null,
    };
}
/**
 * Whether reviews should be suppressed for the given app.
 *
 * @param {Data} data MAPI data blob describing the app.
 * @returns {boolean} Returns `true` if reviews are restricted.
 */
export function shouldSuppressReviews(objectGraph, data) {
    if (!serverData.isDefinedNonNull(data)) {
        return false;
    }
    // If we have a system deletable and force-1st-party-app-review bag key
    const allowsReviewsForSADApp = shouldAllowReviewsForSADApp(objectGraph, data);
    if (allowsReviewsForSADApp) {
        return false;
    }
    // Suppress reviews for first party apps
    const isFirstPartyHideableApp = mediaAttributes.attributeAsBooleanOrFalse(data, "isFirstPartyHideableApp");
    if (isFirstPartyHideableApp) {
        return true;
    }
    // Suppress reviews for restricted apps
    const areReviewsRestricted = mediaAttributes.attributeAsBooleanOrFalse(data, "reviewsRestricted");
    if (areReviewsRestricted) {
        return true;
    }
    return false;
}
/**
 * Whether reviews should be allowed for the given app if it is a 1st party/SAD app.
 *
 * @param {Data} data MAPI data blob describing the app.
 * @returns {boolean} Returns `true` if the app is a 1st party/SAD app and current bag has reviews enabled for 1st party/SAD apps.
 */
export function shouldAllowReviewsForSADApp(objectGraph, data) {
    if (serverData.isNullOrEmpty(data) || !objectGraph.bag.enableSystemAppReviews) {
        return false;
    }
    // Since the bag for watch and iOS have different apps included as SAD apps, it is possible that we are not showing reviews for the following scenario:
    // The watch is direct linked to an app that is iOS only. This means that is should be SAD app from the iOS side, but is not a SAD app on the watch bag,
    // so it doesn't qualify for reviews. However, these apps have the metadata tag of "isFirstPartyHideableApp" that we will use to circumvent this limitation.
    // For watch, we will see if an app is a SAD app for the watch, or if an app is technically a SAD app for the iPhone we are viewing on the watch.
    if (objectGraph.client.isWatch) {
        return (sad.systemApps(objectGraph).isSystemAppFromData(data) ||
            mediaAttributes.attributeAsBooleanOrFalse(data, "isFirstPartyHideableApp"));
    }
    else {
        return sad.systemApps(objectGraph).isSystemAppFromData(data);
    }
}
/**
 * Whether reviews should be allowed for a given app, this returns true for all standard apps, for system apps
 * this will return true only if system app reviews are enabled. For non-shelf-based product pages we return `true` because
 * this logic is handled natively.
 *
 * @param objectGraph
 * @param {Data} data MAPI data blob describing the app.
 * @returns {boolean} Returns `true` if the app is not a system app or if system app reviews are allowed.
 */
export function isAppReviewable(objectGraph, data) {
    if (productPageUtil.isShelfBased(objectGraph)) {
        return true;
    }
    if (serverData.isNullOrEmpty(data)) {
        return false;
    }
    let isSystemApp;
    // Since the bag for watch and iOS have different apps included as SAD apps, it is possible that we are not showing reviews for the following scenario:
    // The watch is direct linked to an app that is iOS only. This means that is should be SAD app from the iOS side, but is not a SAD app on the watch bag,
    // so it doesn't qualify for reviews. However, these apps have the metadata tag of "isFirstPartyHideableApp" that we will use to circumvent this limitation.
    // For watch, we will see if an app is a SAD app for the watch, or if an app is technically a SAD app for the iPhone we are viewing on the watch.
    if (objectGraph.client.isWatch) {
        isSystemApp =
            sad.systemApps(objectGraph).isSystemAppFromData(data) ||
                mediaAttributes.attributeAsBooleanOrFalse(data, "isFirstPartyHideableApp");
    }
    else {
        isSystemApp = sad.systemApps(objectGraph).isSystemAppFromData(data);
    }
    return !isSystemApp || objectGraph.bag.enableSystemAppReviews;
}
/**
 * Generates a tap-to-rate endpoint URL for the given parameter.
 * @param adamId    The adam id of the product to get review data for.
 * @param isBundle Whether this is a bundle adamId
 * @returns A URL for posting tap-to-rate data.
 */
function assembleUserRateURL(objectGraph, adamId, isBundle) {
    return createBaseURL(objectGraph.bag.userRateURL, isBundle).param("id", adamId).build();
}
/**
 * Generates a writeUserReview endpoint URL for the given parameter.
 * @param adamId    The adam id of the product to be reviewed.
 * @param isBundle Whether this is a bundle adamId
 * @returns A URL for posting write review data.
 */
function assembleWriteReviewURL(objectGraph, adamId, isBundle) {
    return createBaseURL(objectGraph.bag.writeReviewURL, isBundle).param("id", adamId).build();
}
function createBaseURL(baseURL, isBundle) {
    const url = urls.URL.from(baseURL);
    const displayableKind = serverData.asString(url.query, "displayable-kind");
    // Convert displayable-kind for bundles
    if (isBundle && (displayableKind === null || displayableKind === void 0 ? void 0 : displayableKind.length) > 0) {
        url.query["displayable-kind"] = softwareToBundleKindMap[displayableKind] || displayableKind;
    }
    return url;
}
/**
 * Create and return a rate action for a given adamId.
 * @param adamId    The adamId of the app to rate
 * @param isBundle Whether this is a bundle adamId
 * @param appName the name of the app
 * @returns A new rate action.
 */
export function userRateAction(objectGraph, adamId, isBundle, appName = null) {
    const successToast = new models.AlertAction("toast");
    successToast.title = objectGraph.loc.string("TOAST_TAP_TO_RATE_TITLE");
    successToast.message = objectGraph.loc.string("TOAST_TAP_TO_RATE_DESCRIPTION");
    successToast.artwork = artworkBuilder.createArtworkForResource(objectGraph, "resource://ToastStar.png", 95.0, 90.0);
    const action = new models.RateAction(assembleUserRateURL(objectGraph, adamId, isBundle));
    action.adamId = adamId;
    action.method = "POST";
    action.isStoreRequest = true;
    action.disableCache = true;
    action.successAction = successToast;
    const ratingParameter = new models.HttpTemplateParameter("rating", "urlQuery", "decimalPad");
    const appVersionParameter = new models.HttpTemplateParameter("version-to-review", "urlQuery", "decimalPad");
    action.parameters = [ratingParameter, appVersionParameter];
    if (objectGraph.client.isTV && (appName === null || appName === void 0 ? void 0 : appName.length) > 0) {
        action.title = objectGraph.loc.string("TV_RATE_PRODUCT").replace("{title}", appName);
    }
    return action;
}
export function createProductReviewsList(objectGraph, ratingsData, reviewItems, includeMoreAction = false, editorsChoiceReview, reviewSummary, shelfMetrics) {
    return validation.context("createProductReviewsList", () => {
        const productReviews = [];
        if (serverData.isDefinedNonNullNonEmpty(reviewSummary) && objectGraph.client.isiOS) {
            if (isSome(shelfMetrics)) {
                const shelfMetricsOptions = {
                    id: `${shelfMetrics.getSequenceId()}`,
                    kind: null,
                    softwareType: null,
                    targetType: "reviewSummary",
                    title: objectGraph.loc.string("ProductPage.ReviewSummary.Body.Title"),
                    pageInformation: shelfMetrics.metricsPageInformation,
                    locationTracker: shelfMetrics.locationTracker,
                    idType: "sequential",
                };
                metricsHelpersLocation.pushContentLocation(objectGraph, {
                    pageInformation: shelfMetrics.metricsPageInformation,
                    locationTracker: shelfMetrics.locationTracker,
                    targetType: "reviewSummary",
                    id: `${shelfMetrics.getSequenceId()}`,
                    idType: "sequential",
                }, objectGraph.loc.string("ProductPage.ReviewSummary.Body.Title"));
                metricsHelpersImpressions.addImpressionFields(objectGraph, reviewSummary, shelfMetricsOptions);
                metricsHelpersLocation.popLocation(shelfMetrics.locationTracker);
                metricsHelpersLocation.nextPosition(shelfMetrics.locationTracker);
            }
            productReviews.push(reviewSummary);
        }
        if (serverData.isDefinedNonNullNonEmpty(editorsChoiceReview) && !objectGraph.client.isiOS) {
            productReviews.push(editorsChoiceReview);
        }
        if (serverData.isDefinedNonNull(reviewItems) && reviewItems.length > 0) {
            const isWatchStore = objectGraph.client.isWatch;
            // We omit the actions on watchOS, they aren't used.
            const includeActions = !isWatchStore;
            // We limit the number of reviews to one on watchOS. That's all
            // we can display inline, and we want to reduce memory usage.
            const fixedUpReviewItems = isWatchStore ? reviewItems.slice(0, 1) : reviewItems;
            const includeFeedbackActions = objectGraph.client.isVision;
            const userReviews = createReviewItems(objectGraph, objectGraph.client.guid, ratingsData, fixedUpReviewItems, includeMoreAction && includeActions, includeFeedbackActions && includeActions, includeActions, shelfMetrics);
            if (isSome(shelfMetrics)) {
                metricsHelpersLocation.pushContentLocation(objectGraph, {
                    pageInformation: shelfMetrics.metricsPageInformation,
                    locationTracker: shelfMetrics.locationTracker,
                    targetType: "mostHelpfulReviews",
                    id: `${shelfMetrics.getSequenceId()}`,
                    idType: "sequential",
                }, null);
            }
            userReviews.forEach((userReview, index) => {
                const productReview = new models.ProductReview();
                productReview.sourceType = "user";
                productReview.review = userReview;
                productReviews.push(productReview);
                if (isSome(shelfMetrics)) {
                    const options = {
                        id: productReview.id,
                        idType: "its_id",
                        kind: null,
                        softwareType: null,
                        title: null,
                        pageInformation: shelfMetrics.metricsPageInformation,
                        locationTracker: shelfMetrics.locationTracker,
                        targetType: "helpfulReview",
                    };
                    metricsHelpersImpressions.addImpressionFields(objectGraph, productReview, options);
                    metricsHelpersLocation.nextPosition(shelfMetrics.locationTracker);
                }
            });
            if (isSome(shelfMetrics)) {
                metricsHelpersLocation.popLocation(shelfMetrics.locationTracker);
                metricsHelpersLocation.nextPosition(shelfMetrics.locationTracker);
            }
        }
        return productReviews;
    });
}
export function createEditorsChoiceReview(objectGraph, data) {
    return validation.context("editorsChoiceItem", () => {
        if (objectGraph.client.isiOS) {
            // On iOS, Editors' Choice is a separate shelf to reviews. On all other platforms, editors choice is embedded in the reviews list.
            return null;
        }
        const editorsChoice = createEditorsChoiceModel(objectGraph, data);
        if (isSome(editorsChoice)) {
            const productReview = new models.ProductReview();
            productReview.sourceType = "editorsChoice";
            productReview.review = editorsChoice;
            if (objectGraph.client.isVision) {
                productReview.review.clickAction = createEditorsChoiceDetailActionForEditorsChoice(objectGraph, productReview.review);
            }
            return productReview;
        }
        return null;
    });
}
/**
 * Creates a flow action for navigating to the expanded view of an editors choice item.
 *
 * @param objectGraph The current object graph
 * @param editorsChoice The editors choice item
 * @returns A flow action
 */
function createEditorsChoiceDetailActionForEditorsChoice(objectGraph, editorsChoice) {
    const flowAction = new models.FlowAction("editorsChoiceDetail");
    flowAction.pageData = objects.shallowCopyOf(editorsChoice);
    return flowAction;
}
/**
 * Converts an array of user review rows into an array of review objects.
 * @param deviceId  The UUID for the user's device.
 * @param rows  User review rows from an API response.
 * @returns An array of zero or more review objects.
 */
export function createReviewItems(objectGraph, deviceId, ratingsData, reviewItems, includeMoreAction = false, includeFeedbackActions = false, includeFlowPreviewActionsConfiguration = true, shelfMetrics) {
    return validation.context("createReviewItems", () => {
        const reviewDateString = function (date, isEdited) {
            if (isEdited) {
                const now = new Date();
                const withinAnHour = (now.getTime() - date.getTime()) * 1000 < 60 * 60;
                if (withinAnHour) {
                    return objectGraph.loc.string("TimeAgo.Edited.JustNow");
                }
                else {
                    return objectGraph.loc
                        .string("TimeAgo.Edited.Time")
                        .replace("{time}", objectGraph.loc.timeAgoWithContext(date, "standalone"));
                }
            }
            else {
                return objectGraph.loc.timeAgoWithContext(date, "standalone");
            }
        };
        return reviewItems.map((item) => {
            var _a;
            const review = new models.Review();
            review.id = serverData.asString(item, "id", "coercible");
            review.title = mediaAttributes.attributeAsString(item, "title");
            const rawDate = mediaAttributes.attributeAsString(item, "date");
            if (rawDate) {
                review.date = new Date(rawDate);
                review.dateText = reviewDateString(review.date, mediaAttributes.attributeAsBooleanOrFalse(item, "isEdited"));
            }
            review.contents = mediaAttributes.attributeAsString(item, "review");
            review.rating = mediaAttributes.attributeAsNumber(item, "rating");
            review.reviewerName = mediaAttributes.attributeAsString(item, "userName");
            review.dateAuthorText = objectGraph.loc
                .string("ProductPage.Section.Reviews.DateAuthor")
                .replace("{date}", review.dateText)
                .replace("{author}", review.reviewerName);
            let responseToReviewText = null;
            const responseId = mediaAttributes.attributeAsString(item, "developerResponse.id");
            if ((responseId === null || responseId === void 0 ? void 0 : responseId.length) > 0) {
                const response = new models.Response();
                response.id = responseId;
                response.contents = mediaAttributes.attributeAsString(item, "developerResponse.body");
                const rawResponseDate = mediaAttributes.attributeAsString(item, "developerResponse.modified");
                if (rawResponseDate) {
                    response.date = new Date(rawResponseDate);
                    response.dateText = reviewDateString(response.date, false);
                }
                review.response = response;
                responseToReviewText = review.response.contents;
            }
            if (includeFlowPreviewActionsConfiguration) {
                const adamId = serverData.asString(ratingsData, "adamId");
                review.flowPreviewActionsConfiguration = flowPreview.flowPreviewActionsConfigurationForReviewFromData(objectGraph, item, deviceId, adamId, responseToReviewText);
            }
            if (includeFeedbackActions) {
                const voteActions = [
                    flowPreview.voteActionFromData(objectGraph, item, deviceId, true),
                    flowPreview.voteActionFromData(objectGraph, item, deviceId, false),
                ];
                if (((_a = objectGraph.bag.reportConcernUrl) === null || _a === void 0 ? void 0 : _a.length) > 0) {
                    voteActions.push(flowPreview.reportConcernActionFromData(objectGraph, item, deviceId));
                }
                review.voteActions = voteActions;
            }
            if (includeMoreAction) {
                if (objectGraph.client.isVision) {
                    review.moreAction = createReviewDetailActionForReview(objectGraph, review);
                    // Clear out the voteActions, as we only need them in the copy of the review
                    // attached to the `moreAction`.
                    review.voteActions = null;
                }
                else {
                    review.moreAction = singleReviewPageActionFromReviewItem(objectGraph, deviceId, ratingsData, item, shelfMetrics);
                }
            }
            return review;
        });
    });
}
/**
 * Create a ratings object from the responses of the requests to get product reviews.
 * @param deviceId  The UUID for the user's device.
 * @param ratingsData    The basic review data response.
 * @returns A customer reviews object.
 */
export function ratingsFromApiResponses(objectGraph, deviceId, context, ratingsData) {
    if (!ratingsData) {
        return null;
    }
    return validation.context("ratingsFromApiResponses", () => {
        const ratings = new models.Ratings();
        ratings.productId = serverData.asString(ratingsData, "adamId", "coercible");
        ratings.ratingAverage = serverData.asNumber(ratingsData, "ratingAverage");
        ratings.totalNumberOfRatings = serverData.asNumber(ratingsData, "ratingCount");
        ratings.totalNumberOfReviews = serverData.asNumber(ratingsData, "totalNumberOfReviews");
        ratings.context = context;
        // Translate rating counts for each star level to represent the number of ratings out of `totalNumberOfRatings`.
        const absoluteRatingsCounts = serverData
            .asArrayOrEmpty(ratingsData, "ratingCountList")
            .slice()
            .reverse();
        const totalAbsoluteRatingsCounts = absoluteRatingsCounts.reduce((a, b) => a + b, 0);
        if (totalAbsoluteRatingsCounts > 0) {
            ratings.ratingCounts = absoluteRatingsCounts.map((absoluteCount) => (absoluteCount / totalAbsoluteRatingsCounts) * ratings.totalNumberOfRatings);
        }
        else {
            ratings.ratingCounts = absoluteRatingsCounts;
        }
        const hasRatings = ratings.ratingAverage > 0 && ratings.ratingCounts;
        if (!hasRatings) {
            const wasReset = serverData.asBooleanOrFalse(ratingsData, "wasReset");
            ratings.status = wasReset
                ? objectGraph.loc.string("RATINGS_STATUS_DEVELOPER_RESET")
                : objectGraph.loc.string("RATINGS_STATUS_NOT_ENOUGH_RATINGS");
        }
        return ratings;
    });
}
export function createReviewSummaryProductReview(objectGraph, data, shelfMetrics) {
    return validation.context("createReviewSummaryProductReview", () => {
        const reviewSummary = reviewSummaryFromData(objectGraph, data, shelfMetrics);
        if (isNothing(reviewSummary)) {
            return null;
        }
        const reviewSummaryProductReview = new models.ProductReview();
        reviewSummaryProductReview.review = reviewSummary;
        reviewSummaryProductReview.sourceType = "reviewSummary";
        return reviewSummaryProductReview;
    });
}
/**
 * Create a review summary object from the product page data
 * @param data Product page data
 * @param objectGraph Current object graph
 * @returns The review summary object
 */
export function reviewSummaryFromData(objectGraph, data, shelfMetrics) {
    if (!isReviewSummaryEnabled(objectGraph)) {
        return null;
    }
    const reviewSummaryRelationship = mediaRelationship.relationship(data, "review-summary");
    if (isNothing(reviewSummaryRelationship)) {
        return null;
    }
    const reviewSummaryDataArray = reviewSummaryRelationship.data;
    if (serverData.isNullOrEmpty(reviewSummaryDataArray)) {
        return null;
    }
    const reviewSummaryData = reviewSummaryDataArray[0];
    const reviewSummaryId = serverData.asString(reviewSummaryData, "id", "coercible");
    const reviewSummaryBodyWithTitle = createReviewSummaryBody(objectGraph, reviewSummaryData, true);
    const reviewSummaryBodyNoTitle = createReviewSummaryBody(objectGraph, reviewSummaryData, false);
    const subtitle = objectGraph.loc.string("ProductPage.ReviewSummary.Subtitle");
    const reviewSummaryReportConcernData = objectGraph.bag.reviewSummaryReportConcernData;
    if (isNothing(reviewSummaryBodyNoTitle) || isNothing(reviewSummaryBodyWithTitle)) {
        return null;
    }
    const appName = mediaAttributes.attributeAsString(data, "name");
    const reviewSummaryText = contentAttributes.contentAttributeAsString(objectGraph, reviewSummaryData, "text");
    const reviewSummaryArtwork = artworkBuilder.createArtworkForResource(objectGraph, "systemimage://text.line.2.summary");
    const reviewSummary = new models.ReviewSummary(reviewSummaryBodyWithTitle, reviewSummaryBodyNoTitle, subtitle, reviewSummaryArtwork, "leading", "text/markdown", flowPreviewActionsConfigurationForReviewSummaryFromData(objectGraph, reviewSummaryReportConcernData, data.id, appName, reviewSummaryId, reviewSummaryText, objectGraph.client.guid));
    // Add metrics before serializing token for url
    const shelfMetricsOptions = {
        id: `${shelfMetrics.getSequenceId()}`,
        kind: null,
        softwareType: null,
        targetType: "reviewSummary",
        title: objectGraph.loc.string("ProductPage.ReviewSummary.Body.Title"),
        pageInformation: shelfMetrics.metricsPageInformation,
        locationTracker: shelfMetrics.locationTracker,
        idType: "sequential",
    };
    metricsHelpersLocation.pushContentLocation(objectGraph, {
        pageInformation: shelfMetrics.metricsPageInformation,
        locationTracker: shelfMetrics.locationTracker,
        targetType: "reviewSummary",
        id: `${shelfMetrics.getSequenceId()}`,
        idType: "sequential",
    }, reviewSummary.title);
    metricsHelpersImpressions.addImpressionFields(objectGraph, reviewSummary, shelfMetricsOptions);
    metricsHelpersLocation.popLocation(shelfMetrics.locationTracker);
    metricsHelpersLocation.nextPosition(shelfMetrics.locationTracker);
    return reviewSummary;
}
/**
 * Checks if the review summary module should be enabled
 * @param objectGraph
 * @returns true if the feature flag and bag key are enabled and the platform is iOS
 */
export function isReviewSummaryEnabled(objectGraph) {
    return objectGraph.client.isiOS && objectGraph.bag.enableReviewSummarization;
}
/**
 * Builds the review summary text using the review summary text
 * @param objectGraph The current object graph
 * @param reviewSummaryData The review summary content attributes
 * @returns The built review summary body text
 */
function createReviewSummaryBody(objectGraph, reviewSummaryData, withTitle) {
    const reviewSummaryText = contentAttributes.contentAttributeAsString(objectGraph, reviewSummaryData, "text");
    if (isNothing(reviewSummaryText)) {
        return null;
    }
    const reviewSummaryTitle = objectGraph.loc.string("ProductPage.ReviewSummary.Body.Title");
    const reviewSummaryTitleStyled = `^[${reviewSummaryTitle}](jetFont: 'reviewSummaryTitle')`;
    const reviewSummaryTextStyled = `^[${reviewSummaryText}](jetFont: 'reviewSummaryText')`;
    if (!withTitle) {
        return reviewSummaryTextStyled;
    }
    const reviewSummaryBody = objectGraph.loc
        .string("ProductPage.ReviewSummary.Body")
        .replace("{styledTitle}", reviewSummaryTitleStyled)
        .replace("{reviewSummary}", reviewSummaryTextStyled);
    return reviewSummaryBody;
}
export function starRatingsFromRatings(ratings) {
    if (!ratings) {
        return null;
    }
    const starRatings = new models.ProductStarRatings();
    copyRatingsInfoIntoOther(ratings, starRatings);
    return starRatings;
}
export function starRatingsHistogramFromRatings(ratings) {
    if (!ratings) {
        return null;
    }
    const starRatings = new models.ProductStarRatingsHistogram();
    copyRatingsInfoIntoOther(ratings, starRatings);
    return starRatings;
}
export function noRatingsFromRatings(ratings) {
    if (!ratings) {
        return null;
    }
    const noRatings = new models.ProductNoRatings();
    copyRatingsInfoIntoOther(ratings, noRatings);
    return noRatings;
}
function copyRatingsInfoIntoOther(original, other) {
    other.ratingAverage = original.ratingAverage;
    other.ratingCounts = original.ratingCounts;
    other.totalNumberOfRatings = original.totalNumberOfRatings;
    other.totalNumberOfReviews = original.totalNumberOfReviews;
    other.status = original.status;
    other.reviews = original.reviews;
    other.actions = original.actions;
    other.nextPage = original.nextPage;
}
/**
 * Create a tap to rate model from the lookup response
 * @param adamId The adamId of the app.
 * @param appName The name of the app.
 * @param isBundle Whether this is a bundle adamId
 * @param rating The current rating
 * @returns A single tap to rate model object
 */
export function tapToRateWithAdamId(objectGraph, adamId, isBundle, appName = null, rating = null) {
    const tapToRate = new models.TapToRate();
    switch (objectGraph.client.deviceType) {
        case "tv":
            tapToRate.title = objectGraph.loc.string("TV_SELECT_TO_RATE");
            break;
        case "mac":
            tapToRate.title = objectGraph.loc.string("CLICK_TO_RATE");
            break;
        default:
            tapToRate.title = objectGraph.client.isiOS
                ? objectGraph.loc.string("TAP_TO_RATE")
                : objectGraph.loc.string("TAP_TO_RATE_LEGACY");
            break;
    }
    tapToRate.rating = rating;
    tapToRate.rateAction = userRateAction(objectGraph, adamId, isBundle, appName);
    return tapToRate;
}
/**
 * Creates a platform-specific action to write a review.
 * @param adamId The app's identifier.
 * @param isBundle Whether this is a bundle adamId
 * @param appIcon The app's icon.
 * @param isRated Whether the app has an existing rating
 * @returns Action to show the write a review sheet.
 */
export function createWriteReviewAction(objectGraph, adamId, isBundle, appIcon, isRated = false, lockupSubtitle, lockupTitle) {
    return validation.context("createWriteReviewAction", () => {
        const title = isRated ? objectGraph.loc.string("EDIT_REVIEW") : objectGraph.loc.string("WRITE_A_REVIEW");
        const writeReviewUrl = assembleWriteReviewURL(objectGraph, adamId, isBundle);
        let appIconWithCrop;
        if (isSome(appIcon)) {
            // The artwork template is ultimately passed to AMS, and doesn't go through our pipeline,
            // so we need to ensure the crop code and file type is already populated.
            const variant = artworkBuilder.createArtworkVariantForClient(objectGraph, true, false, 1 /* ArtworkUseCase.LockupIconSmall */);
            const template = appIcon.template
                .replace("{c}", `${appIcon.crop}-${variant.quality}`)
                .replace("{f}", variant.format);
            appIconWithCrop = new models.Artwork(template, appIcon.width, appIcon.height, appIcon.variants);
            appIconWithCrop.backgroundColor = appIcon.backgroundColor;
            appIconWithCrop.textColor = appIcon.textColor;
            appIconWithCrop.checksum = appIcon.checksum;
            appIconWithCrop.style = appIcon.style;
            appIconWithCrop.crop = appIcon.crop;
            appIconWithCrop.contentMode = appIcon.contentMode;
            appIconWithCrop.imageScale = appIcon.imageScale;
        }
        let writeReviewAction;
        switch (objectGraph.client.deviceType) {
            case "mac": {
                const action = new models.WriteReviewAction(adamId, writeReviewUrl);
                action.title = title;
                action.appIcon = appIconWithCrop;
                action.itemDescription = lockupSubtitle;
                action.appName = lockupTitle;
                writeReviewAction = action;
                break;
            }
            default: {
                if (objectGraph.featureFlags.isEnabled("review_composer_redesign")) {
                    const action = new models.WriteReviewAction(adamId, writeReviewUrl);
                    action.title = title;
                    action.appName = lockupTitle;
                    action.itemDescription = lockupSubtitle;
                    action.appIcon = appIconWithCrop;
                    action.artwork = artworkBuilder.createArtworkForResource(objectGraph, "systemimage://square.and.pencil");
                    writeReviewAction = action;
                    break;
                }
                else {
                    const action = new models.FlowAction("writeReview");
                    action.title = title;
                    action.pageUrl = writeReviewUrl;
                    action.pageData = adamId;
                    action.presentationContext = "presentModal";
                    action.artwork = artworkBuilder.createArtworkForResource(objectGraph, "systemimage://square.and.pencil");
                    writeReviewAction = action;
                    break;
                }
            }
        }
        return writeReviewAction;
    });
}
/**
 * Creates and returns an action for writing a product review
 * @param data  The response data to read from.
 * @returns An action or null
 */
export function writeReviewActionFromData(objectGraph, data, lockupSubtitle, lockupTitle, appIcon) {
    return validation.context(`writeReviewActionFromData`, () => {
        const adamId = data.id;
        if ((adamId === null || adamId === void 0 ? void 0 : adamId.length) > 0) {
            const isBundle = data.type === "app-bundles";
            const rating = mediaAttributes.attributeAsNumber(data, "rating");
            const isRated = serverData.isDefinedNonNull(rating) && rating > 0;
            return createWriteReviewAction(objectGraph, adamId, isBundle, appIcon, isRated, lockupSubtitle, lockupTitle);
        }
        return null;
    });
}
/**
 * Creates and returns an action for navigating to a product's ratings & reviews
 * @param clickAction  The flow action for viewing the product
 * @returns An action or null
 */
export function seeRatingsAndReviewsActionFromClickAction(objectGraph, adamId, clickAction) {
    return validation.context(`seeRatingsAndReviewsActionFromData`, () => {
        const flowAction = objects.shallowCopyOf(clickAction);
        if (clickAction.pageData instanceof models.ProductPage ||
            clickAction.pageData instanceof models.ShelfBasedProductPage) {
            let shelfBasedPageScrollAction;
            if (objectGraph.client.isVision) {
                shelfBasedPageScrollAction = new models.ShelfBasedPageScrollAction("productRatings", "notPurchasedRatingsAndReviews", "purchasedRatingsAndReviews", adamId);
            }
            else {
                shelfBasedPageScrollAction = new models.ShelfBasedPageScrollAction("productRatings");
            }
            const scrollAction = productPageUtil.isShelfBased(objectGraph)
                ? shelfBasedPageScrollAction
                : new models.ProductPageScrollAction(new models.ProductPageSection("shelf", "reviews"));
            const productPageData = objects.shallowCopyOf(clickAction.pageData);
            productPageData.fullProductFetchedAction = scrollAction;
            flowAction.pageData = productPageData;
        }
        return flowAction;
    });
}
/**
 * Create a custom shelf for the reviews module
 * @param deviceId  The UUID for the user's device.
 * @param reviewData The basic review data response.
 * @param rows The review row data response.
 * @returns A custom shelf with one ratings module
 */
export function reviewsShelfForReviewsData(objectGraph, deviceId, ratingsData, reviewItems, includeMoreAction = false, includeFeedbackActions = false, includeFlowPreviewActionsConfiguration = true, shelfMetrics) {
    return validation.context("reviewsShelfForReviewsData", () => {
        if (objectGraph.client.isiOS) {
            const shelf = new models.Shelf("productReview");
            shelfMetrics === null || shelfMetrics === void 0 ? void 0 : shelfMetrics.addImpressionsToShelf(objectGraph, shelf, "ratingsDetails");
            shelf.items = createProductReviewsList(objectGraph, ratingsData, reviewItems, includeMoreAction, null, null, shelfMetrics);
            return shelf;
        }
        else {
            const shelf = new models.Shelf("reviews");
            shelfMetrics === null || shelfMetrics === void 0 ? void 0 : shelfMetrics.addImpressionsToShelf(objectGraph, shelf, "ratingsDetails");
            shelf.items = createReviewItems(objectGraph, deviceId, ratingsData, reviewItems, includeMoreAction, includeFeedbackActions, includeFlowPreviewActionsConfiguration, shelfMetrics);
            return shelf;
        }
    });
}
/**
 * Create a reviews container shelf. Optionally pass in reviews to horizontally scroll them.
 */
export function reviewsContainerShelfForReviewsData(objectGraph, deviceId, ratingsData, reviewItems, appName, productData, appIcon, editorsChoice, shelfMetrics, nextPageHref, includeSeeAllAction = false, shouldIncludePersonalizationUrl = true, rating = null, tvOnlyApp = false) {
    return validation.context("reviewsContainerShelfForReviewsData", () => {
        const reviewsContainer = reviewsContainerForReviewsData(objectGraph, deviceId, ratingsData, reviewItems, productData, appName, appIcon, editorsChoice, shelfMetrics, rating, tvOnlyApp);
        const shelf = new models.Shelf("reviewsContainer");
        shelf.title = sectionTitleForPlatform(objectGraph);
        shelf.items = [reviewsContainer];
        shelfMetrics === null || shelfMetrics === void 0 ? void 0 : shelfMetrics.addImpressionsToShelf(objectGraph, shelf, "ratingsDetails");
        if (includeSeeAllAction &&
            serverData.isDefinedNonNull(reviewsContainer.reviews) &&
            reviewsContainer.reviews.length > 0) {
            shelf.seeAllAction = reviewsPageActionFromReviewsData(objectGraph, deviceId, ratingsData, reviewItems, nextPageHref, appName, appIcon, false, false);
        }
        return shelf;
    });
}
/**
 * Create a personalized reviews container shelf
 */
export function personalizedReviewsContainerShelf(objectGraph, deviceId, token, dataContainer) {
    return validation.context("personalizedReviewsContainerShelf", () => {
        const data = mediaDataStructure.dataFromDataContainer(objectGraph, dataContainer);
        const rating = mediaAttributes.attributeAsNumber(data, "rating");
        return reviewsContainerShelfForReviewsData(objectGraph, deviceId, token.ratingsData, token.reviewItems, token.appName, data, token.appIcon, token.editorsChoice, token.shelfMetrics, token.nextPageHref, token.includeSeeAllAction, false, rating);
    });
}
/**
 * Create a reviews container
 */
export function reviewsContainerForReviewsData(objectGraph, deviceId, ratingsData, reviewItems, productData, appName, appIcon, editorsChoice, shelfMetrics, rating = null, tvOnlyApp = false) {
    return validation.context("reviewsContainerForReviewsData", () => {
        const reviewsContainer = new models.ReviewsContainer();
        const adamId = serverData.asString(ratingsData, "adamId");
        const isBundle = serverData.asBooleanOrFalse(ratingsData, "isBundle");
        reviewsContainer.adamId = adamId;
        // Ratings
        reviewsContainer.ratings = ratingsFromApiResponses(objectGraph, deviceId, "details", ratingsData);
        if (objectGraph.client.isiOS) {
            const reviewSummary = reviewSummaryFromData(objectGraph, productData, shelfMetrics);
            if (serverData.isDefinedNonNull(reviewSummary)) {
                reviewsContainer.reviewSummary = reviewSummary;
            }
        }
        // Tap to Rate
        if (!tvOnlyApp || objectGraph.client.isTV) {
            reviewsContainer.tapToRate = tapToRateWithAdamId(objectGraph, adamId, isBundle, appName, rating);
        }
        if (objectGraph.client.isWeb) {
            const productPageIntent = makeProductPageIntent({
                ...getLocale(objectGraph),
                ...getPlatform(objectGraph),
                id: unwrapOptional(adamId),
            });
            const productAction = actionFor(productPageIntent, objectGraph);
            productAction.title = appName;
            reviewsContainer.productAction = productAction;
        }
        // Reviews
        if (serverData.isDefinedNonNull(reviewItems) && reviewItems.length > 0) {
            const isWatchStore = objectGraph.client.isWatch;
            // We omit the actions on watchOS, they aren't used.
            const includeActions = !isWatchStore;
            // We limit the number of reviews to one on watchOS. That's all
            // we can display inline, and we want to reduce memory usage.
            const fixedUpReviewItems = isWatchStore ? reviewItems.slice(0, 1) : reviewItems;
            reviewsContainer.reviews = createReviewItems(objectGraph, deviceId, ratingsData, fixedUpReviewItems, includeActions, false, includeActions, shelfMetrics);
        }
        // No reviews affects ratings message
        if (serverData.isNull(reviewsContainer.reviews) || reviewsContainer.reviews.length === 0) {
            const hasRatings = reviewsContainer.ratings.ratingAverage > 0 && reviewsContainer.ratings.ratingCounts;
            const wasReset = serverData.asBooleanOrFalse(ratingsData, "wasReset");
            if (!hasRatings && !wasReset) {
                reviewsContainer.ratings.status = objectGraph.loc.string("RATINGS_STATUS_NOT_ENOUGH_RATINGS_OR_REVIEWS");
            }
        }
        // Editors choice
        if (!serverData.isNull(editorsChoice)) {
            reviewsContainer.editorsChoice = editorsChoice;
        }
        // Write a review action
        if (!tvOnlyApp || objectGraph.client.isTV) {
            const isRated = serverData.isDefinedNonNull(rating) && rating > 0;
            reviewsContainer.writeReviewAction = createWriteReviewAction(objectGraph, adamId, isBundle, appIcon, isRated, subtitleFromData(objectGraph, productData), appName);
        }
        // Support action
        const supportUrl = serverData.asString(ratingsData, "supportUrl");
        if (supportUrl) {
            const supportAction = new models.ExternalUrlAction(supportUrl, false);
            supportAction.title = objectGraph.loc.string("APP_SUPPORT");
            reviewsContainer.supportAction = supportAction;
        }
        let alwaysAllowReviews = false;
        for (const item of reviewItems) {
            if (shouldAllowReviewsForSADApp(objectGraph, item)) {
                alwaysAllowReviews = true;
                break;
            }
        }
        reviewsContainer.alwaysAllowReviews = alwaysAllowReviews;
        return reviewsContainer;
    });
}
function createSortOption(objectGraph, adamId, sortId, title, sortActionTitle, sortedReviewsPageToken = null) {
    const url = sortedReviewsPageUrl(objectGraph, adamId, sortId, sortedReviewsPageToken);
    return new models.ReviewsPageSortOption(sortId, title, sortActionTitle, url);
}
/**
 * Create and return the learn more action on the Review Summary context menu
 * @param objectGraph
 * @returns a flow action for the learn more article page for review summary generation
 */
export function reviewSummaryLearnMoreAction(objectGraph) {
    const editorialItemId = objectGraph.bag.reviewSummarizationLearnMoreEditorialItemId;
    if (serverData.isNullOrEmpty(editorialItemId)) {
        return null;
    }
    const title = objectGraph.loc.string("Action.LearnMore");
    const flowAction = new models.FlowAction("article");
    flowAction.title = title;
    flowAction.pageUrl = `https://apps.apple.com/story/id${editorialItemId}`;
    flowAction.artwork = artworkBuilder.createArtworkForResource(objectGraph, "systemimage://questionmark.circle");
    return flowAction;
}
/**
 * Create a reviews page
 * @param deviceId  The UUID for the user's device.
 * @param ratingsData The basic ratings response.
 * @param reviewItems Reviews row data.
 * @param isFirstPage Whether this is the first page.
 * @param nextPageHref the Media API href for next page.
 * @param appName The name of the app.
 * @param appAdamId The adamId of the app.
 * @param appIcon The app icon to use.
 * @param sortId The sort identifier for this page.
 * @param productData Product data for the app
 * @returns A page object to be presented using a FlowAction
 */
function reviewsPageForReviewsData(objectGraph, deviceId, ratingsData, reviewItems, isFirstPage, nextPageHref = null, appAdamId = null, appName, appIcon = null, productData, shelfMetrics, includeMoreAction = false, includeFeedbackActions = false, sortId = sortIdDefault, sortedReviewsPageToken = null) {
    const page = new models.ReviewsPage();
    page.shelves = [];
    return validation.context("reviewsPageForReviewsData", () => {
        const adamId = serverData.isNull(appAdamId) ? serverData.asString(ratingsData, "adamId") : appAdamId;
        if (isFirstPage &&
            !serverData.isNull(ratingsData) &&
            !objectGraph.client.isiOS &&
            !objectGraph.client.isVision) {
            // Reviews container shelf
            const containerShelf = reviewsContainerShelfForReviewsData(objectGraph, deviceId, ratingsData, [], appName, productData, appIcon, null, shelfMetrics);
            page.trailingNavBarAction = reviewSummaryLearnMoreAction(objectGraph);
            page.shelves.push(containerShelf);
        }
        // Ratings & review actions
        if (isFirstPage && objectGraph.client.isVision && serverData.isDefinedNonNull(productData)) {
            const appPlatforms = supportedAppPlatformsFromData(objectGraph, productData);
            const tvOnlyApp = appPlatforms.length === 1 && appPlatforms[0] === "tv";
            const isBundle = productData.type === "app-bundles";
            page.ratings = ratingsFromApiResponses(objectGraph, deviceId, "details", ratingsData);
            page.productReviewActions = createProductReviewActions(objectGraph, productData, appName, ratingsData, isBundle, tvOnlyApp, appIcon);
        }
        const pageComponents = createReviewsPageComponents(objectGraph, deviceId, adamId, ratingsData, reviewItems, nextPageHref, includeMoreAction, includeFeedbackActions, sortId, sortedReviewsPageToken, shelfMetrics);
        pageComponents.reviewsShelf.presentationHints = {
            ...pageComponents.reviewsShelf.presentationHints,
            isSortable: isFirstPage && pageComponents.reviewsShelf.presentationHints.isSortable,
        };
        page.adamId = adamId;
        page.shelves.push(pageComponents.reviewsShelf);
        page.nextPage = pageComponents.paginationToken;
        page.initialSortOptionIdentifier = pageComponents.initialSortId;
        page.sortActionSheetTitle = pageComponents.sortActionSheetTitle;
        page.sortOptions = pageComponents.sorts;
        page.alwaysAllowReviews = shouldAllowReviewsForSADApp(objectGraph, productData);
        return page;
    });
}
/// THe id used to concat the sort optin if there is one
const baseReviewsShelfId = "ReviewsPage.ShelfId";
/// Create the known shelfId for the shelf that includes the reviews
export function reviewsShelfIdForSortId(sortOptionId) {
    if (serverData.isNullOrEmpty(sortOptionId)) {
        return baseReviewsShelfId;
    }
    return `${baseReviewsShelfId}.${sortOptionId}`;
}
/**
 * @param objectGraph The dependency graph for the app.
 * @param deviceId The id used when submitting reviews.
 * @param ratingsData The ratings data for this app.
 * @param reviewItems The actual reivews data
 * @param nextPageHref The url to fetch more reviews.
 * @param includeMoreAction Whether to include the more action on the reviews shelf.
 * @param includeFeedbackActions Whether to include the feedback actions on the reviews shelf.
 * @param sortId The sort identifier for this page.
 * @returns The components needed to create a reviews page.
 */
export function createReviewsPageComponents(objectGraph, deviceId, adamId, ratingsData, reviewItems, nextPageHref = null, includeMoreAction = false, includeFeedbackActions = false, sortId = sortIdDefault, sortedReviewsPageToken = null, shelfMetrics) {
    // Ensure an even number of items are on the page for two column layout paging
    const shouldTruncateShelfItems = (nextPageHref === null || nextPageHref === void 0 ? void 0 : nextPageHref.length) > 0 && serverData.isDefinedNonNullNonEmpty(reviewItems) && reviewItems.length % 2 > 0;
    const itemsForReviewsShelf = shouldTruncateShelfItems ? reviewItems.slice(0, reviewItems.length - 1) : reviewItems;
    const remainingItems = shouldTruncateShelfItems
        ? reviewItems.slice(reviewItems.length - 1)
        : [];
    const reviewsShelf = reviewsShelfForReviewsData(objectGraph, deviceId, ratingsData, itemsForReviewsShelf, includeMoreAction, includeFeedbackActions, true, shelfMetrics);
    reviewsShelf.id = reviewsShelfIdForSortId(sortId);
    const pageComponents = {
        reviewsShelf,
    };
    reviewsShelf.presentationHints = {
        isSortable: reviewItems.length > 0 || (nextPageHref === null || nextPageHref === void 0 ? void 0 : nextPageHref.length) > 0,
        isSeeAllContext: true,
    };
    pageComponents.initialSortId = sortId;
    pageComponents.sortActionSheetTitle = objectGraph.loc.string("REVIEWS_SORT_BY");
    pageComponents.sorts = [
        createSortOption(objectGraph, adamId, "helpful", objectGraph.loc.string("REVIEWS_MOST_HELPFUL"), objectGraph.loc.string(objectGraph.client.isiOS ? "REVIEWS_MOST_HELPFUL" : "REVIEWS_SORT_BY_MOST_HELPFUL"), sortedReviewsPageToken),
        createSortOption(objectGraph, adamId, "favorable", objectGraph.loc.string("REVIEWS_MOST_FAVORABLE"), objectGraph.loc.string(objectGraph.client.isiOS ? "REVIEWS_MOST_FAVORABLE" : "REVIEWS_SORT_BY_MOST_FAVORABLE"), sortedReviewsPageToken),
        createSortOption(objectGraph, adamId, "critical", objectGraph.loc.string("REVIEWS_MOST_CRITICAL"), objectGraph.loc.string(objectGraph.client.isiOS ? "REVIEWS_MOST_CRITICAL" : "REVIEWS_SORT_BY_MOST_CRITICAL"), sortedReviewsPageToken),
        createSortOption(objectGraph, adamId, "recent", objectGraph.loc.string("REVIEWS_MOST_RECENT"), objectGraph.loc.string(objectGraph.client.isiOS ? "REVIEWS_MOST_RECENT" : "REVIEWS_SORT_BY_MOST_RECENT"), sortedReviewsPageToken),
    ];
    if ((nextPageHref === null || nextPageHref === void 0 ? void 0 : nextPageHref.length) > 0) {
        pageComponents.paginationToken = createReviewsPageToken(objectGraph, adamId, nextPageHref, sortId, remainingItems);
    }
    return pageComponents;
}
/**
 * Create a partial reviews page from a reviews media api container
 */
export function partialReviewsPageForReviewsMediaContainer(objectGraph, deviceId, adamId, prependingItems, data, isFirstPage, sortId, sortedReviewsPageToken, shelfMetrics) {
    return validation.context("reviewsPageForReviewsMediaContainer", () => {
        let reviewItems;
        if (serverData.isDefinedNonNullNonEmpty(data.data)) {
            reviewItems = prependingItems.concat(data.data);
        }
        else {
            reviewItems = prependingItems;
        }
        const includeMoreAction = objectGraph.client.isVision;
        const includeFeedbackActions = objectGraph.client.isVision;
        return reviewsPageForReviewsData(objectGraph, deviceId, null, reviewItems, isFirstPage, data.next, adamId, null, null, null, shelfMetrics, includeMoreAction, includeFeedbackActions, sortId, sortedReviewsPageToken);
    });
}
/**
 * Creates a flow action to display a reviews page.
 * @param deviceId  The UUID for the user's device.
 * @param ratingsData The ratings data response
 * @param reviewsData The review row data response.
 * @param nextPageHref The Media API href for the next page.
 * @param appName The name of the app
 * @param appIcon The app's icon.
 * @param productData The data for the product
 
 * @returns A `FlowAction` object pointing to a reviews page.
 */
export function reviewsPageActionFromReviewsData(objectGraph, deviceId, ratingsData, reviewsData, nextPageHref = null, appName = null, appIcon = null, includeMoreAction, includeFeedbackActions, productData, shelfMetrics) {
    if (!ratingsData) {
        return null;
    }
    return validation.context("reviewsPageActionFromReviewsData", () => {
        const pageData = reviewsPageForReviewsData(objectGraph, deviceId, ratingsData, reviewsData, true, nextPageHref, null, appName, appIcon, productData, shelfMetrics, includeMoreAction, includeFeedbackActions);
        pageData.title = pageTitleForPlatform(objectGraph);
        const action = new models.FlowAction("reviews");
        action.pageData = pageData;
        action.title = objectGraph.loc.string("ACTION_SEE_ALL");
        if (objectGraph.client.isWeb) {
            const destination = makeSeeAllPageIntent({
                ...getLocale(objectGraph),
                ...getPlatform(objectGraph),
                "id": pageData.adamId,
                "see-all": "reviews",
            });
            action.destination = destination;
            action.pageUrl = makeSeeAllPageURL(objectGraph, destination);
            const { metricsPageInformation, locationTracker } = shelfMetrics !== null && shelfMetrics !== void 0 ? shelfMetrics : {};
            metricsHelpersClicks.addClickEventToAction(objectGraph, action, {
                id: "SeeAllReviews",
                actionType: "navigate",
                locationTracker: locationTracker,
                pageInformation: metricsPageInformation,
            }, false, "button");
        }
        return action;
    });
}
/**
 * Creates a flow action to display a single reviewreviewsPageUrl
 * @param deviceId  The UUID for the user's device.
 * @param ratingsData The ratings data response
 * @param item The review data from a single row data response.
 * @returns A `FlowAction` object pointing to a reviews page.
 */
function singleReviewPageActionFromReviewItem(objectGraph, deviceId, ratingsData, item, shelfMetrics) {
    if (!item) {
        return null;
    }
    return validation.context("singleReviewActionFromReviewData", () => {
        // Reviews shelf
        const reviewsShelf = reviewsShelfForReviewsData(objectGraph, deviceId, ratingsData, [item], null, null, null, shelfMetrics);
        const page = new models.ReviewsPage();
        page.adamId = serverData.asString(ratingsData, "adamId");
        page.targetReviewId = serverData.asString(item, "id", "coercible");
        page.shelves = [reviewsShelf];
        const action = new models.FlowAction("reviews");
        action.pageData = page;
        action.title = sectionTitleForPlatform(objectGraph);
        return action;
    });
}
export function pageTitleForPlatform(objectGraph) {
    if (objectGraph.client.isWatch) {
        return objectGraph.loc.string("ProductPage.Section.Reviews.Title");
    }
    else {
        return null;
    }
}
export function sectionTitleForPlatform(objectGraph) {
    switch (objectGraph.client.deviceType) {
        case "tv":
            return objectGraph.loc.string("TV_PRODUCT_SECTION_RATINGS");
        case "watch":
            return null;
        default:
            return objectGraph.loc.string("PRODUCT_SECTION_REVIEWS");
    }
}
/**
 * Creates a flow action for navigating to the expanded view of a review.
 *
 * @param objectGraph The current object graph
 * @param review The source review
 * @returns A flow action
 */
function createReviewDetailActionForReview(objectGraph, review) {
    const flowAction = new models.FlowAction("reviewDetail");
    const detailReview = objects.shallowCopyOf(review);
    detailReview.moreAction = null;
    flowAction.pageData = detailReview;
    return flowAction;
}
//# sourceMappingURL=reviews.js.map