/**
 * Created by keithpk on 4/25/17.
 */
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 * as client from "../foundation/wrappers/client";
import * as contentAttributes from "./content/attributes";
import * as content from "./content/content";
import * as sad from "./content/sad";
export function shouldFilter(objectGraph, data, type = 80894 /* Filter.All */) {
    let filter = false;
    if (type & 2 /* Filter.ThirtyTwoBit */) {
        filter = filter || shouldFilter32Bit(objectGraph, data);
    }
    if (type & 4 /* Filter.UnsupportedSystemDeletableApps */) {
        filter = filter || shouldFilterDeletableSystemApp(objectGraph, data);
    }
    if (type & 8 /* Filter.UnsupportedWatchAppOnWatchClient */) {
        filter = filter || shouldFilterUnsupportedWatchAppOnWatchClient(objectGraph, data);
    }
    if (type & 16 /* Filter.DisabledMerchandisableIAPs */) {
        filter = filter || shouldFilterMerchandisableInAppPurchase(objectGraph, data);
    }
    if (type & 32 /* Filter.LegacyApps */) {
        filter = filter || shouldFilterLegacyApps(objectGraph, data);
    }
    if (type & 64 /* Filter.LegacyProductionMacOSInstaller */) {
        filter = filter || isLegacyProductionMacOSInstaller(objectGraph, data);
    }
    if (type & 128 /* Filter.UnsupportedPlatform */) {
        filter = filter || shouldFilterUnsupportedPlatform(objectGraph, data);
    }
    if (type & 16384 /* Filter.UnsupportedPlatformForMacCharts */) {
        filter = filter || shouldFilterUnsupportedPlatformForMacCharts(objectGraph, data);
    }
    if (type & 256 /* Filter.UnsupportedPreorders */) {
        filter = filter || shouldFilterUnsupportedPreorders(objectGraph, data);
    }
    if (type & 512 /* Filter.MinimumOSRequirement */) {
        filter = filter || shouldFilterForMinimumOSRequirement(objectGraph, data);
    }
    if (type & 1024 /* Filter.SADWatchApps */) {
        filter = filter || shouldFilterSADWatchApps(objectGraph, data);
    }
    if (type & 2048 /* Filter.MinimumCompanionOSRequirement */) {
        filter = filter || shouldFilterForMinimumCompanionOSRequirement(objectGraph, data);
    }
    if (type & 4096 /* Filter.MacOSCompatibleIOSBinary */) {
        filter = filter || shouldFilterForMacOSCompatibleIOSBinary(objectGraph, data);
    }
    if (type & 8192 /* Filter.MacOSRosetta */) {
        filter = filter || shouldFilterRosetta(objectGraph, data);
    }
    if (type & 32768 /* Filter.VisionOSCompatibility */) {
        filter = filter || shouldFilterForVisionOSCompatibility(objectGraph, data);
    }
    if (type & 65536 /* Filter.SADMinimumOSRequirement */) {
        filter = filter || shouldFilterForSADMinimumOSRequirement(objectGraph, data);
    }
    return filter;
}
function shouldFilter32Bit(objectGraph, data) {
    if (objectGraph.client.isWatch) {
        // We still ship 32 bit watches and software.
        return false;
    }
    return (contentAttributes.contentAttributeAsBooleanOrFalse(objectGraph, data, "is32bitOnly") ||
        // I don't get why we need a different field for macOS, but so is life
        contentAttributes.contentAttributeAsBooleanOrFalse(objectGraph, data, "requires32bit"));
}
function shouldFilterUnsupportedWatchAppOnWatchClient(objectGraph, data) {
    return derivedData.value(data, "shouldFilterUnsupportedWatchAppOnWatchClient", () => {
        const isWatchSupported = contentAttributes.contentAttributeAsBooleanOrFalse(objectGraph, data, "isAppleWatchSupported");
        const isBundle = data.type === "app-bundles";
        if (objectGraph.host.clientIdentifier === client.watchIdentifier && !isWatchSupported && !isBundle) {
            return true;
        }
        return false;
    });
}
function shouldFilterLegacyApps(objectGraph, data) {
    return derivedData.value(data, "shouldFilterLegacyApps", () => {
        const bundleId = contentAttributes.contentAttributeAsString(objectGraph, data, "bundleId");
        if (objectGraph.client.isiOS || objectGraph.client.isVision) {
            switch (bundleId) {
                // "Find My iPhone" has been replaced by "Find My" in Yukon
                case "com.apple.mobileme.fmip1":
                    return true;
                // Old 2nd party Shortcuts is no longer available on iOS 13
                // <rdar://problem/51756700> In Search results user will see 2 Shortcuts apps
                case "is.workflow.my.app":
                    return true;
                default:
                    break;
            }
        }
        if (objectGraph.client.isVision) {
            switch (bundleId) {
                // iTunes Store is not available on visionOS
                case "com.apple.MobileStore":
                    return true;
                default:
                    break;
            }
        }
        if (objectGraph.client.isWatch) {
            switch (bundleId) {
                // "Find My Friends" has been replaced by "Find My" in Grace
                // rdar://62885564 (Find my app changes)
                case "com.apple.mobileme.fmf1":
                    return true;
                case "com.apple.findmy":
                    // "Find My" has been replaced by "Find People" in JupiterC.
                    // rdar://85616308 (2021 JS: Find People (watch app) - Filter Search and Disable Offer Button for watchOS 8.3 and above)
                    return content.isOSAtLeastVersion(objectGraph, "8.3");
                case "com.apple.findmy.findpeople":
                    // "Find My" has been replaced by "Find People" in JupiterC.
                    // Older clients should filter the new "Find People" app.
                    // rdar://85616308 (2021 JS: Find People (watch app) - Filter Search and Disable Offer Button for watchOS 8.3 and above)
                    return !content.isOSAtLeastVersion(objectGraph, "8.3");
                default:
                    break;
            }
        }
        if (objectGraph.client.isMac) {
            switch (bundleId) {
                // Facetime is now bundled into macOS
                case "com.apple.FaceTime":
                    return true;
                // These are betas of old macOS releases
                case "com.apple.InstallAssistant.Seed.macOS1013Seed1":
                case "com.apple.InstallAssistant.OSX12PublicSeed2":
                case "com.apple.InstallAssistant.OSX12CustomerSeed1":
                case "com.apple.InstallAssistant.OSX12Seed2":
                    return true;
                // These are old version of macOS server that are no longer relevant
                case "com.apple.Server.v3":
                case "com.apple.Server.v2":
                case "com.apple.Server.v1":
                    return true;
                default:
                    break;
            }
        }
        return false;
    });
}
function isLegacyProductionMacOSInstaller(objectGraph, data) {
    return derivedData.value(data, "isLegacyMacOSInstaller", () => {
        const bundleId = contentAttributes.contentAttributeAsString(objectGraph, data, "bundleId");
        const isMac = objectGraph.client.isMac;
        if (!isMac) {
            return false;
        }
        switch (bundleId) {
            // These are production releases of old OSes
            case "com.apple.InstallAssistant.ElCapitan2":
            case "com.apple.InstallAssistant.ElCapitan":
            case "com.apple.InstallAssistant.Yosemite":
            case "com.apple.InstallAssistant.Mavericks":
            case "com.apple.InstallAssistant.MountainLion":
            case "com.apple.InstallAssistant.Lion":
            case "com.apple.InstallAssistant.Sierra":
            case "com.apple.InstallAssistant.HighSierra":
            case "com.apple.InstallAssistant.Mojave":
                return true;
            default:
                break;
        }
        return false;
    });
}
/**
 * For Mac charts, we want to show Almond apps regardless of AS/Intel configuration
 * @param objectGraph The object graph reference
 * @param data The data blob representing a single application
 * @returns Whether the application should be filtered out for charts on Mac based on its available platforms
 */
