import { isNothing, isSome } from "@jet/environment";
import * as models from "../../api/models";
import * as serverData from "../../foundation/json-parsing/server-data";
import * as mediaAttributes from "../../foundation/media/attributes";
import * as platformAttributes from "../../foundation/media/platform-attributes";
import * as mediaRelationship from "../../foundation/media/relationships";
import { Host, Parameters, Protocol } from "../../foundation/network/url-constants";
import * as urls from "../../foundation/network/urls";
import * as objects from "../../foundation/util/objects";
import * as videoDefaults from "../constants/video-constants";
import * as contentArtwork from "../content/artwork/artwork";
import * as contentAttributes from "../content/attributes";
import * as content from "../content/content";
import * as lockups from "../lockups/lockups";
import * as metricsBuilder from "../metrics/builder";
import * as metricsHelpersClicks from "../metrics/helpers/clicks";
import * as metricsHelpersImpressions from "../metrics/helpers/impressions";
import * as metricsHelpersLocation from "../metrics/helpers/location";
import * as metricsHelpersMisc from "../metrics/helpers/misc";
import * as metricsHelpersModels from "../metrics/helpers/models";
import * as appPromotionModel from "./app-promotion";
import { formattedTextFromData } from "./contingent-offer";
/**
 * Convenience function for determining if app events are enabled.
 */
export function appEventsAreEnabled(objectGraph) {
    return objectGraph.bag.enableAppEvents && (objectGraph.client.isiOS || objectGraph.client.isWeb);
}
/**
 * Convenience function for determining if contingent items are enabled.
 */
export function appContingentItemsAreEnabled(objectGraph) {
    const isContingentEnabledInBag = objectGraph.bag.enableContingentOffers;
    return isContingentEnabledInBag && objectGraph.client.isiOS;
}
/**
 * Convenience function for determining if offer items (Winback) items are enabled.
 */
export function appOfferItemsAreEnabled(objectGraph) {
    return objectGraph.bag.enableOfferItems && objectGraph.client.isiOS;
}
/**
 * Creates the artwork suitable for an app promotion
 * @param data The data blob
 * @param artworkKey The key used to derive the artwork from the data blob
 */
export function artworkFromData(objectGraph, data, artworkKey) {
    const artworkData = mediaAttributes.attributeAsDictionary(data, artworkKey);
    if (isNothing(artworkData)) {
        return null;
    }
    const artwork = content.artworkFromApiArtwork(objectGraph, artworkData, {
        useCase: 0 /* content.ArtworkUseCase.Default */,
        withJoeColorPlaceholder: true,
        cropCode: "sr",
    });
    return artwork;
}
/**
 * Creates the artwork suitable for an app promotion from the platform attributes
 * @param data The data blob
 * @param artworkKey The key used to derive the artwork from the data blob
 */
export function artworkFromPlatformData(objectGraph, data, artworkKey) {
    const attributePlatform = contentAttributes.bestAttributePlatformFromData(objectGraph, data);
    if (isNothing(attributePlatform)) {
        return null;
    }
    const artworkData = platformAttributes.platformAttributeAsDictionary(data, attributePlatform, artworkKey);
    if (isNothing(artworkData)) {
        return null;
    }
    const artwork = content.artworkFromApiArtwork(objectGraph, artworkData, {
        useCase: 0 /* content.ArtworkUseCase.Default */,
        withJoeColorPlaceholder: true,
        cropCode: "sr",
    });
    return artwork;
}
/**
 * Creates the video suitable for an app promotion
 * @param objectGraph
 * @param data The data blob
 * @param videoKey The key used to derive the video from the data blob
 * @param canPlayFullScreen Whether the video should support full-screen playback
 * @param isFullPage whether this video is being used on the full page
 */
