import * as metricsLocation from "./location";
import * as metricsUtil from "./util";
import { isNothing, isSome } from "@jet/environment";
import * as validation from "@jet/environment/json/validation";
import * as models from "../../../api/models";
import * as serverData from "../../../foundation/json-parsing/server-data";
import * as contentAttributes from "../../content/attributes";
import * as content from "../../content/content";
import * as productVariants from "../../product-page/product-page-variants";
import * as lockups from "../../../common/lockups/lockups";
//* *************************
//* Impression Metrics
//* *************************
function generateImpressionFields(objectGraph, options) {
    /// please note this is not the metrics event itself but the fields for the items that impress
    /// there is a very strict spec for these items so please do not modify this unless you know
    /// exactly what you are doing.
    var _a, _b, _c, _d;
    let id = options.id;
    let title = options.title;
    if (serverData.isDefinedNonNullNonEmpty(options.anonymizationOptions)) {
        const anonymizationString = (_b = (_a = options.anonymizationOptions) === null || _a === void 0 ? void 0 : _a.anonymizationString) !== null && _b !== void 0 ? _b : "ANONYMOUS";
        id = anonymizationString;
        title = anonymizationString;
    }
    else if (id && options.createUniqueImpressionId && !objectGraph.client.isWatch) {
        id = createUniqueImpressionId(objectGraph, id);
    }
    const impressionData = {
        id: metricsUtil.emptyStringIfNullOrUndefined(id),
        name: metricsUtil.emptyStringIfNullOrUndefined(title),
        impressionType: metricsUtil.targetTypeForMetricsOptions(objectGraph, options),
    };
    const idType = metricsUtil.idTypeForMetricsOptions(options);
    if (isSome(idType)) {
        impressionData["idType"] = idType;
    }
    if (options && options.kind) {
        impressionData["kind"] = options.kind;
    }
    if (options && options.softwareType) {
        impressionData["softwareType"] = options.softwareType;
    }
    if (options && options.recoMetricsData) {
        Object.assign(impressionData, options.recoMetricsData);
    }
    if (options && options.mercuryMetricsData) {
        Object.assign(impressionData, options.mercuryMetricsData);
    }
    if (options && options.lockupDisplayStyle) {
        impressionData["platformDisplayStyle"] = options.lockupDisplayStyle;
    }
    const shouldOmitImpressionIndex = (_c = options.shouldOmitImpressionIndex) !== null && _c !== void 0 ? _c : false;
    if (options && options.locationTracker && !shouldOmitImpressionIndex) {
        const currentPosition = metricsLocation.currentPosition(options.locationTracker);
        impressionData["impressionIndex"] = currentPosition;
        if (impressionData.id === "") {
            impressionData.id = currentPosition.toString();
            impressionData["idType"] = "sequential";
        }
    }
    if (options && options.modelSource) {
        impressionData["modelSource"] = options.modelSource;
    }
    // Add offerType if available
    if (serverData.isDefinedNonNull(options.offerType)) {
        impressionData["offerType"] = options.offerType;
    }
    // Arcade Upsell Tracking
    if (options && serverData.isDefinedNonNull(options.displaysArcadeUpsell)) {
        impressionData["displaysArcadeUpsell"] = options.displaysArcadeUpsell;
    }
    // Preorder Tracking
    if (options && serverData.isDefinedNonNull(options.isPreorder)) {
        impressionData["isPreorder"] = options.isPreorder;
    }
    // Add adamId if available
    if (serverData.isDefinedNonNull(options.adamId) && serverData.isNullOrEmpty(options.anonymizationOptions)) {
        impressionData["adamId"] = options.adamId;
    }
    // Badges
    if (options && serverData.isDefinedNonNull(options.badges)) {
        impressionData["badges"] = options.badges;
    }
    // In App Event ID
    if (options && serverData.isDefinedNonNull(options.inAppEventId)) {
        impressionData["inAppEventId"] = options.inAppEventId;
    }
    // Related subject IDs
    if (options && serverData.isDefinedNonNull(options.relatedSubjectIds)) {
        impressionData["relatedSubjectIds"] = options.relatedSubjectIds;
    }
    /// Hints entity
    if ((_d = options === null || options === void 0 ? void 0 : options.hintsEntity) === null || _d === void 0 ? void 0 : _d.length) {
        impressionData["hintsEntity"] = options.hintsEntity;
    }
    // autoAdvanceInterval for auto scrolling Views
    if (options && serverData.isDefinedNonNull(options.autoAdvanceInterval)) {
        impressionData["autoAdvanceInterval"] = options.autoAdvanceInterval;
    }
    // Add fcKind if available
    if (serverData.isDefinedNonNull(options === null || options === void 0 ? void 0 : options.fcKind)) {
        impressionData["fcKind"] = options.fcKind;
    }
    if (serverData.isDefinedNonNull(options === null || options === void 0 ? void 0 : options.canonicalId)) {
        impressionData["canonicalId"] = options.canonicalId;
    }
    if (serverData.isDefinedNonNull(options === null || options === void 0 ? void 0 : options.displayStyle)) {
        impressionData["displayStyle"] = options.displayStyle;
    }
    // Add product variant fields if available
    if (serverData.isDefinedNonNull(options.productVariantData)) {
        Object.assign(impressionData, productVariants.contentFieldsForProductVariantData(options.productVariantData));
    }
    if (isSome(options.contentRating)) {
        impressionData["contentRating"] = options.contentRating;
    }
    if (isSome(options.bundleId)) {
        impressionData["bundleId"] = options.bundleId;
    }
    if (impressionData.id === "") {
        objectGraph.console.log(`impressionId missing. Tracking broken for ${impressionData.name} of ${impressionData.impressionType}`);
    }
    return impressionData;
}
export function addImpressionFields(objectGraph, impressionable, options) {
    if (!impressionable) {
        return;
    }
    impressionable.impressionMetrics = new models.ImpressionMetrics(generateImpressionFields(objectGraph, options));
}
export function addImpressionFieldsToTagRoomHeader(objectGraph, impressionable, options) {
    if (!impressionable) {
        return;
    }
    const impressionMetrics = new models.ImpressionMetrics(generateImpressionFields(objectGraph, options));
    delete impressionMetrics.fields.impressionIndex;
    impressionable.impressionMetrics = impressionMetrics;
}
/**
 * Adds impression fields to the search metadata ribbon item.
 *
 * @param objectGraph - The object graph.
 * @param metadataRibbonItem - The metadata ribbon item.
 * @param options - The metrics impression options.
 */
