import * as models from "../../../api/models";
import * as serverData from "../../../foundation/json-parsing/server-data";
import { isNothing } from "@jet/environment";
import * as mediaAttributes from "../../../foundation/media/attributes";
import * as mediaRelationship from "../../../foundation/media/relationships";
import { shallowCopyOf } from "../../../foundation/util/objects";
import { tryAwait } from "../../../foundation/util/promise-util";
import { withAsyncValidationContext } from "../../../foundation/util/validation-util";
import * as appPromotionsCommon from "../../app-promotions/app-promotions-common";
import * as contentAttributes from "../../content/attributes";
import * as lockups from "../../lockups/lockups";
import * as metricsHelpersLocation from "../../metrics/helpers/location";
import * as productPageCommon from "../product-page-common";
import { ProductPageSectionMapping } from "../shelf-based/product-page-section-mapping";
/**
 * Create a shelf for the in-app purchase items for this product page.
 *
 * @param data The raw data response for a product page JSON fetch.
 * @param shelfMetrics The product page shelf metrics.
 * @param shelfContext A collection of any other variables used when creating this shelf.
 * @returns An in-app purchase shelf.
 */
export async function create(objectGraph, productData, shelfMetrics, shelfContext) {
    return await withAsyncValidationContext("inAppPurchasesShelf", async () => {
        var _a;
        if (!shouldShowIAPShelf(objectGraph, objectGraph.host.platform)) {
            return null;
        }
        if (serverData.isNullOrEmpty(productData)) {
            return null;
        }
        let inAppsContainer;
        if (appPromotionsCommon.appContingentItemsAreEnabled(objectGraph)) {
            inAppsContainer = mediaRelationship.relationshipViewsContainer(productData, "standalone-merchandised-in-apps");
        }
        else {
            inAppsContainer = mediaRelationship.relationship(productData, "merchandised-in-apps");
        }
        if (isNothing(inAppsContainer) || inAppsContainer.data.length === 0) {
            return null;
        }
        // Consider only the In-App Purchase lockups that are appropriate for this type (i.e. subscription or not).
        const merchandisedInApps = inAppsContainer.data.filter(function (inAppData) {
            const isDataForSubscription = mediaAttributes.attributeAsBooleanOrFalse(inAppData, "isSubscription");
            return isDataForSubscription === shelfContext.isForSubscriptions;
        });
        if (merchandisedInApps.length === 0) {
            return null;
        }
        const metricsOptions = {
            pageInformation: shelfMetrics.metricsPageInformation,
            locationTracker: shelfMetrics.locationTracker,
            targetType: "swoosh",
            id: `${shelfMetrics.getSequenceId()}`,
            idType: "sequential",
        };
        const contentType = "inAppPurchaseLockup";
        const shelf = new models.Shelf(contentType);
        // Disable iAP offer button for preorders
        const isPreorder = mediaAttributes.attributeAsBoolean(productData, "isPreorder");
        const offerStyle = isPreorder ? "disabled" : "infer";
        const appBundleId = contentAttributes.contentAttributeAsString(objectGraph, productData, "bundleId");
        const spotlightId = (_a = shelfContext.options) === null || _a === void 0 ? void 0 : _a.spotlightInAppProductIdentifier;
        injectParentIntoInAppsContainer(objectGraph, productData, inAppsContainer);
        const remainingItems = [];
        const contentUnavailable = function (index, dataItem) {
            remainingItems.push(dataItem);
            return false;
        };
        const iapLockups = inAppPurchaseLockupsFromData(objectGraph, inAppsContainer.data, offerStyle, metricsOptions, spotlightId, contentUnavailable).filter(function (item) {
            if (item.productIdentifier === spotlightId) {
                shelfContext.options.spotlightSection = new ProductPageSectionMapping("shelf", shelfContext.isForSubscriptions ? "subscriptions" : "inAppPurchases");
            }
            return item.isSubscription === shelfContext.isForSubscriptions;
        });
        if (iapLockups.length === 0 && remainingItems.length === 0) {
            return null;
        }
        shelf.items = await applyClientOrderingToIAPShelfItems(objectGraph, iapLockups, appBundleId, spotlightId);
        if (serverData.isDefinedNonNullNonEmpty(remainingItems)) {
            const shelfToken = new productPageCommon.ProductPageShelfToken(productData.id, remainingItems, shelf.title, false, undefined, contentType, offerStyle, null);
            shelfToken.appBundleId = appBundleId;
            shelfToken.iapShelfContext = shelfContext;
            if (shelfContext.isForSubscriptions) {
                shelfToken.inAppShelfId = "subscriptions";
            }
            else {
                shelfToken.inAppShelfId = "inAppPurchases";
            }
            shelf.url = productPageCommon.shelfContentUrl(objectGraph, shelfToken, shelfMetrics);
        }
        let targetType;
        if (shelfContext.isForSubscriptions) {
            shelf.title = objectGraph.loc.string("ProductPage.Section.Subscriptions.Title", "Subscriptions");
            targetType = "subscription";
        }
        else {
            shelf.title = objectGraph.loc.string("ProductPage.Section.InAppPurchases.Title");
            targetType = "iAP";
        }
        metricsHelpersLocation.pushContentLocation(objectGraph, metricsOptions, shelf.title);
        metricsHelpersLocation.popLocation(shelfMetrics.locationTracker);
        metricsHelpersLocation.nextPosition(shelfMetrics.locationTracker);
        shelf.isHorizontal = true;
        shelfMetrics.addImpressionsToShelf(objectGraph, shelf, targetType);
        return shelf;
    });
}
/**
 * In-App Purchases have a relationship back to the parent app. However, this specific relationship is not included
 * when the In-App Purchase itself is a relationship on the parent app resource. Therefore, we need to do some work to
 * inject the parent app into each IAP on the IAP relationship. This is the path of least resistance, as it will allow
 * us to keep our core lockup builder lean and consistent across all call sites (after all, on everywhere else except
 * the product page, the parent app will be included in the relationship).
 * @param {Data} productData The data for the parent ap.
 * @param {DataContainer} inAppsContainer The container for the In-App Purchases relationship.
 */