export function videoFromData(objectGraph, data, videoKey, canPlayFullScreen, isFullPage) {
    // Preview artwork
    const previewArtwork = artworkFromData(objectGraph, data, `${videoKey}.previewFrame`);
    if (serverData.isNull(previewArtwork)) {
        return null;
    }
    // Video URL
    const videoUrl = mediaAttributes.attributeAsString(data, `${videoKey}.video`);
    if (serverData.isNull(videoUrl)) {
        return null;
    }
    const autoplayPlaybackControls = {
        muteUnmute: true,
    };
    const configuration = {
        allowsAutoPlay: true,
        looping: true,
        canPlayFullScreen: canPlayFullScreen,
        playbackControls: isFullPage ? videoDefaults.standardControls(objectGraph) : {},
        autoPlayPlaybackControls: isFullPage ? autoplayPlaybackControls : {},
    };
    const video = new models.Video(videoUrl, previewArtwork, configuration);
    video.canPlayFullScreen = canPlayFullScreen;
    video.allowsAutoPlay = true;
    video.looping = true;
    return video;
}
/**
 * Creates the lockup for an app event or contingent offer
 * @param objectGraph The object graph.
 * @param promotionData The data blob
 * @param parentAppData The related parent app of this app promotion
 * @param title The title of the app promotion
 * @param offerEnvironment The preferred environment for the offer
 * @param offerStyle The preferred style of the offer
 * @param includeCrossLinkTitles Whether the cross link titles will be displayed when the app is installed
 * @param baseMetricsOptions The base metrics options for the lockup
 * @param includeLockupClickAction Whether to generate a click action for the lockup
 * @param referrerData Referrer data from an incoming deep link
 * @param isArcadePage Whether or not this is presented on the Arcade page.
 * @param includeModuleClickLocation Whether or not this to push the module location to the location tracker.

 */
