import { isNothing, isSome } from "@jet/environment/types/optional";
import * as derivedData from "../../foundation/json-parsing/derived-data";
import * as serverData from "../../foundation/json-parsing/server-data";
import * as mediaAttributes from "../../foundation/media/attributes";
import * as mediaPlatformAttributes from "../../foundation/media/platform-attributes";
import { variantAttributeForKey } from "../product-page/product-page-variants";
import * as contentDeviceFamily from "./device-family";
/**
 * Retrieve the specified attribute from the data, coercing it to a JSONData dictionary
 *
 * @param data The data from which to retrieve the attribute.
 * @param attributePath The path of the attribute.
 * @param attributePlatform The specific platform attribute to get content for. Omit to infer from the data's structure.
 * @param defaultValue The object to return if the path search fails.
 * @returns The dictionary of data
 */
export function contentAttributeAsDictionary(objectGraph, data, attributePath, attributePlatform, defaultValue) {
    if (!attributePlatform) {
        attributePlatform = bestAttributePlatformFromData(objectGraph, data);
    }
    if (isNothing(attributePlatform)) {
        return null;
    }
    let value = mediaPlatformAttributes.platformAttributeAsDictionary(data, attributePlatform, attributePath);
    if (!value) {
        value = mediaAttributes.attributeAsDictionary(data, attributePath, defaultValue);
    }
    return value;
}
/**
 * Retrieve the specified attribute from the data as an array, coercing to an empty array if the object is not an array.
 *
 * @param data The data from which to retrieve the attribute.
 * @param attributePath The path of the attribute.
 * @param attributePlatformOverride An override platform, from which to fetch the attribute.
 * @returns {any[]} The attribute value as an array.
 */
export function contentAttributeAsArrayOrEmpty(objectGraph, data, attributePath, attributePlatformOverride = undefined) {
    const attributePlatform = attributePlatformOverride !== null && attributePlatformOverride !== void 0 ? attributePlatformOverride : bestAttributePlatformFromData(objectGraph, data);
    if (isNothing(attributePlatform)) {
        return [];
    }
    let value = mediaPlatformAttributes.platformAttributeAsArrayOrEmpty(data, attributePlatform, attributePath);
    if (serverData.isNullOrEmpty(value)) {
        value = mediaAttributes.attributeAsArrayOrEmpty(data, attributePath);
    }
    return value;
}
/**
 * Retrieve the specified attribute from the data as an array.
 *
 * @param data The data from which to retrieve the attribute.
 * @param attributePath The path of the attribute.
 * @param attributePlatformOverride An override platform, from which to fetch the attribute.
 * @returns {any[]} The attribute value as an array.
 */
export function contentAttributeAsArray(objectGraph, data, attributePath, attributePlatformOverride = undefined) {
    const attributePlatform = attributePlatformOverride !== null && attributePlatformOverride !== void 0 ? attributePlatformOverride : bestAttributePlatformFromData(objectGraph, data);
    if (isNothing(attributePlatform)) {
        return null;
    }
    let value = mediaPlatformAttributes.platformAttributeAsArray(data, attributePlatform, attributePath);
    if (isNothing(value)) {
        value = mediaAttributes.attributeAsArray(data, attributePath);
    }
    return value;
}
/**
 * Retrieve the specified attribute from the data as a string.
 *
 * @param data The data from which to retrieve the attribute.
 * @param attributePath The object path for the attribute.
 * @param attributePlatformOverride An override platform, from which to fetch the attribute.
 * @param policy The validation policy to use when resolving this value.
 * @returns {string} The attribute value as a string.
 */
export function contentAttributeAsString(objectGraph, data, attributePath, attributePlatformOverride = undefined, policy = "coercible") {
    let value;
    const attributePlatform = attributePlatformOverride !== null && attributePlatformOverride !== void 0 ? attributePlatformOverride : bestAttributePlatformFromData(objectGraph, data);
    if (isSome(attributePlatform)) {
        value = mediaPlatformAttributes.platformAttributeAsString(data, attributePlatform, attributePath, policy);
    }
    if (!value) {
        value = mediaAttributes.attributeAsString(data, attributePath, policy);
    }
    return value;
}
/**
 * Retrieve the specified attribute from the data as a boolean.
 *
 * @param data The data from which to retrieve the attribute.
 * @param attributePath The path of the attribute.
 * @param policy The validation policy to use when resolving this value.
 * @returns {boolean} The attribute value as a boolean.
 */
export function contentAttributeAsBoolean(objectGraph, data, attributePath, attributePlatform, policy = "coercible") {
    if (!attributePlatform) {
        attributePlatform = bestAttributePlatformFromData(objectGraph, data);
    }
    if (isNothing(attributePlatform)) {
        return null;
    }
    let value = mediaPlatformAttributes.platformAttributeAsBoolean(data, attributePlatform, attributePath, policy);
    if (serverData.isNull(value)) {
        value = mediaAttributes.attributeAsBoolean(data, attributePath, policy);
    }
    return value;
}
/**
 * Retrieve the specified attribute from the data as a boolean, which will be `false` if the attribute does not exist.
 *
 * @param data The data from which to retrieve the attribute.
 * @param attributePath The path of the attribute.
 * @param attributePlatform The specific platform attribute to get content for. Omit to infer from the data's structure.
 * @returns {boolean} The attribute value as a boolean, coercing to `false` if the value is not present..
 */
