import * as models from "../../../api/models";
import * as validation from "@jet/environment/json/validation";
import * as contentArtwork from "../../content/artwork/artwork";
import { isNothing, isSome } from "@jet/environment";
import { attributeAsDictionary, attributeAsString, URL } from "@apple-media-services/media-api";
import { asString } from "../../../foundation/json-parsing/server-data";
import { isEmpty, isNotEmpty } from "../../../foundation/util/array-util";
import { Path, Protocol } from "../../../foundation/network/url-constants";
import { isProductAccessibilityLabelsEnabled, shouldSuppressAccessibilityLabelsForAdamId, shouldSuppressAccessibilityLabelsForBundleId, } from "../../accessibility/accessibility-common";
import { attributeAsArray } from "../../../foundation/media/attributes";
import { contentAttributeAsString } from "../../content/attributes";
import { newLocationTracker, nextPosition } from "../../metrics/helpers/location";
import { addClickEventToAction } from "../../metrics/helpers/clicks";
import { addMetricsEventsToPageWithInformation, metricsPageInformationFromMediaApiResponse, } from "../../metrics/helpers/page";
import { makeRoutableArticlePageIntent } from "../../../api/intents/routable-article-page-intent";
import { getLocale } from "../../locale";
import { getPlatform } from "../../preview-platform";
// region Validation
/**
 * Returns whether the accessibility section should be displayed on the product page, based on whether accessibility
 * data is available for the device family we want to use, and the feature is enabled.
 */
export function shouldShowAccessibilitySection(objectGraph, data, deviceFamily) {
    var _a;
    const accessibilityData = attributeAsDictionary(data, `accessibility.${deviceFamily}`);
    const bundleId = (_a = contentAttributeAsString(objectGraph, data, "bundleId")) !== null && _a !== void 0 ? _a : "";
    return (isProductAccessibilityLabelsEnabled(objectGraph) &&
        !shouldSuppressAccessibilityLabelsForAdamId(objectGraph, data.id) &&
        !shouldSuppressAccessibilityLabelsForBundleId(objectGraph, bundleId) &&
        isSome(accessibilityData));
}
// region Shelves
/**
 * Builds the header shelf for the accessibility product page section or details page.
 */
export function createHeaderShelf(objectGraph, data, deviceFamily, isSeeAllContext, shelfMetrics, pageInformation, locationTracker) {
    return validation.context("createHeaderShelf", () => {
        const shelf = new models.Shelf("accessibilityParagraph");
        shelf.presentationHints = { isSeeAllContext: isSeeAllContext };
        // Only applicable for tvOS. Since tvOS doesn't support inline linkable text, we have to show any actions as
        // distinct buttons instead. This should remain empty for all other platforms.
        const actions = [];
        const title = objectGraph.loc.string("ProductPage.Accessibility.Shelf.Title");
        // Add shelf header / see all action on product page of all platforms, except watchOS
        if (!isSeeAllContext && !objectGraph.client.isWatch) {
            shelf.title = title;
            // Only add a details action if there are supported features
            const supportedFeatures = supportedFeaturesForDeviceFamily(data, deviceFamily, isSeeAllContext);
            const hasSupportedFeatures = isSome(supportedFeatures) && isNotEmpty(supportedFeatures);
            if (hasSupportedFeatures) {
                const seeDetailsAction = createSeeDetailsAction(objectGraph, data, deviceFamily, "button", pageInformation, locationTracker);
                if (objectGraph.client.isTV) {
                    actions.push(seeDetailsAction);
                }
                else {
                    shelf.seeAllAction = seeDetailsAction;
                }
            }
        }
        if (objectGraph.client.isTV && !isSeeAllContext) {
            // Add learn more link action, if applicable
            const learnMoreAction = createLearnMoreAction(objectGraph, pageInformation, locationTracker);
            if (isSome(learnMoreAction)) {
                actions.push(learnMoreAction);
            }
        }
        // Create item model
        const text = headerTextFromData(objectGraph, data, deviceFamily, isSeeAllContext, pageInformation, locationTracker);
        const item = new models.AccessibilityParagraph(text, actions);
        // Decorate item with impression information
        if (isSome(shelfMetrics) && !isSeeAllContext && !objectGraph.client.isWatch) {
            shelfMetrics.addImpressionsToShelf(objectGraph, shelf, "accessibilityOverview");
            nextPosition(shelfMetrics.locationTracker);
        }
        // Add item to shelf
        shelf.items = [item];
        return shelf;
    });
}
/**
 * Builds a shelf for `accessibilityFeatures`, which will display the supported accessibility features card on the
 * product page, or a list on the details page, if there are 1 or more reported features.
 */