export function lockupFromData(objectGraph, promotionData, parentAppData, title, offerEnvironment, offerStyle, includeCrossLinkTitles, baseMetricsOptions, includeLockupClickAction, referrerData, isArcadePage, includeModuleClickLocation) {
    var _a, _b, _c;
    if (isNothing(promotionData) || isNothing(parentAppData)) {
        // if (serverData.isNullOrEmpty(promotionData) || serverData.isNullOrEmpty(parentAppData)) {
        return null;
    }
    const promotionType = appPromotionModel.promotionTypeFromData(promotionData);
    // Push a content location, so that the lockup action has both the containing card (eg. event module)
    // lockup location included.
    const contentMetricsOptions = {
        ...baseMetricsOptions,
        id: promotionData.id,
        relatedSubjectIds: [parentAppData.id],
        idType: "its_id",
    };
    const lockupMetrics = {
        ...baseMetricsOptions,
        id: parentAppData.id,
        relatedSubjectIds: [parentAppData.id],
        targetType: "lockup",
        idType: "its_id",
        kind: null,
        softwareType: null,
        title: (_a = mediaAttributes.attributeAsString(parentAppData, "name")) !== null && _a !== void 0 ? _a : "",
        excludeAttribution: serverData.isNullOrEmpty(referrerData),
    };
    if (promotionType === models.AppPromotionType.AppEvent) {
        contentMetricsOptions["inAppEventId"] = promotionData.id;
        lockupMetrics["inAppEventId"] = promotionData.id;
    }
    // If our base metrics options are in fact content metrics options, we want to carry across
    // the ID and ID type. This specifically caters for heros / editorial cards.
    if (metricsHelpersModels.isContentMetricsOptions(baseMetricsOptions)) {
        contentMetricsOptions.id = baseMetricsOptions.id;
        contentMetricsOptions.idType = baseMetricsOptions.idType;
    }
    if (includeModuleClickLocation) {
        const locationTitle = promotionType === models.AppPromotionType.ContingentOffer
            ? (_b = formattedTextFromData(objectGraph, promotionData)) === null || _b === void 0 ? void 0 : _b.rawTitle
            : mediaAttributes.attributeAsString(promotionData, "name");
        metricsHelpersLocation.pushContentLocation(objectGraph, contentMetricsOptions, locationTitle !== null && locationTitle !== void 0 ? locationTitle : "");
    }
    const externalDeepLinkUrl = mediaAttributes.attributeAsString(promotionData, "deepLink");
    const lockupOptions = {
        metricsOptions: lockupMetrics,
        artworkUseCase: 1 /* content.ArtworkUseCase.LockupIconSmall */,
        externalDeepLinkUrl: externalDeepLinkUrl !== null && externalDeepLinkUrl !== void 0 ? externalDeepLinkUrl : undefined,
        crossLinkSubtitle: includeCrossLinkTitles ? title : undefined,
        offerEnvironment: offerEnvironment,
        offerStyle: offerStyle,
        skipDefaultClickAction: !includeLockupClickAction,
        includeBetaApps: true,
        referrerData: referrerData !== null && referrerData !== void 0 ? referrerData : undefined,
        shouldHideArcadeHeader: objectGraph.featureFlags.isEnabled("hide_arcade_header_on_arcade_tab") && isArcadePage,
        parentAppData: parentAppData,
        useJoeColorIconPlaceholder: true,
        overrideArtworkTextColorKey: "textColor4",
    };
    const resolvedData = promotionType === models.AppPromotionType.AppEvent ? parentAppData : promotionData;
    const lockup = lockups.lockupFromData(objectGraph, resolvedData, lockupOptions);
    if (includeModuleClickLocation) {
        metricsHelpersLocation.popLocation(baseMetricsOptions.locationTracker);
    }
    if (serverData.isNull(lockup)) {
        return null;
    }
    if (includeCrossLinkTitles) {
        lockup.crossLinkTitle = (_c = objectGraph.loc.uppercased(lockup.title)) !== null && _c !== void 0 ? _c : undefined;
    }
    return lockup;
}
export function notificationConfigFromData(objectGraph, data, appEvent, baseMetricsOptions, includeScheduledAction) {
    // If the event has already started, we cannot set a notification reminder
    if (appEvent.startDate.getTime() <= Date.now()) {
        return null;
    }
    if (isNothing(appEvent.lockup)) {
        return null;
    }
    const title = objectGraph.loc.string("APP_EVENTS_NOTIFICATION_TITLE").replace("{appTitle}", appEvent.lockup.title);
    const detail = objectGraph.loc.string("APP_EVENTS_NOTIFICATION_DETAIL").replace("{eventTitle}", appEvent.title);
    const displayTime = appEvent.startDate;
    const icon = appEvent.lockup.icon;
    const artworkUrl = appEvent.lockup.icon.template
        .replace("{w}", `${icon.width}`)
        .replace("{h}", `${icon.height}`)
        .replace("{c}", "wd") // iOS rounded corners
        .replace("{f}", "png");
    // Notification scheduled action
    let scheduledAction;
    if (includeScheduledAction) {
        scheduledAction = new models.AlertAction("toast");
        scheduledAction.title = objectGraph.loc.string("APP_EVENTS_NOTIFICATION_TOAST_TITLE");
        scheduledAction.message = objectGraph.loc.string("APP_EVENTS_NOTIFICATION_TOAST_DETAIL");
        scheduledAction.artwork = contentArtwork.createArtworkForResource(objectGraph, "systemimage://bell.fill");
    }
    // The below if statement can be removed in Sydro timeframe
    // Notifications not authorized action
    let notAuthorizedAction;
    if (objectGraph.bag.newEventsForODJAreEnabled) {
        // When we have ODJs active we send a metrics click event to signal the Alert button was tapped. ODJ picks this up as a signal to
        // show a half/full sheet notifications upsell to the user
        const notAuthorizedMetricsAction = new models.BlankAction();
        // Schedule click data
        const scheduleClickFieldsNotAuthed = metricsHelpersMisc.fieldsFromPageInformation(baseMetricsOptions.pageInformation);
        scheduleClickFieldsNotAuthed["actionType"] = "notifyActivateNotificationsDisabled";
        scheduleClickFieldsNotAuthed["location"] = metricsHelpersLocation.createContentLocation(objectGraph, {
            ...baseMetricsOptions,
            id: data.id,
        }, "");
        // We want to actively remove the topic from this click event so it doesn't leave the device and is only consumed by ODJ
        scheduleClickFieldsNotAuthed["topic"] = "";
        const scheduleClickDataNotAuthed = metricsBuilder.createMetricsClickData(objectGraph, appEvent.lockup.adamId, "lockup", scheduleClickFieldsNotAuthed);
        notAuthorizedMetricsAction.actionMetrics.addMetricsData(scheduleClickDataNotAuthed);
        notAuthorizedAction = notAuthorizedMetricsAction;
    }
    else {
        const notAuthorizedAlertAction = new models.AlertAction("default");
        notAuthorizedAlertAction.title = objectGraph.loc.string("APP_EVENTS_NOTIFICATION_NOT_AUTHORIZED_TITLE");
        notAuthorizedAlertAction.message = objectGraph.loc.string("APP_EVENTS_NOTIFICATION_NOT_AUTHORIZED_DETAIL");
        notAuthorizedAlertAction.isCancelable = true;
        notAuthorizedAlertAction.buttonTitles = [objectGraph.loc.string("ACTION_SETTINGS")];
        // NOTE: This URL only works on iOS. If this feature is expanded beyond iOS, this code will need to be split per-platform.
        notAuthorizedAlertAction.buttonActions = [
            new models.ExternalUrlAction("prefs:root=NOTIFICATIONS_ID&path=com.apple.AppStore", true),
        ];
        notAuthorizedAction = notAuthorizedAlertAction;
    }
    const failureAction = new models.AlertAction("default");
    failureAction.title = objectGraph.loc.string("APP_EVENTS_NOTIFICATION_FAILURE_TITLE");
    failureAction.message = objectGraph.loc.string("APP_EVENTS_NOTIFICATION_FAILURE_DETAIL");
    failureAction.isCancelable = true;
    // App launch trampoline URL
    const appLaunchTrampolineUrl = new urls.URL()
        .set("protocol", Protocol.storeKitUIServiceAppStore)
        .param(Parameters.appId, appEvent.lockup.adamId)
        .param(Parameters.bundleId, appEvent.lockup.bundleId)
        .param(Parameters.appEventId, appEvent.appEventId);
    appLaunchTrampolineUrl.host = Host.launchApp;
    const externalDeepLinkUrl = mediaAttributes.attributeAsString(data, "deepLink");
    if (isSome(externalDeepLinkUrl) && (externalDeepLinkUrl === null || externalDeepLinkUrl === void 0 ? void 0 : externalDeepLinkUrl.length) > 0) {
        appLaunchTrampolineUrl.param(Parameters.appEventDeepLink, encodeURIComponent(externalDeepLinkUrl));
    }
    // Schedule click data
    const scheduleClickFields = metricsHelpersMisc.fieldsFromPageInformation(baseMetricsOptions.pageInformation);
    scheduleClickFields["actionType"] = "notifyActivate";
    scheduleClickFields["location"] = metricsHelpersLocation.createContentLocation(objectGraph, {
        ...baseMetricsOptions,
        id: data.id,
    }, "");
    const scheduleClickData = metricsBuilder.createMetricsClickData(objectGraph, appEvent.lockup.adamId, "lockup", scheduleClickFields);
    // Cancel schedule click data
    const cancelScheduleClickFields = objects.shallowCopyOf(scheduleClickFields);
    cancelScheduleClickFields["actionType"] = "notifyDeactivate";
    const cancelScheduleClickData = metricsBuilder.createMetricsClickData(objectGraph, appEvent.lockup.adamId, "lockup", cancelScheduleClickFields);
    return new models.AppEventNotificationConfig(data.id, title, detail, artworkUrl, displayTime, scheduledAction, notAuthorizedAction, failureAction, appLaunchTrampolineUrl.build(), scheduleClickData, cancelScheduleClickData);
}
/**
 * Create a click action for navigating to the contingent offer detail page.
 * @param data The data blob
 * @param parentAppData The associated parent app data
 * @param appPromotion The source app promotion
 * @param baseMetricsOptions The base metrics options
 * @param includeLockupClickAction Whether to generate a click action for the lockup
 */