function shouldFilterUnsupportedPlatformForMacCharts(objectGraph, data) {
    return derivedData.value(data, "shouldFilterUnsupportedPlatformForCharts", () => {
        if (data.type !== "apps" && data.type !== "app-bundles") {
            return false;
        }
        // All apps should be considered "supported" by the "web" client
        if (objectGraph.client.isWeb) {
            return false;
        }
        const appPlatforms = content.supportedAppPlatformsFromData(objectGraph, data);
        const supportsMacOSCompatibleIOSBinary = content.supportsMacOSCompatibleIOSBinaryFromData(objectGraph, data, true);
        const supportsVisionOSCompatibleIOSBinary = content.supportsVisionOSCompatibleIOSBinaryFromData(objectGraph, data);
        // This check purposely omits passing additional parameters to consider Rosetta for compatibility
        // because doing so would result in the app being filtered from Charts on macOS.
        return !content.buyableOnDevice(objectGraph, data, appPlatforms, objectGraph.client.deviceType, supportsMacOSCompatibleIOSBinary, supportsVisionOSCompatibleIOSBinary);
    });
}
function shouldFilterUnsupportedPlatform(objectGraph, data) {
    return derivedData.value(data, "shouldFilterUnsupportedPlatform", () => {
        if (data.type !== "apps" && data.type !== "app-bundles") {
            return false;
        }
        // All apps should be considered "supported" by the "web" client
        if (objectGraph.client.isWeb) {
            return false;
        }
        const appPlatforms = content.supportedAppPlatformsFromData(objectGraph, data);
        // rdar://83688780 (Top chart - several categories pages are missing apps)
        // For now, we will support showing almond apps for intel and AS mac while charts backend looks to enable server-side filtering.
        const supportsMacOSCompatibleIOSBinary = content.supportsMacOSCompatibleIOSBinaryFromData(objectGraph, data, objectGraph.appleSilicon.isSupportEnabled);
        const supportsVisionOSCompatibleIOSBinary = content.supportsVisionOSCompatibleIOSBinaryFromData(objectGraph, data);
        // This check purposely omits passing additional parameters to consider Rosetta for compatibility
        // because doing so would result in the app being filtered from Charts on macOS.
        return !content.buyableOnDevice(objectGraph, data, appPlatforms, objectGraph.client.deviceType, supportsMacOSCompatibleIOSBinary, supportsVisionOSCompatibleIOSBinary);
    });
}
function shouldFilterUnsupportedPreorders(objectGraph, data) {
    return derivedData.value(data, "shouldFilterUnsupportedPreordersOnPlatform", () => {
        const isPreorder = mediaAttributes.attributeAsBooleanOrFalse(data, "isPreorder");
        if (!isPreorder) {
            return false;
        }
        if (data.type !== "apps") {
            return false;
        }
        // On the web, we show preoderable apps across all device types for the browsing experience
        if (objectGraph.client.isWeb) {
            return false;
        }
        const appPlatforms = content.supportedAppPlatformsFromData(objectGraph, data);
        const supportsMacOSCompatibleIOSBinary = content.supportsMacOSCompatibleIOSBinaryFromData(objectGraph, data, objectGraph.appleSilicon.isSupportEnabled);
        const supportsVisionOSCompatibleIOSBinary = content.supportsVisionOSCompatibleIOSBinaryFromData(objectGraph, data);
        return !content.preorderableOnDevice(objectGraph, appPlatforms, objectGraph.client.deviceType, supportsMacOSCompatibleIOSBinary, supportsVisionOSCompatibleIOSBinary);
    });
}
function shouldFilterDeletableSystemApp(objectGraph, data) {
    return derivedData.value(data, "shouldFilterDeletableSystemApp", () => {
        const systemApps = sad.systemApps(objectGraph);
        if (!systemApps.isSystemAppFromData(data)) {
            return false;
        }
        const bundleId = systemApps.bundleIdFromData(data);
        const model = objectGraph.host.deviceModel;
        if (objectGraph.client.isWeb) {
            return false;
        }
        const isPhone = model.startsWith("iPhone");
        const isPad = model.startsWith("iPad");
        let countrySupportsTVApp;
        if (content.isOSAtLeastVersion(objectGraph, "12.3") || objectGraph.client.isVision) {
            // All countries support the tv app for PeaceF+ clients.
            countrySupportsTVApp = true;
        }
        else {
            countrySupportsTVApp = objectGraph.bag.isTVAppEnabled;
        }
        switch (bundleId) {
            // These apps are only available on iPhone
            case "com.apple.Bridge":
            case "com.apple.Passbook":
            case "com.apple.visionproapp":
                return !isPhone;
            // These apps are only avaliable on iPad
            case "com.apple.Photo-Booth":
                return !isPad;
            // TV.app is only enabled in the US storefront
            case "com.apple.tv":
                return !countrySupportsTVApp;
            // Videos.app everywhere else
            case "com.apple.videos":
                return countrySupportsTVApp;
            // iCloud Drive is replaced by Files on Tigris clients
            case "com.apple.iCloudDriveApp":
                return true;
            // FaceTime & Phone are not available in some Arab countries; defer to MobileGestalt
            case "com.apple.facetime":
            case "com.apple.mobilephone":
                return (!deviceHasCapability(objectGraph, "any-telephony", data) ||
                    !deviceHasCapability(objectGraph, "venice", data));
            case "com.apple.Fitness":
                if (isPad || isPhone) {
                    let isFitnessAppInstallationAllowed = false;
                    if (serverData.isDefinedNonNull(objectGraph.user.isFitnessAppInstallationAllowed)) {
                        isFitnessAppInstallationAllowed = objectGraph.user.isFitnessAppInstallationAllowed;
                    }
                    return !isFitnessAppInstallationAllowed;
                }
                else {
                    /// Should be safe to filter out on all other platforms since tvOS has it bundled and watchOS has it as Activity.
                    return true;
                }
            case "com.apple.measure":
                return !deviceHasCapability(objectGraph, "arkit", data);
            case "com.apple.Jellyfish":
                return !deviceHasCapability(objectGraph, "front-depth-camera", data);
            // Old 2nd party Shortcuts is no longer available on iOS 13
            // <rdar://problem/49929227> SAD: Filter our Shortcuts 2nd party app in App Store on iOS 13
            case "is.workflow.my.app":
                return true;
            // Find My apps are being combined in iOS 13. Filter out the existing ones
            // <rdar://problem/48297097> SAD: Filter FM apps from app store results
            case "com.apple.mobileme.fmf1":
                return true;
            case "com.apple.NanoHeartRhythm":
                return !objectGraph.client.isElectrocardiogramInstallationAllowed;
            // This app has hardware requirements we must enforce.
            // <rdar://problem/48789916> WAS: SAD: Ursa App - HW exclusion
            case "com.apple.NanoCompass.watchkitapp":
                return !deviceHasCapability(objectGraph, "magnetometer", data);
            case "com.apple.NanoOxygenSaturation.watchkitapp":
                return !objectGraph.client.isScandiumInstallationAllowed;
            case "com.apple.DeepBreathing":
                return true;
            case "com.apple.NanoRadio":
                return true;
            case "com.apple.Depth":
                return !objectGraph.client.isCharonSupported;
            case "com.apple.Mandrake":
                return !objectGraph.client.isMandrakeSupported;
            case "com.apple.GenerativePlaygroundApp":
                return !deviceHasCapability(objectGraph, "generative-model-systems", data);
            default:
                break;
        }
        return false;
    });
}
function shouldFilterMerchandisableInAppPurchase(objectGraph, data) {
    if (data.type !== "in-apps") {
        return false;
    }
    // If a contingent offer exists than do not filter
    if (serverData.isDefinedNonNullNonEmpty(serverData.asDictionary(data, "meta.contingentItemOffer"))) {
        return false;
    }
    if (serverData.isDefinedNonNullNonEmpty(serverData.asDictionary(data, "meta.discountOffer"))) {
        return false;
    }
    return !mediaAttributes.attributeAsBooleanOrFalse(data, "isMerchandisedEnabled");
}
/**
 * Returns whether an app supports at least the current version of the OS
 * @param {JSONData} data
 * @returns {boolean}
 */