export function createFeaturesShelf(objectGraph, data, deviceFamily, isSeeAllContext, shelfMetrics = null, pageInformation, locationTracker) {
    return validation.context("createFeaturesShelf", () => {
        const features = featuresFromData(objectGraph, data, deviceFamily, isSeeAllContext);
        // We only want to show this shelf if there is at least 1 feature
        if (isEmpty(features)) {
            return null;
        }
        // Create shelf
        const shelf = new models.Shelf("accessibilityFeatures");
        shelf.presentationHints = { isSeeAllContext: isSeeAllContext };
        // Create item
        const title = objectGraph.loc.string("ProductPage.Accessibility.Card.SupportedFeaturesTitle");
        const item = new models.AccessibilityFeatures(title, contentArtwork.createArtworkForResource(objectGraph, "systemimage://accessibility"), features);
        // Decorate with metrics and add see all action for the product page
        if (!isSeeAllContext) {
            if (isSome(shelfMetrics)) {
                shelfMetrics.addImpressionsToShelf(objectGraph, shelf, "supportedFeaturesCard", undefined, undefined, null, title);
                nextPosition(shelfMetrics.locationTracker);
            }
            // Add the see details click action for the card.
            item.clickAction = createSeeDetailsAction(objectGraph, data, deviceFamily, "card", pageInformation, locationTracker);
        }
        // Add the item to the shelf
        shelf.items = [item];
        return shelf;
    });
}
/**
 * Builds a shelf with the developer's accessibility site link, if provided.
 *
 * Not applicable on tvOS; we don't show the developer link at all on tvOS, since opening external urls is not supported.
 */
export function createDeveloperLinkShelf(objectGraph, data, isSeeAllContext, pageInformation, locationTracker) {
    return validation.context("createDeveloperLinkShelf", () => {
        if (objectGraph.client.isTV) {
            // We don't show the developer link at all on tvOS, since opening external urls is not supported.
            return null;
        }
        const text = developerLinkTextFromData(objectGraph, data, isSeeAllContext, pageInformation, locationTracker);
        if (isNothing(text)) {
            return null;
        }
        const shelf = new models.Shelf("accessibilityParagraph");
        shelf.items = [new models.AccessibilityParagraph(text, [])];
        shelf.presentationHints = { isSeeAllContext: isSeeAllContext };
        return shelf;
    });
}
/**
 * Builds a shelf with the learn more link & developer link actions as buttons, if present, to be displayed on the
 * intermediary details page.
 *
 * Only applicable on watchOS.
 */
function createWatchActionsShelf(objectGraph, data, pageInformation, locationTracker) {
    const shelf = new models.Shelf("action");
    const items = [];
    const developerLinkAction = createDeveloperLinkAction(objectGraph, data, false, pageInformation, locationTracker);
    if (isSome(developerLinkAction)) {
        items.push(developerLinkAction);
    }
    const learnMoreAction = createLearnMoreAction(objectGraph, pageInformation, locationTracker);
    if (isSome(learnMoreAction)) {
        items.push(learnMoreAction);
    }
    if (isEmpty(items)) {
        return null;
    }
    else {
        shelf.items = items;
        return shelf;
    }
}
// region Data to Model Mapping
/**
 * Returns an array of `AccessibilityFeature` models mapped from the data.
 */