export function detailPageClickActionFromData(objectGraph, data, parentAppData, appPromotion, baseMetricsOptions, includeLockupClickAction) {
    const action = appPromotionModel.detailPageFlowActionFromData(objectGraph, data, parentAppData, appPromotion, baseMetricsOptions, "infer", includeLockupClickAction, null);
    if (isNothing(action)) {
        return undefined;
    }
    const clickOptions = {
        id: data.id,
        actionDetails: {
            action: "Open",
            contentType: appPromotionModel.metricsTargetTypeFromData(data),
        },
        relatedSubjectIds: [parentAppData.id],
        ...baseMetricsOptions,
    };
    const promotionType = appPromotionModel.promotionTypeFromData(data);
    if (promotionType === models.AppPromotionType.AppEvent) {
        clickOptions["inAppEventId"] = data.id;
    }
    metricsHelpersClicks.addClickEventToAction(objectGraph, action, clickOptions);
    return action;
}
/**
 * Creates the app events or contingent offers objects from the given data
 * @param objectGraph The object graph
 * @param appPromotionDataItems The array of app event / contingent offer data blobs.
 * @param parentAppData The data for the parent app, if any.
 * @param hideLockupWhenNotInstalled If true, the lockup will be hidden when the app is not locally installed
 * @param includeCrossLinkTitles Whether the cross link titles will be displayed when the app is installed
 * @param baseMetricsOptions The base metrics options for the app promotions
 * @param allowEndedEvents Whether or not ended events should be returned
 * @param includeLockupClickAction Whether to generate a click action for the lockup
 * @param isArcadePage Whether or not this is presented on the Arcade page
 * @param allowUnpublishedAppEventPreviews Whether or not to allow app event previews
 * @returns an DisplayableAppPromotions object including the relevant App Promotions, as well as an optional Date for when the next App Event should be visible.
 */