export function addImpressionFieldsToSearchMetadataRibbonItem(objectGraph, metadataRibbonItem, options) {
    var _a;
    if (!metadataRibbonItem) {
        return;
    }
    addImpressionFields(objectGraph, metadataRibbonItem, options);
    if ((options.isAdvert || options.isAdEligible) &&
        ((_a = options.pageInformation) === null || _a === void 0 ? void 0 : _a.iAdInfo) &&
        metadataRibbonItem.impressionMetrics) {
        metadataRibbonItem.impressionMetrics = new models.FastImpressionMetrics(metadataRibbonItem.impressionMetrics, true);
    }
}
/**
 * Add impressions fields to a Today card.
 * @param objectGraph The object graph.
 * @param card The Today card to apply the impressions fields to.
 * @param options A set of metrics options to gather data from.
 * @param franchise The card franchise.
 * @param cardType The card type.
 * @param isOnboardingCard Whether the card is an onboarding card.
 * @param coerceNullToEmptyStrings Whether `null` values for `franchise` and `cardType` should be coerced into empty strings. This
 * was a behaviour that was always enabled by default, but as of the implementation of Chainlink ads, we don't necessarily want empty strings.
 * Defaults to true to maintain legacy behaviour for other cards that don't want to opt out.
 * @returns
 */