function featuresFromData(objectGraph, data, deviceFamily, isSeeAllContext) {
    const supportedFeatures = supportedFeaturesForDeviceFamily(data, deviceFamily, isSeeAllContext);
    if (isNothing(supportedFeatures)) {
        return [];
    }
    return supportedFeatures.reduce((features, feature) => {
        // Extract properties from data
        const identifier = asString(feature, "identifier");
        const title = asString(feature, "title");
        const description = asString(feature, "description");
        // Validate required data
        if (isNothing(identifier) || identifier.length === 0 || isNothing(title) || title.length === 0) {
            return features;
        }
        // Map the identifier to a system image
        const systemImage = systemImageForFeature(identifier);
        if (isNothing(systemImage)) {
            return features;
        }
        // Create the feature model
        const artwork = contentArtwork.createArtworkForResource(objectGraph, `systemimage://${systemImage}`);
        artwork.imageScale = imageScaleForFeature(identifier);
        features.push(new models.AccessibilityFeature(title, description !== null && description !== void 0 ? description : null, artwork));
        return features;
    }, []);
}
/**
 * Creates the header text based on the data available.
 */
function headerTextFromData(objectGraph, data, deviceFamily, isSeeAllContext, pageInformation, locationTracker) {
    // Define input for the header text
    const supportedFeatures = supportedFeaturesForDeviceFamily(data, deviceFamily, isSeeAllContext);
    const learnMoreLinkAction = createLearnMoreAction(objectGraph, pageInformation, locationTracker);
    const developerName = attributeAsString(data, "artistName");
    const hasDeveloperName = isSome(developerName) && isNotEmpty(developerName);
    // Localize the template for the text
    let templateKey;
    if (objectGraph.client.isTV) {
        // Since the learn more link is a standalone button on tvOS, we want to ensure that we don't use the inline link version.
        templateKey = headerTemplateLocKey(isSeeAllContext, supportedFeatures, null, hasDeveloperName);
    }
    else if (objectGraph.client.isWatch) {
        templateKey = watchHeaderTemplateLocKey(supportedFeatures, hasDeveloperName);
    }
    else {
        templateKey = headerTemplateLocKey(isSeeAllContext, supportedFeatures, learnMoreLinkAction, hasDeveloperName);
    }
    let text = objectGraph.loc.string(templateKey);
    let textType = "text/plain";
    const linkedSubstrings = {};
    // Replace the learn more link with localized text, and add the relevant action
    if (isSome(learnMoreLinkAction)) {
        const learnMoreLinkText = objectGraph.loc.string("Action.LearnMore");
        text = text.replace("{learnMoreLink}", learnMoreLinkText);
        linkedSubstrings[learnMoreLinkText] = learnMoreLinkAction;
    }
    // Add the developer name
    if (hasDeveloperName) {
        text = text.replace("{developerName}", `<b>${developerName}</b>`);
        textType = "text/x-apple-as3-nqml";
    }
    const styledText = new models.StyledText(text, textType);
    return new models.LinkableText(styledText, linkedSubstrings);
}
/**
 * Creates the text for linking to the developer accessibility site, if provided.
 *
 * This is not used on tvOS.
 */
function developerLinkTextFromData(objectGraph, data, isSeeAllContext, pageInformation, locationTracker) {
    const action = createDeveloperLinkAction(objectGraph, data, isSeeAllContext, pageInformation, locationTracker);
    if (isNothing(action)) {
        return null;
    }
    const developerLinkText = objectGraph.loc.string("Accessibility.DeveloperUrlLinkTitle");
    const text = objectGraph.loc
        .string("Accessibility.DeveloperUrlText")
        .replace("{accessibilitySite}", developerLinkText);
    const linkedSubstrings = {};
    linkedSubstrings[developerLinkText] = action;
    const styledText = new models.StyledText(text, "text/plain");
    return new models.LinkableText(styledText, linkedSubstrings);
}
// region Data Parsing
/**
 * Returns the list of supported features for the device family that we want to display.
 */
function developerLinkUrl(data, isSeeAllContext) {
    const accessibilityKey = isSeeAllContext ? "accessibilityDetails" : "accessibility";
    return attributeAsString(data, `${accessibilityKey}.developerUrl`);
}
/**
 * Returns the list of supported features for the device family that we want to display.
 */