export function appPromotionsFromData(objectGraph, appPromotionDataItems, parentAppData = null, hideLockupWhenNotInstalled, includeCrossLinkTitles, baseMetricsOptions, allowEndedEvents, includeLockupClickAction, isArcadePage, allowUnpublishedAppEventPreviews) {
    var _a;
    const appPromotions = [];
    let nextAppEventPromotionStartDate;
    for (const data of appPromotionDataItems) {
        const appPromotionOrDate = appPromotionModel.appPromotionOrDateFromData(objectGraph, data, parentAppData, hideLockupWhenNotInstalled, true, "light", "infer", includeCrossLinkTitles, baseMetricsOptions, allowEndedEvents, includeLockupClickAction, null, isArcadePage, allowUnpublishedAppEventPreviews);
        if (serverData.isNull(appPromotionOrDate)) {
            continue;
        }
        if (appPromotionOrDate instanceof Date) {
            // Set the next event promotion start date if we don't yet have one, or it's sooner than the current one.
            if (isNothing(nextAppEventPromotionStartDate) ||
                appPromotionOrDate.getTime() < nextAppEventPromotionStartDate.getTime()) {
                nextAppEventPromotionStartDate = appPromotionOrDate;
            }
            continue;
        }
        const appPromotionItem = appPromotionOrDate;
        // Metrics
        const impressionOptions = {
            ...baseMetricsOptions,
            id: data.id,
            kind: appPromotionModel.metricsKindFromData(data),
            targetType: appPromotionModel.metricsTargetTypeFromData(data),
            title: (_a = appPromotionItem.title) !== null && _a !== void 0 ? _a : "",
            softwareType: null,
        };
        const resolvedParentAppData = parentAppData !== null && parentAppData !== void 0 ? parentAppData : mediaRelationship.relationshipData(objectGraph, data, "app");
        if (serverData.isDefinedNonNull(resolvedParentAppData)) {
            impressionOptions.relatedSubjectIds = [resolvedParentAppData.id];
        }
        metricsHelpersImpressions.addImpressionFields(objectGraph, appPromotionItem, impressionOptions);
        metricsHelpersLocation.nextPosition(impressionOptions.locationTracker);
        appPromotions.push(appPromotionItem);
    }
    return {
        appPromotions: appPromotions,
        nextAppEventPromotionStartDate: nextAppEventPromotionStartDate,
    };
}
/**
 * Replaces keys inside a templated string with their computed values.
 * @param templateString A templated string with keys that need to be replaced
 * @param templateKeys A map of string keys to replacement strings
 * @returns A filled out string with no keys
 */
export function replacingTemplatedKeys(templateString, templateKeys) {
    let returnString = templateString !== null && templateString !== void 0 ? templateString : "";
    Object.keys(templateKeys).forEach((element) => {
        returnString = returnString.replace(element, templateKeys[element]);
    });
    return returnString;
}
// endregion
//# sourceMappingURL=app-promotions-common.js.map