export function addImpressionsFieldsToTodayCard(objectGraph, card, options, franchise, cardType, isOnboardingCard, coerceNullToEmptyStrings = true) {
    var _a, _b, _c, _d, _e, _f;
    if (!card) {
        return;
    }
    const impressionData = generateImpressionFields(objectGraph, options);
    if (coerceNullToEmptyStrings) {
        impressionData["franchise"] = metricsUtil.emptyStringIfNullOrUndefined(franchise);
        impressionData["cardType"] = metricsUtil.emptyStringIfNullOrUndefined(cardType);
    }
    else {
        if (franchise) {
            impressionData["franchise"] = franchise;
        }
        if (cardType) {
            impressionData["cardType"] = cardType;
        }
    }
    if (isOnboardingCard) {
        impressionData["isOnboardingCard"] = isOnboardingCard;
    }
    if (((_b = (_a = options === null || options === void 0 ? void 0 : options.optimizationEntityId) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0) {
        impressionData["optimizationEntityId"] = options.optimizationEntityId;
    }
    if (((_d = (_c = options === null || options === void 0 ? void 0 : options.optimizationId) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0) > 0) {
        impressionData["optimizationId"] = options.optimizationId;
    }
    if (isSome(options === null || options === void 0 ? void 0 : options.rowIndex)) {
        impressionData["rowIndex"] = options.rowIndex;
    }
    card.impressionMetrics = new models.ImpressionMetrics(impressionData);
    if ((options.isAdvert || options.isAdEligible) && ((_e = options.pageInformation) === null || _e === void 0 ? void 0 : _e.iAdInfo)) {
        const sanitizedIAdData = metricsUtil.sanitizedMetricsDictionary(options.pageInformation.iAdInfo.fastImpressionsFieldsForCurrentItem(options.locationTracker, options.adSlotOverride));
        Object.assign(card.impressionMetrics.fields, sanitizedIAdData);
        card.impressionMetrics = new models.FastImpressionMetrics(card.impressionMetrics, true);
        if (options.isAdvert) {
            (_f = card.impressionMetrics) === null || _f === void 0 ? true : delete _f.fields["cardType"];
        }
    }
}
export function addImpressionsFieldsToAd(objectGraph, impressionable, options, iAdData) {
    if (!impressionable || !iAdData) {
        return;
    }
    addImpressionFields(objectGraph, impressionable, options);
    const sanitizedIAdData = metricsUtil.sanitizedMetricsDictionary(iAdData.fastImpressionsFieldsForCurrentItem(options.locationTracker, options.adSlotOverride));
    if (isSome(impressionable.impressionMetrics)) {
        Object.assign(impressionable.impressionMetrics.fields, sanitizedIAdData);
        const disableFastImpressions = serverData.asBooleanOrFalse(options.disableFastImpressionsForAds);
        impressionable.impressionMetrics = new models.FastImpressionMetrics(impressionable.impressionMetrics, !disableFastImpressions);
    }
    /**
     * This is an longstanding hack to prevent ad and organic impression showing same content (i.e. AdamId)
     * to properly have nonclashing identifiers, and have separate impression objects.
     * Even with impression item ids' hasing on `impressionIndex` - this is still needed in case the Nth rotated ad is the same as Nth organic.
     * This is orthogonal to "ad_container" in location stack when building ads for ad-rotation, which is a separate metrics trick.
     */
    if (isSome(impressionable.impressionMetrics)) {
        impressionable.impressionMetrics.fields["parentId"] = "ad_container";
    }
}
export function addImpressionFieldsToInAppPurchaseLockup(objectGraph, lockup, options) {
    if (!lockup) {
        return;
    }
    // The code that calls this method currently does this indirectly,
    // this is just to guard against that code changing in the future.
    if (!lockup.impressionMetrics) {
        addImpressionFields(objectGraph, lockup, options);
    }
    if (lockup.parent && lockup.parent.adamId && isSome(lockup.impressionMetrics)) {
        lockup.impressionMetrics.fields["parentAdamId"] = metricsUtil.emptyStringIfNullOrUndefined(lockup.parent.adamId);
    }
}
export function impressionOptionsForLockup(objectGraph, data, lockup, displayStyle, baseOptions, canDisplayArcadeOfferButton, attributePlatformOverride = undefined) {
    var _a;
    const options = impressionOptions(objectGraph, data, lockup.title, baseOptions);
    options.lockupDisplayStyle = displayStyle;
    options.contentRating = (_a = lockup.offerDisplayProperties) === null || _a === void 0 ? void 0 : _a.contentRating;
    options.bundleId = lockup.bundleId;
    // If no targetType is provided, set the correct value for the platform.
    if (serverData.isNullOrEmpty(options.targetType)) {
        options.targetType = objectGraph.client.isVision ? "lockupSmall" : "lockup";
    }
    if (canDisplayArcadeOfferButton && content.isArcadeSupported(objectGraph, data)) {
        options.displaysArcadeUpsell = true;
    }
    // If it has a discounted offer then use the options already set
    const parentID = baseOptions["id"];
    if (serverData.isDefinedNonNullNonEmpty(lockups.discountedOfferFromData(data)) &&
        serverData.isDefinedNonNull(parentID) &&
        parentID.length > 0) {
        options.id = parentID;
    }
    return options;
}
export function impressionOptions(objectGraph, data, title, baseOptions, attributePlatformOverride = undefined) {
    return validation.context("impressionOptions", () => {
        const kind = metricsUtil.metricsKindFromData(objectGraph, data);
        const softwareType = metricsUtil.softwareTypeForData(objectGraph, data);
        const metricsOptions = {
            ...baseOptions,
            kind: kind,
            softwareType: softwareType,
            title: title,
            id: data.id,
        };
        // Include offerType for pre-order impressions
        // NOTE: Even though metricsOptions.isPreorder may be true, we don't key off that here because
        //       offerType implies an offer exists, which is not always true (e.g. an Arcade Coming Soon breakout).
        const containsPreorderOffer = contentAttributes.contentAttributeAsBooleanOrFalse(objectGraph, data, "isPreorder", attributePlatformOverride);
        if (containsPreorderOffer) {
            metricsOptions.offerType = "preorder";
        }
        return metricsOptions;
    });
}
/// Returns impression options for Arcade See All Games ribbon item.
export function impressionOptionsForArcadeSeeAllGamesRibbonItem(baseOptions) {
    return validation.context("impressionOptionsForArcadeSeeAllGamesRibbonItem", () => {
        const metricsOptions = {
            ...baseOptions,
            id: "AllGames",
            idType: "none",
            kind: null,
            softwareType: null,
            title: "All Games",
        };
        return metricsOptions;
    });
}
/// Returns impression options for tag ribbon item on product page.
export function impressionOptionsForTagRibbonItem(objectGraph, data, title, baseOptions) {
    return validation.context("impressionOptions", () => {
        const kind = metricsUtil.metricsKindFromData(objectGraph, data);
        const softwareType = metricsUtil.softwareTypeForData(objectGraph, data);
        const metricsOptions = {
            ...baseOptions,
            kind: kind,
            softwareType: softwareType,
            title: title,
            id: data.id,
            idType: "its_id",
            displayStyle: "textOnly",
        };
        return metricsOptions;
    });
}
/// Returns impression options for tag ribbon item on product page.
export function impressionOptionsForTagHeader(objectGraph, data, title, baseOptions) {
    return validation.context("impressionOptions", () => {
        const kind = metricsUtil.metricsKindFromData(objectGraph, data);
        const softwareType = metricsUtil.softwareTypeForData(objectGraph, data);
        const metricsOptions = {
            ...baseOptions,
            kind: kind,
            softwareType: softwareType,
            title: title,
            id: data.id,
            idType: "its_contentId",
            targetType: "tagHeader",
        };
        return metricsOptions;
    });
}
/// Returns impression options for Arcade Choose Your Favorites brick.
export function impressionOptionsForArcadeChooseYourFavoritesBrick(baseOptions) {
    return validation.context("impressionOptionsForArcadeChooseYourFavoritesBrick", () => {
        const metricsOptions = {
            ...baseOptions,
            id: "",
            kind: null,
            softwareType: null,
            title: "choose_your_games_brick",
        };
        return metricsOptions;
    });
}
export function impressionOptionsForMetadataRibbonItem(baseOptions, id, name, idType) {
    return validation.context("impressionOptionsForMetadataRibbonItem", () => {
        const metricsOptions = {
            ...baseOptions,
            id: id,
            kind: null,
            softwareType: null,
            title: name,
            idType: idType,
            targetType: "tag",
        };
        return metricsOptions;
    });
}
// region Hints Impressions
export function impressionOptionsForSearchHint(objectGraph, hintTerm, baseOptions, searchEntity, hintSource) {
    return validation.context("impressionOptionsForSearchHint", () => {
        const metricsOptions = {
            ...baseOptions,
            id: "",
            kind: null,
            softwareType: null,
            title: hintTerm,
            hintsEntity: searchEntity,
            modelSource: hintSource,
        };
        return metricsOptions;
    });
}
export function addImpressionMetricsToHintsSearchAction(objectGraph, searchAction, metricsOptions) {
    const options = impressionOptionsForSearchHint(objectGraph, searchAction.term, metricsOptions, searchAction.entity, searchAction.source);
    const impressionFields = generateImpressionFields(objectGraph, options);
    searchAction.impressionMetrics = new models.ImpressionMetrics(impressionFields);
}
const uniqueIdDelimiter = "::";
function createUniqueImpressionId(objectGraph, baseId) {
    return `${baseId}${uniqueIdDelimiter}${objectGraph.random.nextUUID()}`;
}
/**
 * Strips the unique impression ID from the event fields if necessary.
 *
 * @param eventFields - The event fields containing impressions.
 */
export function stripUniqueImpressionIdsIfNecessary(eventFields) {
    const impressions = serverData.asArrayOrEmpty(eventFields, "impressions");
    for (const impression of impressions) {
        const impressionId = serverData.asString(impression, "id");
        if (isNothing(impressionId)) {
            continue;
        }
        impression["id"] = stripUniqueImpressionIdIfNecessary(impressionId);
    }
}
/**
 * Strips the unique impression ID from the given impression ID if necessary.
 * If the impression ID contains a unique ID delimiter, it splits the string
 * and returns the part before the delimiter. Otherwise, it returns the original
 * impression ID.
 *
 * @param impressionId - The impression ID to process.
 * @returns The processed impression ID.
 */
function stripUniqueImpressionIdIfNecessary(impressionId) {
    if (impressionId.includes(uniqueIdDelimiter)) {
        return impressionId.split(uniqueIdDelimiter)[0];
    }
    return impressionId;
}
// endregion
//# sourceMappingURL=impressions.js.map