function supportedFeaturesForDeviceFamily(data, deviceFamily, isSeeAllContext) {
    const accessibilityKey = isSeeAllContext ? "accessibilityDetails" : "accessibility";
    return attributeAsArray(data, `${accessibilityKey}.${deviceFamily}.supportedCategories`);
}
// region Actions
/**
 * Creates the action for displaying the intermediary details page on watchOS.
 *
 * This intermediary page is unique to watchOS, and is really a mix between what we show on the product page vs details
 * page on all the other platforms. It is a complete page, sidepacked with all the data we have on hand from the product
 * page request (which is basically all the accessibility data, except for the feature descriptions).
 *
 * The "end" details page can be actioned by tapping on the features card platter on this page, and will load the
 * feature descriptions.
 */
export function createSeeIntermediaryDetailsAction(objectGraph, data, deviceFamily) {
    const action = new models.FlowAction("page");
    action.title = objectGraph.loc.string("ProductPage.Accessibility.Shelf.Title");
    action.pageData = accessibilityIntermediaryDetailsSidePackedPageFromData(objectGraph, data, deviceFamily);
    // A click event for this is added in `action-link-shelf.ts`.
    return action;
}
/**
 * Creates the action for displaying the accessibility details page.
 */
function createSeeDetailsAction(objectGraph, data, deviceFamily, targetType, pageInformation, locationTracker) {
    const seeDetailsAction = new models.FlowAction("accessibilityDetails");
    if (objectGraph.client.isWatch) {
        // On watchOS, we only display the supported feature descriptions on this "end" details page, which we need to
        // load. This initial page is empty.
        seeDetailsAction.pageData = watchAccessibilityDetailsPage(objectGraph);
    }
    else {
        seeDetailsAction.title = objectGraph.loc.string("ACTION_SEE_DETAILS");
        seeDetailsAction.pageData = accessibilityDetailsSidePackedPageFromData(objectGraph, data, deviceFamily, pageInformation, locationTracker);
    }
    const productType = data.type === "app-bundles" ? Path.productBundle : Path.product;
    const pageUrl = URL.fromComponents(Protocol.internal, null, `/${Path.accessibilityDetails}/${productType}/${data.id}`, { deviceFamily: deviceFamily });
    seeDetailsAction.pageUrl = pageUrl.build();
    if (objectGraph.props.enabled("supportsClickEventsOnSwiftUIHostingCell")) {
        addClickEventToAction(objectGraph, seeDetailsAction, {
            id: "AccessibilityDetails",
            targetType: targetType,
            pageInformation: pageInformation,
            locationTracker: locationTracker,
        });
    }
    return seeDetailsAction;
}
/**
 * Creates the action for linking to the learn more URL.
 */
function createLearnMoreAction(objectGraph, pageInformation, locationTracker) {
    const editorialItemId = objectGraph.bag.accessibilityLearnMoreEditorialItemId;
    if (isNothing(editorialItemId)) {
        return null;
    }
    const learnMoreAction = new models.FlowAction("article");
    learnMoreAction.title = objectGraph.loc.string("Action.LearnMore");
    learnMoreAction.pageUrl = `https://apps.apple.com/story/id${editorialItemId}`;
    if (objectGraph.client.isWeb) {
        learnMoreAction.destination = makeRoutableArticlePageIntent({
            ...getLocale(objectGraph),
            ...getPlatform(objectGraph),
            id: editorialItemId,
        });
    }
    if (objectGraph.client.isVision) {
        learnMoreAction.presentation = "sheetPresent";
    }
    if (objectGraph.props.enabled("supportsClickEventsOnSwiftUIHostingCell")) {
        addClickEventToAction(objectGraph, learnMoreAction, {
            id: "LearnMore",
            targetType: "button",
            pageInformation: pageInformation,
            locationTracker: locationTracker,
        });
    }
    return learnMoreAction;
}
/**
 * Creates the action for linking to the developer provided accessibility site.
 */