function injectParentIntoInAppsContainer(objectGraph, productData, inAppsContainer) {
    const parentAppRelationshipType = "app";
    for (const data of inAppsContainer.data) {
        let existingParentRelationship = mediaRelationship.relationship(data, parentAppRelationshipType);
        if (!existingParentRelationship) {
            existingParentRelationship = {
                data: [productData],
            };
        }
        if (serverData.isNull(data.relationships)) {
            data.relationships = {};
        }
        data.relationships[parentAppRelationshipType] = existingParentRelationship;
    }
}
function inAppPurchaseLockupsFromData(objectGraph, inAppsData, offerStyle, metricsOptions, spotlightId, contentUnavailable) {
    const lockupOptions = {
        metricsOptions: metricsOptions,
        offerStyle: offerStyle,
        skipDefaultClickAction: true,
        artworkUseCase: 1 /* content.ArtworkUseCase.LockupIconSmall */,
    };
    const options = {
        lockupOptions: lockupOptions,
        contentUnavailable: contentUnavailable,
    };
    const lockupModels = lockups.lockupsFromData(objectGraph, inAppsData, options);
    if (spotlightId) {
        productPageCommon.moveLockupToFront(objectGraph, spotlightId, lockupModels);
    }
    return lockupModels;
}
/**
 * Whether or not IAP shelf should be shown
 */
function shouldShowIAPShelf(objectGraph, platform) {
    if (platform === "macOS" || objectGraph.client.isCompanionVisionApp) {
        return false;
    }
    return true;
}
async function applyClientOrderingToIAPShelfItems(objectGraph, currentItems, appBundleId, spotlightInAppProductIdentifier) {
    if (isNothing(appBundleId)) {
        return currentItems;
    }
    const allInAppIds = [];
    const defaultVisibleInAppIds = [];
    for (const inAppLockup of currentItems) {
        const productIdentifier = inAppLockup.productIdentifier;
        // We must ensure this item is appropriate for the shelf type.
        allInAppIds.push(productIdentifier);
        if (inAppLockup.isVisibleByDefault) {
            defaultVisibleInAppIds.push(productIdentifier);
        }
    }
    // FIXME: <rdar://99419136> ESLint rule disabled temporarily but code should be fixed. If `orderedVisibleIAPs()` is rejected, nothing will happen.
    // eslint-disable-next-line @typescript-eslint/no-floating-promises
    const finalOrderingResult = await tryAwait(objectGraph.clientOrdering.orderedVisibleIAPs(appBundleId, allInAppIds, defaultVisibleInAppIds, spotlightInAppProductIdentifier));
    if (!finalOrderingResult.success) {
        return currentItems;
    }
    return filteredInAppLockupsUsingOrdering(currentItems, finalOrderingResult.value);
}
function filteredInAppLockupsUsingOrdering(iAPLockups, iAPOrdering) {
    // Use a map to avoid nested iteration.
    const identifiersToLockups = {};
    for (const lockup of iAPLockups) {
        identifiersToLockups[lockup.productIdentifier] = lockup;
    }
    // Filter by those present in the ordering.
    const filteredOrderedLockups = [];
    for (const productIdentifier of iAPOrdering) {
        const foundLockup = identifiersToLockups[productIdentifier];
        if (foundLockup) {
            const copy = shallowCopyOf(foundLockup);
            filteredOrderedLockups.push(copy);
        }
    }
    return filteredOrderedLockups;
}
//# sourceMappingURL=in-app-purchases-shelf.js.map