import * as metricsBuilder from "../builder";
import * as metricsConstants from "./constants";
import * as metricsLocation from "./location";
import * as metricsModels from "./models";
import * as metricsUtil from "./util";
import * as metricsMisc from "./misc";
import * as validation from "@jet/environment/json/validation";
import { isNothing, isSome } from "@jet/environment/types/optional";
import * as models from "../../../api/models";
import * as serverData from "../../../foundation/json-parsing/server-data";
import * as mediaAttributes from "../../../foundation/media/attributes";
import * as dateUtil from "../../../foundation/util/date-util";
//* *************************
//* Click Metrics
//* *************************
export function clickOptionsForLockup(objectGraph, data, baseOptions, clickOptions) {
    return validation.context("clickOptionsForLockup", () => {
        const contextualAdamId = data.id.slice();
        let id = data.id;
        if (baseOptions.anonymizationOptions !== undefined &&
            baseOptions.anonymizationOptions.anonymizationString.length > 0) {
            id = baseOptions.anonymizationOptions.anonymizationString;
        }
        const metricsOptions = {
            ...baseOptions,
            ...clickOptions,
            id: id,
            contextualAdamId: contextualAdamId,
            softwareType: metricsUtil.softwareTypeForData(objectGraph, data),
        };
        if (serverData.isNullOrEmpty(metricsOptions.targetType)) {
            metricsOptions.targetType = objectGraph.client.isVision ? "lockupSmall" : "lockup";
        }
        // There's a delicate false split from `baseOptions` and click options interface. Some paths pre-populate an unexpected `kind`, but we don't want to change that suddenly.
        // Derive `kind` from data if missing.
        if (serverData.isNull(metricsOptions.kind)) {
            metricsOptions.kind = metricsUtil.metricsKindFromData(objectGraph, data);
        }
        // Include offerType for pre-order impressions
        const isPreorder = mediaAttributes.attributeAsBoolean(data, "isPreorder");
        if (isPreorder) {
            metricsOptions.offerType = "preorder";
        }
        return metricsOptions;
    });
}
export function addBuyEventToOfferActionOnPage(objectGraph, action, options, isPreorder, isDefaultBrowser) {
    var _a, _b, _c, _d, _e;
    const pageInformation = options.pageInformation;
    const buttonMetricsOptions = {
        ...options,
        targetType: "button",
    };
    const metricsLocations = metricsLocation.createContentLocation(objectGraph, buttonMetricsOptions, (_a = action.title) !== null && _a !== void 0 ? _a : "");
    let targetId = (_c = (_b = options.anonymizationOptions) === null || _b === void 0 ? void 0 : _b.anonymizationString) !== null && _c !== void 0 ? _c : action.adamId;
    if (isSome(options.targetId) && ((_d = options.targetId) === null || _d === void 0 ? void 0 : _d.length) > 0) {
        targetId = options.targetId;
    }
    addBuyEventToOfferAction(objectGraph, action, targetId, isPreorder, pageInformation, metricsLocations, (_e = options.isAdvert) !== null && _e !== void 0 ? _e : false, options.recoMetricsData, isDefaultBrowser);
}
export function addBuyEventToOfferActionInheritingMetrics(objectGraph, newAction, originalAction, isPreorder) {
    const originalPageInformation = originalAction.purchaseConfiguration.pageInformation;
    // Find some event to inherit location event field from.
    let metricsLocations;
    if (isSome(originalAction.actionMetrics)) {
        for (const event of originalAction.actionMetrics.data) {
            metricsLocations = serverData.asArrayOrEmpty(serverData.asJSONValue(event.fields), "location");
            if (metricsLocations) {
                break;
            }
        }
    }
    // Fine for now - CMC doesn't use anonymization.
    addBuyEventToOfferAction(objectGraph, newAction, newAction.adamId, isPreorder, originalPageInformation, metricsLocations, false);
}
function addBuyEventToOfferAction(objectGraph, action, targetId, isPreorder, pageInformation, metricsLocations, isAdvert, recoMetricsData, isDefaultBrowser) {
    var _a, _b, _c, _d, _e;
    const eventFields = {};
    if (pageInformation) {
        // We can't always check that `pageInformation` is an `instanceof MetricsPageInformation` here, because sometimes
        // `pageInformation` is reconstituted from JSON which means it doesn't get the underlying type information.
        // Instead, cast it and check for the existence of individual properties on the cast object.
        const metricsPageInformation = pageInformation;
        if (isAdvert &&
            ((_c = (_b = (_a = metricsPageInformation.iAdInfo) === null || _a === void 0 ? void 0 : _a.iAdAdamId) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) > 0 &&
            isSome(metricsPageInformation.iAdInfo) &&
            metricsPageInformation.iAdInfo.iAdAdamId === action.adamId) {
            Object.assign(eventFields, metricsPageInformation.iAdInfo.clickFields);
        }
        if (serverData.isDefinedNonNullNonEmpty(metricsPageInformation.searchTermContext)) {
            eventFields["searchTerm"] = metricsPageInformation.searchTermContext.term;
        }
    }
    // Add the reco metrics data if available
    if (isSome(recoMetricsData)) {
        Object.assign(eventFields, recoMetricsData);
    }
    eventFields["actionDetails"] = { buyParams: action.purchaseConfiguration.buyParams };
    if (metricsLocations !== undefined) {
        eventFields["location"] = metricsLocations;
    }
    // This hack where we add the adamId to the eventFields can be removed when `ActionDispatcher`
    // is fully enabled and old ActionRunner code is removed. The custom data below replaces this.
    eventFields[metricsConstants.contextualAdamIdKey] = action.adamId;
    action.actionMetrics.custom[metricsConstants.contextualAdamIdKey] = action.adamId;
    // Add Pre-order fields
    if (isPreorder) {
        eventFields["offerType"] = "preorder";
        if (serverData.isDefinedNonNull(action.expectedReleaseDate)) {
            eventFields["offerReleaseDate"] = dateUtil.millisecondsToUTCMidnightFromLocalDate(action.expectedReleaseDate);
        }
    }
    const clickEvent = metricsBuilder.createMetricsClickData(objectGraph, targetId, "button", eventFields, undefined, isDefaultBrowser);
    // This hack where we add the adamId to the eventFields can be removed when `ActionDispatcher`
    // is fully enabled and old ActionRunner code is removed. The custom data below replaces this.
    eventFields[metricsConstants.contextualAdamIdKey] = action.adamId; // needed for `appState`
    action.actionMetrics.custom[metricsConstants.contextualAdamIdKey] = action.adamId;
    clickEvent.includingFields.push("appState");
    if (action.purchaseConfiguration.isArcadeApp) {
        // Include button names in arcade buy action metrics
        clickEvent.includingFields.push("buttonName");
    }
    const shouldIncludeAdRotationFields = (_e = (_d = pageInformation === null || pageInformation === void 0 ? void 0 : pageInformation.iAdInfo) === null || _d === void 0 ? void 0 : _d.shouldIncludeAdRotationFields) !== null && _e !== void 0 ? _e : false;
    if (isAdvert && shouldIncludeAdRotationFields) {
        clickEvent.includingFields.push("advertRotation");
    }
    const shouldIncludeAdWindowFields = isAdvert && objectGraph.client.isPad;
    if (shouldIncludeAdWindowFields) {
        clickEvent.includingFields.push("advertDeviceWindow");
    }
    action.actionMetrics.addMetricsData(clickEvent);
}
export function addClickEventToArcadeBuyInitiateAction(objectGraph, action, options) {
    var _a;
    addClickEventToAction(objectGraph, action, {
        ...options,
        actionType: "buyInitiate",
        subscriptionSKU: (_a = objectGraph.bag.arcadeProductId) !== null && _a !== void 0 ? _a : undefined,
        actionContext: "Arcade",
        targetType: "button",
    });
}
export function addClickEventToAction(objectGraph, action, options, addIAdFields = false, targetType) {
    var _a, _b, _c, _d, _e, _f, _g;
    let actionType = options.actionType;
    if (!actionType) {
        actionType = "navigate";
    }
    const eventFields = {
        actionType: actionType,
    };
    // Ad click events will be wrapped in a CompoundAction. We still want to handle attaching `actionUrl` properly
    // below if a `FlowAction` or `ExternalUrlAction` are inside the `CompoundAction`, so we create an array of actions
    // to check.
    let actions;
    if (action instanceof models.CompoundAction) {
        actions = action.actions;
    }
    else {
        actions = [action];
    }
    actions.forEach((subAction) => {
        // Set the action URL if appropriate
        if (subAction instanceof models.FlowAction) {
            const flowAction = subAction;
            eventFields["actionUrl"] = flowAction.pageUrl;
        }
        else if (subAction instanceof models.ExternalUrlAction) {
            const flowAction = subAction;
            eventFields["actionUrl"] = flowAction.url;
        }
    });
    if (options.actionDetails) {
        eventFields["actionDetails"] = options.actionDetails;
    }
    if (options.actionContext) {
        eventFields["actionContext"] = options.actionContext;
    }
    // Add offer type for pre-orders
    if (serverData.isDefinedNonNull(options.offerType)) {
        eventFields["offerType"] = options.offerType;
    }
    // Add release date for pre-orders
    if (serverData.isDefinedNonNull(options.offerReleaseDate)) {
        eventFields["offerReleaseDate"] = dateUtil.millisecondsToUTCMidnightFromLocalDate(options.offerReleaseDate);
    }
    const title = (_c = (_b = (_a = options.anonymizationOptions) === null || _a === void 0 ? void 0 : _a.anonymizationString) !== null && _b !== void 0 ? _b : action === null || action === void 0 ? void 0 : action.title) !== null && _c !== void 0 ? _c : "";
    eventFields["location"] = metricsLocation.createContentLocation(objectGraph, options, title);
    // Search Term
    if (options.pageInformation && options.pageInformation.searchTermContext) {
        eventFields["searchTerm"] = options.pageInformation.searchTermContext.term;
    }
    if (serverData.isDefinedNonNull(options.softwareType)) {
        eventFields["softwareType"] = options.softwareType;
    }
    // Advert Metrics
    let additionalIncludingFields;
    // Do we need both `options.isAdvert` and `addIAdFields`?
    if ((options.isAdvert || options.isAdEligible) && addIAdFields && ((_d = options.pageInformation) === null || _d === void 0 ? void 0 : _d.iAdInfo)) {
        Object.assign(eventFields, options.pageInformation.iAdInfo.clickFields);
        if (objectGraph.client.isPad) {
            additionalIncludingFields = ["advertDeviceWindow"];
        }
    }
    if (options.mercuryMetricsData) {
        Object.assign(eventFields, options.mercuryMetricsData);
    }
    if (isSome(options.subjectIds)) {
        eventFields["subjectIds"] = options.subjectIds;
    }
    const event = metricsBuilder.createMetricsClickData(objectGraph, options.id, targetType !== null && targetType !== void 0 ? targetType : metricsUtil.targetTypeForMetricsOptions(objectGraph, options), eventFields, additionalIncludingFields);
    // Include button names in arcade buy action metrics
    const isArcadeBuyAction = options.actionContext === "Arcade" && (options.actionType === "buy" || options.actionType === "buyInitiate");
    if (isArcadeBuyAction) {
        event.includingFields.push("buttonName");
        // This hack where we add the adamId to the eventFields can be removed when `ActionDispatcher`
        // is fully enabled and old ActionRunner code is removed. The custom data below replaces this.
        event.fields[metricsConstants.contextualAdamIdKey] = options.contextualAdamId;
        if (isSome(action.adamId)) {
            action.actionMetrics.custom[metricsConstants.contextualAdamIdKey] = action.adamId;
        }
    }
    // Include ad rotation metrics and click events if enabled for placement.
    const shouldIncludeAdRotationFields = (_g = (_f = (_e = options.pageInformation) === null || _e === void 0 ? void 0 : _e.iAdInfo) === null || _f === void 0 ? void 0 : _f.shouldIncludeAdRotationFields) !== null && _g !== void 0 ? _g : false;
    if (options.isAdvert && shouldIncludeAdRotationFields) {
        event.includingFields.push("advertRotation");
    }
    action.actionMetrics.addMetricsData(event);
}
/**
 *
 * @param objectGraph The App Store Object Graph
 * @param action The search cancel or dismiss action
 * @param options The metrics click options
 * @param targetType The metrics click target type
 * @param searchTerm The current search term
 */
export function addClickEventToSearchCancelOrDismissAction(objectGraph, action, options, targetType, searchTerm) {
    const eventFields = {
        searchTerm: searchTerm,
        actionType: options.actionType,
    };
    if (options.actionDetails) {
        eventFields["actionDetails"] = options.actionDetails;
    }
    if (options.actionContext) {
        eventFields["actionContext"] = options.actionContext;
    }
    // Search Term
    if (searchTerm) {
        eventFields["searchTerm"] = searchTerm;
    }
    if (serverData.isDefinedNonNull(options.softwareType)) {
        eventFields["softwareType"] = options.softwareType;
    }
    if (options.mercuryMetricsData) {
        Object.assign(eventFields, options.mercuryMetricsData);
    }
    const event = metricsBuilder.createMetricsClickData(objectGraph, options.id, targetType !== null && targetType !== void 0 ? targetType : metricsUtil.targetTypeForMetricsOptions(objectGraph, options), eventFields);
    action.actionMetrics.addMetricsData(event);
}
export function addClickEventsToAdLockup(objectGraph, lockup, clickOptions) {
    var _a, _b, _c, _d, _e;
    const searchAd = (_b = (_a = lockup.searchAdOpportunity) === null || _a === void 0 ? void 0 : _a.searchAd) !== null && _b !== void 0 ? _b : lockup.searchAd;
    if (serverData.isNull(searchAd)) {
        return;
    }
    // Theoretically, we would probably be fine to just overwrite the click event action metrics below in `addClickEventToAction`.
    // But we'll keep the call to clear the metrics just to provide continuity with older code that ran this full path.
    (_c = lockup.clickAction) === null || _c === void 0 ? void 0 : _c.actionMetrics.clearAll();
    if (lockup.clickAction) {
        addClickEventToAction(objectGraph, lockup.clickAction, clickOptions, true);
    }
    const pageInformation = clickOptions.pageInformation;
    const eventFields = {
        actionType: "ad_transparency",
    };
    if (pageInformation === null || pageInformation === void 0 ? void 0 : pageInformation.iAdInfo) {
        Object.assign(eventFields, pageInformation.iAdInfo.clickFields);
    }
    const figaroEvent = metricsBuilder.createMetricsClickData(objectGraph, lockup.adamId, "button", eventFields);
    const shouldIncludeAdRotationFields = (_e = (_d = pageInformation === null || pageInformation === void 0 ? void 0 : pageInformation.iAdInfo) === null || _d === void 0 ? void 0 : _d.shouldIncludeAdRotationFields) !== null && _e !== void 0 ? _e : false;
    if (shouldIncludeAdRotationFields) {
        figaroEvent.includingFields.push("advertRotation");
    }
    searchAd.transparencyAction.actionMetrics.addMetricsData(figaroEvent);
}
export function addClickEventToSeeAllAction(objectGraph, action, url, options) {
    const eventFields = {};
    if (serverData.isDefinedNonNull(url)) {
        eventFields["actionUrl"] = url;
    }
    if (!options.targetType) {
        options.targetType = "button";
    }
    eventFields["location"] = metricsLocation.createBasicLocation(objectGraph, options, action.title);
    eventFields["actionType"] = "navigate";
    eventFields["target"] = "button_See All";
    const event = metricsBuilder.createMetricsClickData(objectGraph, "See All", "button", eventFields);
    action.actionMetrics.addMetricsData(event);
}
export function addClickEventToClearSearchHistoryAction(objectGraph, clearAction) {
    // MAINTAINER'S NOTE:
    // We intentionally use an unlocalized targetId, instead of localized `clearAction.title`,
    // so metrics are consistent regardless of language.
    const clickMetrics = metricsBuilder.createMetricsClickData(objectGraph, "Clear Searches", "button", {
        actionType: "confirm",
    });
    clearAction.actionMetrics.addMetricsData(clickMetrics);
}
export function addClickEventToActivityFeedMetrics(objectGraph, actionMetrics, title, targetId, options) {
    const eventFields = {
        actionType: "navigate",
        id: targetId,
        idType: "static",
        location: metricsLocation.createBasicLocation(objectGraph, options, title),
    };
    const clickEvent = metricsBuilder.createMetricsClickData(objectGraph, targetId, "link", eventFields);
    actionMetrics.addMetricsData(clickEvent);
}
export function addClickEventToPageFacetsChangeAction(objectGraph, action, filterParameter) {
    const eventFields = {};
    eventFields["actionType"] = "filter";
    const event = metricsBuilder.createMetricsClickData(objectGraph, `filter_${filterParameter}`, "button", eventFields);
    event.includingFields.push("selectedPageFacets");
    action.actionMetrics.addMetricsData(event);
}
//* *************************
//* Search Metrics
//* *************************
/**
 * Adds a given `SearchAction` with the metrics data based on the Search it will fire, i.e data for:
 * - Click Event
 * - Search Event
 *
 * @param action Action to add metrics to
 * @param target Target of this action. This should correspond to the UI this action is attached to.
 * @param locationTracker Location tracker.
 */
export function addEventsToSearchAction(objectGraph, action, target, locationTracker, pageInformation) {
    var _a, _b, _c, _d;
    const actionType = metricsActionTypeForSearchOrigin(action.origin);
    if (isNothing(pageInformation)) {
        pageInformation = new metricsModels.MetricsPageInformation({
            page: "Search",
            pageType: "Search",
            pageId: "Search",
            pageDetails: "Apps", // Legacy. Note sure why this is Apps.
        });
    }
    const options = {
        pageInformation: pageInformation,
        locationTracker: locationTracker,
        targetType: target,
    };
    // Click-Only Fields
    const clickFields = {
        ...metricsMisc.fieldsFromPageInformation(pageInformation),
        actionType: actionType,
        actionUrl: metricsUtil.emptyStringIfNullOrUndefined(action.url),
        location: metricsLocation.createBasicLocation(objectGraph, options, action.term),
        searchTerm: action.term,
    };
    // Search-Only Fields
    const searchFields = {
        targetId: action.term,
    };
    const searchActionDetails = {};
    if ((_a = action.prefixTerm) === null || _a === void 0 ? void 0 : _a.length) {
        // Keep `searchPrefix` in `actionDetails` for search events
        searchActionDetails["searchPrefix"] = action.prefixTerm;
    }
    if ((_b = action.entity) === null || _b === void 0 ? void 0 : _b.length) {
        searchActionDetails["hintsEntity"] = action.entity;
    }
    if (serverData.isDefinedNonNullNonEmpty(searchActionDetails)) {
        searchFields["actionDetails"] = searchActionDetails;
    }
    // Shared Fields
    if ((_c = action.originatingTerm) === null || _c === void 0 ? void 0 : _c.length) {
        clickFields["searchOriginatingTerm"] = action.originatingTerm;
        searchFields["searchOriginatingTerm"] = action.originatingTerm;
    }
    // SSS: Clicks must be before Search
    const clickData = metricsBuilder.createMetricsClickData(objectGraph, action.term, target, clickFields, [
        "searchGhostHint",
    ]);
    action.actionMetrics.addMetricsData(clickData);
    const searchData = metricsBuilder.createMetricsSearchData(objectGraph, action.term, target, actionType, (_d = action.url) !== null && _d !== void 0 ? _d : null, searchFields, ["searchGhostHint"]);
    action.actionMetrics.addMetricsData(searchData);
}
/**
 * Returns the mapped action type for given search origin.
 * @param origin Origin to resolve action type for
 */
function metricsActionTypeForSearchOrigin(origin) {
    // actionType based on search origin.
    switch (origin) {
        case "trending":
            return "trending";
        case "suggested":
            return "suggested";
        case "recents":
            return "recentQuery";
        case "hints":
            return "hint";
        case "undoSpellCorrection":
            return "searchInsteadFor";
        case "applySpellCorrection":
            return "didYouMean";
        case "userTypedHint":
            return "userTypedHint";
        // It is unexpected to see other search origins here. These are built in native:
        default:
            return "submit";
    }
}
// region Segmented Search
/**
 * Add click metrics to segment change action
 * @param action Action to add click event to.
 * @param locationTracker Location tracker
 */
export function addEventsToSegmentChangeAction(objectGraph, action, targetId, locationTracker) {
    // Click-Only Fields
    const targetType = "link";
    const clickFields = {
        actionType: "navigate",
        location: metricsLocation.createBasicLocation(objectGraph, {
            pageInformation: null,
            locationTracker: locationTracker,
            targetType: targetType,
        }, action.title),
    };
    const clickData = metricsBuilder.createMetricsClickData(objectGraph, targetId, targetType, clickFields);
    action.actionMetrics.addMetricsData(clickData);
}
/**
 * Add click metrics to segment change action
 * @param action Action to add click event to.
 * @param locationTracker Location tracker
 */
export function addClickEventToSearchPageSegmentChangeAction(objectGraph, action, targetId, locationTracker) {
    // Click-Only Fields
    const targetType = "SearchResults";
    const clickFields = {
        actionType: "navigate",
        location: metricsLocation.createBasicLocation(objectGraph, {
            pageInformation: null,
            locationTracker: locationTracker,
            targetType: targetType,
        }, "searchPageSegmentChange"),
    };
    const clickData = metricsBuilder.createMetricsClickData(objectGraph, targetId, targetType, clickFields);
    action.actionMetrics.addMetricsData(clickData);
}
// endregion
//# sourceMappingURL=clicks.js.map