function createDeveloperLinkAction(objectGraph, data, isSeeAllContext, pageInformation, locationTracker) {
    const url = developerLinkUrl(data, isSeeAllContext);
    if (isNothing(url) || isEmpty(url)) {
        return null;
    }
    const action = new models.ExternalUrlAction(url, false);
    action.title = objectGraph.loc.string("Accessibility.DeveloperUrlLinkActionTitle");
    if (objectGraph.props.enabled("supportsClickEventsOnSwiftUIHostingCell")) {
        addClickEventToAction(objectGraph, action, {
            id: "AccessibilitySite",
            targetType: "link",
            pageInformation: pageInformation,
            locationTracker: locationTracker,
        });
    }
    return action;
}
// region Details
/**
 * Creates a complete, intermediary accessibility details page, sidepacking all data loaded from the product page.
 *
 * This intermediary page is unique to watchOS, and is really a mix between what we show on the product page vs details
 * page on all the other platforms. The "end" details page can be actioned by tapping on the features card platter on
 * this page, and will load the feature descriptions.
 *
 * NOTE: These shelves are created with `isSeeAllContext = false`, which is important for the `accessibilityFeatures`
 * shelf, so that the corresponding view is displayed as a card platter.
 */
function accessibilityIntermediaryDetailsSidePackedPageFromData(objectGraph, data, deviceFamily) {
    const shelves = [];
    // Create metrics objects
    const pageInformation = metricsPageInformationFromMediaApiResponse(objectGraph, "AppAccessibilityDetails", data.id, data);
    const locationTracker = newLocationTracker();
    // Add header shelf
    const headerShelf = createHeaderShelf(objectGraph, data, deviceFamily, false, null, pageInformation, locationTracker);
    shelves.push(headerShelf);
    // Add features shelf, if applicable
    const featuresShelf = createFeaturesShelf(objectGraph, data, deviceFamily, false, null, pageInformation, locationTracker);
    if (isSome(featuresShelf)) {
        shelves.push(featuresShelf);
    }
    // Add actions shelf, if applicable
    const actionsShelf = createWatchActionsShelf(objectGraph, data, pageInformation, locationTracker);
    if (isSome(actionsShelf)) {
        shelves.push(actionsShelf);
    }
    // Create and return page
    const page = new models.GenericPage(shelves);
    page.title = objectGraph.loc.string("AccessibilityDetails.Title");
    addMetricsEventsToPageWithInformation(objectGraph, page, pageInformation);
    return page;
}
/**
 * Creates an incomplete accessibility details page, sidepacking the header shelf & optional developer link shelf.
 */
function accessibilityDetailsSidePackedPageFromData(objectGraph, data, deviceFamily, pageInformation, locationTracker) {
    const shelves = [];
    // Add header shelf
    const headerShelf = createHeaderShelf(objectGraph, data, deviceFamily, true, null, pageInformation, locationTracker);
    shelves.push(headerShelf);
    // Add developer link shelf, if applicable
    const developerLinkShelf = createDeveloperLinkShelf(objectGraph, data, true, pageInformation, locationTracker);
    if (isSome(developerLinkShelf)) {
        shelves.push(developerLinkShelf);
    }
    // The web client displays accessibilityDetailPage as a modal,
    // so we include accessibility feature data for immediate display.
    if (objectGraph.client.isWeb) {
        const featuresShelf = createFeaturesShelf(objectGraph, data, deviceFamily, true, null, pageInformation, locationTracker);
        if (isSome(featuresShelf)) {
            shelves.push(featuresShelf);
        }
    }
    // Create and return page
    const page = new models.GenericPage(shelves);
    page.title = objectGraph.loc.string("AccessibilityDetails.Title");
    page.isIncomplete = true;
    page.presentationOptions = ["prefersLargeTitle", "prefersIndirectTouch", "prefersReadableContentAlignedTitle"];
    return page;
}
/**
 * Creates an empty accessibility details page for watchOS.
 *
 * This page is displayed when the customer taps on the features card platter on the intermediary details page, and
 * is intended to display the descriptions of the supported features, which needs to be loaded.
 */
function watchAccessibilityDetailsPage(objectGraph) {
    const page = new models.GenericPage([]);
    page.title = objectGraph.loc.string("ProductPage.Accessibility.Card.SupportedFeaturesTitle");
    page.isIncomplete = true;
    return page;
}
// region Helpers
/**
 * Returns a system image name based on the feature identifier.
 */