export function contentAttributeAsBooleanOrFalse(objectGraph, data, attributePath, attributePlatform) {
    if (!attributePlatform) {
        attributePlatform = bestAttributePlatformFromData(objectGraph, data);
    }
    if (isNothing(attributePlatform)) {
        return false;
    }
    let value = mediaPlatformAttributes.platformAttributeAsBoolean(data, attributePlatform, attributePath);
    if (serverData.isNull(value)) {
        value = mediaAttributes.attributeAsBooleanOrFalse(data, attributePath);
    }
    return value;
}
/**
 * Retrieve the specified attribute from the data as a number.
 *
 * @param data The data from which to retrieve the attribute.
 * @param attributePath The path of the attribute.
 * @param policy The validation policy to use when resolving this value.
 * @returns {boolean} The attribute value as a number.
 */
export function contentAttributeAsNumber(objectGraph, data, attributePath, policy = "coercible") {
    const attributePlatform = bestAttributePlatformFromData(objectGraph, data);
    if (isNothing(attributePlatform)) {
        return null;
    }
    let value = mediaPlatformAttributes.platformAttributeAsNumber(data, attributePlatform, attributePath, policy);
    if (serverData.isNull(value)) {
        value = mediaAttributes.attributeAsNumber(data, attributePath);
    }
    return value;
}
/**
 * Computes the best attribute platform for a given piece of content
 *
 * @param {Data} data The media API data representing the content
 * @returns {AttributePlatform}
 */
export function bestAttributePlatformFromData(objectGraph, data, clientIdentifierOverride) {
    const baseCacheKey = "bestAttributePlatformFromData";
    const cacheKey = isSome(clientIdentifierOverride) ? `${baseCacheKey}.${clientIdentifierOverride}` : baseCacheKey;
    return derivedData.value(data, cacheKey, () => {
        const isIOSOnly = contentDeviceFamily.dataOnlyHasDeviceFamilies(objectGraph, data, ["iphone", "ipad", "ipod"], true);
        const isTvOnly = contentDeviceFamily.dataOnlyHasDeviceFamily(objectGraph, data, "tvos");
        const isMacOnly = contentDeviceFamily.dataOnlyHasDeviceFamily(objectGraph, data, "mac");
        const isWatchOnly = contentDeviceFamily.dataOnlyHasDeviceFamily(objectGraph, data, "watch");
        const isVisionOnly = contentDeviceFamily.dataOnlyHasDeviceFamily(objectGraph, data, "realityDevice");
        // 1. The data is for a single platform only.
        let dedicatedPlatform = null;
        if (isTvOnly) {
            dedicatedPlatform = "appletvos";
        }
        else if (isMacOnly) {
            dedicatedPlatform = "osx";
        }
        else if (isIOSOnly) {
            dedicatedPlatform = "ios";
        }
        else if (isWatchOnly) {
            dedicatedPlatform = "watch";
        }
        else if (isVisionOnly) {
            dedicatedPlatform = "xros";
        }
        if (!serverData.isNull(dedicatedPlatform)) {
            return dedicatedPlatform;
        }
        // 2. Loop through our preferred ordering of platforms and use the first one that has platformAttributes present.
        const alternatePlatforms = defaultAttributePlatformOrdering(objectGraph, clientIdentifierOverride);
        for (const candidatePlatform of alternatePlatforms) {
            if (mediaPlatformAttributes.hasPlatformAttribute(data, candidatePlatform)) {
                return candidatePlatform;
            }
        }
        // 3. Catch-All
        return defaultAttributePlatform(objectGraph);
    });
}
/**
 * Computes the best attribute platform for a given Media API Marketplace
 * response. Since Marketplace responses don't contain a top-level
 * `deviceFamilies` property, this employs an alternative method from
 * `bestAttributePlatformFromData()` to get the attribute platform.
 *
 * @param objectGraph The App Store object graph
 * @param data The Media API Marketplace response to search for an attribute platform.
 * @returns The most appropriate attribute platform available for the current client.
 */
export function bestAttributePlatformFromMarketplaceData(objectGraph, data) {
    // 1. Iterate through the client's preferred platform ordering until we
    // find the first one present in the response.
    const preferredAttributePlatforms = defaultAttributePlatformOrdering(objectGraph);
    for (const attributePlatform of preferredAttributePlatforms) {
        const versionsAttributes = contentAttributeAsDictionary(objectGraph, data, "versionAttributes", attributePlatform);
        if (serverData.isDefinedNonNullNonEmpty(versionsAttributes)) {
            return attributePlatform;
        }
    }
    // 2. Catch-All
    return defaultAttributePlatform(objectGraph);
}
/**
 * The default attribute platform for the current client
 */