function shouldFilterForMinimumOSRequirement(objectGraph, data) {
    // If the device is a phone but the app is watch-only, check that the watch version is supported.
    if (objectGraph.client.isPhone &&
        contentAttributes.contentAttributeAsBooleanOrFalse(objectGraph, data, "isStandaloneForWatchOS")) {
        const minimumWatchOSVersionString = contentAttributes.contentAttributeAsString(objectGraph, data, "minimumWatchOSVersion");
        if (!content.isActivePairedWatchOSAtLeastVersion(objectGraph, minimumWatchOSVersionString)) {
            return true;
        }
    }
    if (objectGraph.client.isWatch) {
        const minWatchOSVersion = contentAttributes.contentAttributeAsString(objectGraph, data, "minimumWatchOSVersion");
        return !content.isOSAtLeastVersion(objectGraph, minWatchOSVersion);
    }
    const minOSVersionString = content.minimumOSVersionFromData(objectGraph, data, objectGraph.appleSilicon.isSupportEnabled);
    return !content.isOSAtLeastVersion(objectGraph, minOSVersionString);
}
/**
 * Returns whether an app supports at least the current version of the companion's OS
 * @param {JSONData} data
 * @returns {boolean}
 */
function shouldFilterForMinimumCompanionOSRequirement(objectGraph, data) {
    if (objectGraph.client.deviceType !== "watch") {
        return false;
    }
    // We do not need to check the companion OS version when an app is standalone, or can run standalone.
    if (contentAttributes.contentAttributeAsBooleanOrFalse(objectGraph, data, "isStandaloneForWatchOS") ||
        contentAttributes.contentAttributeAsBooleanOrFalse(objectGraph, data, "isStandaloneWithCompanionForWatchOS")) {
        return false;
    }
    const attributePlatform = contentAttributes.bestAttributePlatformFromData(objectGraph, data);
    const minCompanionVersion = mediaPlatformAttributes.platformAttributeAsString(data, attributePlatform, "minimumOSVersion");
    return !content.isActivePairedDeviceAtLeastVersion(objectGraph, minCompanionVersion);
}
function shouldFilterSADWatchApps(objectGraph, data) {
    if (objectGraph.client.isWatch || objectGraph.client.isWeb) {
        return false;
    }
    const isFirstPartyHideableApp = mediaAttributes.attributeAsBooleanOrFalse(data, "isFirstPartyHideableApp");
    const isWatchOnlyApp = !contentAttributes.contentAttributeAsBooleanOrFalse(objectGraph, data, "isDeliveredInIOSAppForWatchOS") &&
        contentAttributes.contentAttributeAsBooleanOrFalse(objectGraph, data, "isStandaloneForWatchOS");
    return isFirstPartyHideableApp && isWatchOnlyApp;
}
function shouldFilterForMacOSCompatibleIOSBinary(objectGraph, data) {
    if (objectGraph.client.deviceType !== "mac") {
        return false; // mac only filter.
    }
    let isIOSBinaryMacOSCompatible = contentAttributes.contentAttributeAsBooleanOrFalse(objectGraph, data, "isIOSBinaryMacOSCompatible", contentAttributes.defaultAttributePlatform(objectGraph));
    // Override for News in Moltres
    if (preprocessor.GAMES_TARGET && data.id === "1066498020") {
        isIOSBinaryMacOSCompatible = true;
    }
    return isIOSBinaryMacOSCompatible && !objectGraph.appleSilicon.isSupportEnabled;
}
function shouldFilterRosetta(objectGraph, data) {
    // Only apply Rosetta filtering to macOS apps on macOS devices.
    const appPlatforms = content.supportedAppPlatformsFromData(objectGraph, data);
    if (objectGraph.client.deviceType !== "mac" || !appPlatforms.includes("mac")) {
        return false;
    }
    const isBuyable = content.isMacOSAppBuyableAndRunnableFromData(objectGraph, data, objectGraph.appleSilicon.isSupportEnabled, objectGraph.appleSilicon.isRosettaAvailable);
    return !isBuyable;
}
function shouldFilterForVisionOSCompatibility(objectGraph, data) {
    // Only apply filtering to visionOS compatible apps when running in the Vision companion app.
    if (!objectGraph.client.isCompanionVisionApp) {
        return false;
    }
    const isVisionOSCompatibleIOSBinary = mediaPlatformAttributes.platformAttributeAsBooleanOrFalse(data, "ios", "isXROSCompatible");
    const supportedAppPlatforms = content.supportedAppPlatformsFromData(objectGraph, data);
    const isVisionOSBinary = supportedAppPlatforms.indexOf("vision") > -1;
    return !isVisionOSBinary && !isVisionOSCompatibleIOSBinary;
}
/**
 * Checks whether filtering should be applied due to minimum OS, specifically for a SAD app. This check
 * exists separately to `shouldFilterForMinimumOSRequirement` as offer buttons aren't typically disabled
 * for apps that don't meet the minOS, but they should be for SAD apps.
 *
 * @param objectGraph Current object graph
 * @param data The product data
 * @returns True if the product should be filtered
 */
function shouldFilterForSADMinimumOSRequirement(objectGraph, data) {
    const systemApps = sad.systemApps(objectGraph);
    if (!systemApps.isSystemAppFromData(data)) {
        return false;
    }
    return shouldFilterForMinimumOSRequirement(objectGraph, data);
}
/**
 * Checks whether a device has a given capability.
 * @param objectGraph Current object graph
 * @param capability The capability string
 * @param data The data related to the product
 * @returns True if the device supports the capability.
 */
function deviceHasCapability(objectGraph, capability, data) {
    const supportsVisionOSCompatibleIOSBinary = content.supportsVisionOSCompatibleIOSBinaryFromData(objectGraph, data);
    return objectGraph.client.deviceHasCapabilitiesIncludingCompatibilityCheckIsVisionOSCompatibleIOSApp([capability], supportsVisionOSCompatibleIOSBinary);
}
//# sourceMappingURL=filtering.js.map