function systemImageForFeature(identifier) {
    switch (identifier) {
        case "VOICEOVER":
            return "voiceover";
        case "VOICE_CONTROL":
            return "voice.control";
        case "LARGER_TEXT":
            return "textformat.size";
        case "SUFFICIENT_CONTRAST":
            return "circle.lefthalf.filled.inverse";
        case "DARK_INTERFACE":
            return "appearance.darkmode";
        case "DIFFERENTIATE_WITHOUT_COLOR_ALONE":
            return "xmark.triangle.circle.square.fill";
        case "REDUCED_MOTION":
            return "circle.dotted.and.circle";
        case "CAPTIONS":
            return "captions.bubble.fill";
        case "AUDIO_DESCRIPTIONS":
            return "quote.bubble.fill";
        default:
            return null;
    }
}
/**
 * Returns an image scale we want to override based on the feature identifier.
 */
function imageScaleForFeature(identifier) {
    switch (identifier) {
        case "VOICE_CONTROL":
            return "small";
        default:
            return null;
    }
}
/**
 * Returns the localization key for the header template text, based on the information available.
 *
 * There are a few different variations of this template. There are variations for the following conditions:
 * 1. Whether we are displaying the text on the product page vs details page
 * 2. What has been reported by the developer:
 *     a. Reported with at least 1 supported feature
 *     b. Reported with NO supported features
 *     c. Not reported yet
 * 3. Whether the learn more link is available
 * 4. For the details page, whether the developer name is available (as these strings attempt to use the developer name)
 */
function headerTemplateLocKey(isSeeAllContext, supportedFeatures, learnMoreLinkAction, hasDeveloperName) {
    if (isSeeAllContext) {
        // We can only get to the details page if there is at least 1 supported feature, so we don't need to worry
        // about the reported state (2b) or (2c) from comment above.
        if (isSome(learnMoreLinkAction) && hasDeveloperName) {
            return "AccessibilityDetails.Header";
        }
        else if (hasDeveloperName) {
            return "AccessibilityDetails.Header.NoLearnMoreLink";
        }
        else if (isSome(learnMoreLinkAction)) {
            return "AccessibilityDetails.Header.NoDeveloperName";
        }
        else {
            return "AccessibilityDetails.Header.NoLearnMoreLink.NoDeveloperName";
        }
    }
    else {
        const isReported = isSome(supportedFeatures);
        const hasSupportedFeatures = isReported && isNotEmpty(supportedFeatures);
        if (hasSupportedFeatures) {
            return isSome(learnMoreLinkAction)
                ? "ProductPage.Accessibility.Header.SupportedFeatures"
                : "ProductPage.Accessibility.Header.SupportedFeatures.NoLearnMoreLink";
        }
        else if (isReported) {
            return isSome(learnMoreLinkAction)
                ? "ProductPage.Accessibility.Header.NoSupportedFeatures"
                : "ProductPage.Accessibility.Header.NoSupportedFeatures.NoLearnMoreLink";
        }
        else {
            return isSome(learnMoreLinkAction)
                ? "ProductPage.Accessibility.Header.NoReportedFeatures"
                : "ProductPage.Accessibility.Header.NoReportedFeatures.NoLearnMoreLink";
        }
    }
}
/**
 * Returns the localization key for the header template text for watchOS, based on the information available.
 *
 * This is similar to the logic for the other platforms (refer to comment of `headerTemplateLocKey` function above),
 * however only returns a subset of those template keys because:
 * - Inline linkable text is not supported on watchOS
 * - We always display text in the see all context on watchOS
 */
function watchHeaderTemplateLocKey(supportedFeatures, hasDeveloperName) {
    const isReported = isSome(supportedFeatures);
    const hasSupportedFeatures = isReported && isNotEmpty(supportedFeatures);
    if (hasSupportedFeatures) {
        if (hasDeveloperName) {
            return "AccessibilityDetails.Header.NoLearnMoreLink";
        }
        else {
            return "AccessibilityDetails.Header.NoLearnMoreLink.NoDeveloperName";
        }
    }
    else if (isReported) {
        return "ProductPage.Accessibility.Header.NoSupportedFeatures.NoLearnMoreLink";
    }
    else {
        return "ProductPage.Accessibility.Header.NoReportedFeatures.NoLearnMoreLink";
    }
}
//# sourceMappingURL=accessibility-shelves.js.map