export function defaultAttributePlatform(objectGraph) {
    var _a;
    if ((_a = objectGraph.activeIntent) === null || _a === void 0 ? void 0 : _a.attributePlatform) {
        return objectGraph.activeIntent.attributePlatform;
    }
    switch (objectGraph.client.deviceType) {
        case "phone":
        case "pad":
            return "ios";
        case "tv":
            return "appletvos";
        case "mac":
            return "osx";
        case "watch":
            return "watch";
        case "vision":
            return "xros";
        default:
            return null;
    }
}
/**
 * The preferred ordering to use given our default platform.
 */
function defaultAttributePlatformOrdering(objectGraph, clientIdentifierOverride) {
    const defaultPlatform = defaultAttributePlatform(objectGraph);
    if (defaultPlatform === null) {
        // If the `"web"` client is active and there is not an "active intent" to
        // inform a default platform, fall back to a hard-coded ordering
        if (objectGraph.client.isWeb) {
            return ["ios", "osx", "xros", "watch", "appletvos"];
        }
        else {
            return [];
        }
    }
    switch (defaultPlatform) {
        case "ios":
            if (clientIdentifierOverride === "VisionAppStore" /* ClientIdentifier.VisionAppStore */ ||
                clientIdentifierOverride === "com.apple.visionproapp" /* ClientIdentifier.VisionCompanion */) {
                return ["xros", "ios", "appletvos", "osx"];
            }
            else {
                return ["ios", "appletvos", "osx", "xros"];
            }
        case "osx":
            return ["osx", "ios", "appletvos", "xros"];
        case "appletvos":
            return ["appletvos", "ios", "osx", "xros"];
        case "watch":
            // Per Hiren Kotadia on 2019-2-26, watch platform attributes will always be under ios.
            // We're going to promote ios to the head of the search list to speed up Media API
            // response parsing. We'll keep watch as #2 in the list so that if this changes in
            // the future, it should mostly just work. -km
            return ["ios", "watch", "osx", "xros"];
        case "xros":
            return ["xros", "ios", "appletvos", "osx"];
        default:
            return [defaultPlatform];
    }
}
// region Variant Attributes
/**
 * Retrieve the attribute for a specific platform's variant attribute as a dictionary, from custom attributes or standard attributes.
 * @param data Data to get attribute for.
 * @param productVariantData Variant data to use when finding item.
 * @param attributeKey The key to fetch in platform attributes. May be converted to custom attribute key.
 * @param attributePlatform The platform to fetch attribute for. Defaults to current platform if unspecified.
 */
export function customAttributeAsDictionary(objectGraph, data, productVariantData, attributeKey, attributePlatform) {
    // Use `customAttributes.${customAttributeKey}` for platform if present
    const customAttributeKey = mediaAttributes.attributeKeyAsCustomAttributeKey(attributeKey);
    if (isNothing(customAttributeKey)) {
        return null;
    }
    const customAttributes = contentAttributeAsDictionary(objectGraph, data, "customAttributes", attributePlatform);
    const allowNondefaultTreatmentInNondefaultPage = mediaAttributes.attributeAllowsNonDefaultTreatmentInNonDefaultPage(customAttributeKey);
    const customAttribute = variantAttributeForKey(objectGraph, customAttributes, productVariantData, customAttributeKey, allowNondefaultTreatmentInNondefaultPage);
    if (serverData.isDefinedNonNullNonEmpty(customAttribute)) {
        return serverData.asDictionary(customAttribute);
    }
    // Otherwise, use `${attributeKey}` for platform.
    return contentAttributeAsDictionary(objectGraph, data, attributeKey, attributePlatform);
}
/**
 * Retrieve the attribute for a specific platform's variant attribute as a dictionary, from custom attributes or standard attributes.
 * @param data Data to get attribute for.
 * @param productVariantData Variant data to use when finding item.
 * @param attributeKey The key to fetch in platform attributes when custom attributes are not present.
 * @param attributePlatform The platform to fetch attribute for. Defaults to current platform if unspecified.
 */
export function customAttributeAsString(objectGraph, data, productVariantData, attributeKey, attributePlatform) {
    // Use `customAttributes.${customAttributeKey}` for platform if present
    const customAttributeKey = mediaAttributes.attributeKeyAsCustomAttributeKey(attributeKey);
    if (isNothing(customAttributeKey)) {
        return null;
    }
    const customAttributes = contentAttributeAsDictionary(objectGraph, data, "customAttributes", attributePlatform);
    const allowNondefaultTreatmentInNondefaultPage = mediaAttributes.attributeAllowsNonDefaultTreatmentInNonDefaultPage(customAttributeKey);
    const customAttribute = variantAttributeForKey(objectGraph, customAttributes, productVariantData, customAttributeKey, allowNondefaultTreatmentInNondefaultPage);
    if (serverData.isDefinedNonNullNonEmpty(customAttribute)) {
        return serverData.asString(customAttribute);
    }
    // Otherwise, use `${attributeKey}` for platform.
    return contentAttributeAsString(objectGraph, data, attributeKey);
}
// endregion
//# sourceMappingURL=attributes.js.map