/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class ServerConfigurationFixtures: NSObject {
  /// A default configuration with valid inputs. This is the same default configuration used in production code
  static var defaultConfiguration: _ServerConfiguration {
    _ServerConfiguration.defaultServerConfiguration(forAppID: "1.0")
  }

  /// A default configuration with custom values passed by dictionary.
  /// To use: Include a dictionary with the keys and values you want to override on the default configuration
  class func configuration( // swiftlint:disable:this cyclomatic_complexity
    withDictionary dict: [String: Any]
  ) -> _ServerConfiguration {
    var loginTooltipEnabled = defaultConfiguration.isLoginTooltipEnabled
    if dict["loginTooltipEnabled"] != nil {
      loginTooltipEnabled = dict["loginTooltipEnabled"] as? Int != 0
    }
    var advertisingIDEnabled = defaultConfiguration.isAdvertisingIDEnabled
    if dict["advertisingIDEnabled"] != nil {
      advertisingIDEnabled = dict["advertisingIDEnabled"] as? Int != 0
    }
    var implicitLoggingEnabled = defaultConfiguration.isImplicitLoggingSupported
    if dict["implicitLoggingEnabled"] != nil {
      implicitLoggingEnabled = dict["implicitLoggingEnabled"] as? Int != 0
    }
    var implicitPurchaseLoggingEnabled = defaultConfiguration.isImplicitPurchaseLoggingSupported
    if dict["implicitPurchaseLoggingEnabled"] != nil {
      implicitPurchaseLoggingEnabled = dict["implicitPurchaseLoggingEnabled"] as? Int != 0
    }
    var codelessEventsEnabled = defaultConfiguration.isCodelessEventsEnabled
    if dict["codelessEventsEnabled"] != nil {
      codelessEventsEnabled = dict["codelessEventsEnabled"] as? Int != 0
    }
    var uninstallTrackingEnabled = defaultConfiguration.isUninstallTrackingEnabled
    if dict["uninstallTrackingEnabled"] != nil {
      uninstallTrackingEnabled = dict["uninstallTrackingEnabled"] as? Int != 0
    }

    var smartLoginOptions = defaultConfiguration.smartLoginOptions
    if let rawValue = dict["smartLoginOptions"] as? UInt {
      smartLoginOptions = FBSDKServerConfigurationSmartLoginOptions(rawValue: rawValue)
    }

    var defaults = defaultConfiguration.isDefaults
    if let dictDefaults = dict["defaults"] {
      if let intDefaults = dictDefaults as? Int {
        defaults = intDefaults != 0
      } else if let boolDefaults = dictDefaults as? Bool {
        defaults = boolDefaults
      }
    }

    let appID = dict["appID"] as? String ?? defaultConfiguration.appID
    let appName = dict["appName"] as? String ?? defaultConfiguration.appName
    let loginTooltipText = dict["loginTooltipText"] as? String ?? defaultConfiguration.loginTooltipText
    let defaultShareMode = dict["defaultShareMode"] as? String ?? defaultConfiguration.defaultShareMode
    let dialogConfigurations = defaultConfiguration.dialogConfigurations()
      ?? (dict["dialogConfigurations"] as? [String: Any])
    let dialogFlows = dict["dialogFlows"] as? [String: Any] ?? defaultConfiguration.dialogFlows()
    let timestamp = dict["timestamp"] as? Date ?? defaultConfiguration.timestamp
    let errorConfiguration = dict["errorConfiguration"] as? _ErrorConfiguration
      ?? defaultConfiguration.errorConfiguration

    var sessionTimeoutInterval = defaultConfiguration.sessionTimeoutInterval
    if let intInterval = dict["sessionTimeoutInterval"] as? Int {
      sessionTimeoutInterval = TimeInterval(Double(intInterval))
    } else if let doubleInterval = dict["sessionTimeoutInterval"] as? Double {
      sessionTimeoutInterval = TimeInterval(doubleInterval)
    }

    let loggingToken = dict["loggingToken"] as? String ?? defaultConfiguration.loggingToken
    let smartLoginBookmarkIconURL = (dict["smartLoginBookmarkIconURL"] as? URL)
      ?? defaultConfiguration.smartLoginBookmarkIconURL
    let smartLoginMenuIconURL = dict["smartLoginMenuIconURL"] as? URL ?? defaultConfiguration.smartLoginMenuIconURL
    let updateMessage = dict["updateMessage"] as? String ?? defaultConfiguration.updateMessage
    let eventBindings = dict["eventBindings"] as? [[String: Any]] ?? defaultConfiguration.eventBindings
    let restrictiveParams = dict["restrictiveParams"] as? [String: Any] ?? defaultConfiguration.restrictiveParams
    let AAMRules = dict["aamRules"] as? [String: Any] ?? defaultConfiguration.aamRules
    // swiftlint:disable:next line_length
    let suggestedEventsSetting = dict["suggestedEventsSetting"] as? [String: Any] ?? defaultConfiguration.suggestedEventsSetting
    let protectedModeRules = dict["protectedModeRules"] as? [String: Any] ?? defaultConfiguration.protectedModeRules

    return _ServerConfiguration(
      appID: appID,
      appName: appName,
      loginTooltipEnabled: loginTooltipEnabled,
      loginTooltipText: loginTooltipText,
      defaultShareMode: defaultShareMode,
      advertisingIDEnabled: advertisingIDEnabled,
      implicitLoggingEnabled: implicitLoggingEnabled,
      implicitPurchaseLoggingEnabled: implicitPurchaseLoggingEnabled,
      codelessEventsEnabled: codelessEventsEnabled,
      uninstallTrackingEnabled: uninstallTrackingEnabled,
      dialogConfigurations: dialogConfigurations,
      dialogFlows: dialogFlows,
      timestamp: timestamp,
      errorConfiguration: errorConfiguration,
      sessionTimeoutInterval: sessionTimeoutInterval,
      defaults: defaults,
      loggingToken: loggingToken,
      smartLoginOptions: smartLoginOptions,
      smartLoginBookmarkIconURL: smartLoginBookmarkIconURL,
      smartLoginMenuIconURL: smartLoginMenuIconURL,
      updateMessage: updateMessage,
      eventBindings: eventBindings,
      restrictiveParams: restrictiveParams,
      aamRules: AAMRules,
      suggestedEventsSetting: suggestedEventsSetting,
      protectedModeRules: protectedModeRules
    )
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestAccessTokenExpirer: NSObject, _AccessTokenExpiring {}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
final class TestAdvertiserIDProvider: NSObject, _AdvertiserIDProviding {
  var advertiserID: String?
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import TestTools

@objcMembers
final class TestAEMManager: _AutoSetup {

  var enabled = false
  var proxyEnabled = false
  var autoSetupStatus = false
  var source: String?

  // swiftlint:disable:next function_parameter_count
  func configure(
    swizzler: _Swizzling.Type,
    reporter aemReporter: FBSDKCoreKit._AEMReporterProtocol.Type,
    eventLogger: EventLogging,
    crashHandler: CrashHandlerProtocol,
    featureChecker: _FeatureDisabling,
    appEventsUtility: _AppEventsUtilityProtocol
  ) {}

  func enable(_ proxyEnabled: Bool) {
    enabled = true
    self.proxyEnabled = proxyEnabled
  }

  func logAutoSetupStatus(_ optin: Bool, source: String) {
    autoSetupStatus = optin
    self.source = source
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation
import UIKit

// swiftformat:disable indent
@objcMembers
final class TestAEMReporter: NSObject, _AEMReporterProtocol {

  static var enableWasCalled = false
  static var setConversionFilteringEnabledWasCalled = false
  static var capturedConversionFilteringEnabled = false
  static var setCatalogMatchingEnabledWasCalled = false
  static var capturedCatalogMatchingEnabled = false
  static var setAdvertiserRuleMatchInServerEnabledWasCalled = false
  static var capturedAdvertiserRuleMatchInServerEnabled = false
  static var capturedEvent: String?
  static var capturedCurrency: String?
  static var capturedValue: NSNumber?
  static var capturedParameters: [String: Any]?

  static func enable() {
    enableWasCalled = true
  }

  static func recordAndUpdate(
    event: String,
    currency: String?,
    value: NSNumber?,
    parameters: [String: Any]?
  ) {
    capturedEvent = event
    capturedCurrency = currency
    capturedValue = value
    capturedParameters = parameters
  }

  static func setConversionFilteringEnabled(_ enabled: Bool) {
    setConversionFilteringEnabledWasCalled = true
    capturedConversionFilteringEnabled = enabled
  }

  static func setCatalogMatchingEnabled(_ enabled: Bool) {
    setCatalogMatchingEnabledWasCalled = true
    capturedCatalogMatchingEnabled = enabled
  }

  static func setAdvertiserRuleMatchInServerEnabled(_ enabled: Bool) {
    setAdvertiserRuleMatchInServerEnabledWasCalled = true
    capturedAdvertiserRuleMatchInServerEnabled = enabled
  }

  static func handle(_ url: URL?) {}

  static func reset() {
    enableWasCalled = false
    setConversionFilteringEnabledWasCalled = false
    capturedConversionFilteringEnabled = false
    setCatalogMatchingEnabledWasCalled = false
    capturedCatalogMatchingEnabled = false
    capturedEvent = nil
    capturedCurrency = nil
    capturedValue = nil
    capturedParameters = nil
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit

final class TestAppEventParametersExtractor: _AppEventParametersExtracting {
  func activityParametersDictionary(
    forEvent eventCategory: String,
    shouldAccessAdvertisingID: Bool,
    userID: String?,
    userData: String?
  ) -> NSMutableDictionary {
    [:]
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation
import UIKit

// swiftformat:disable indent
@objcMembers
final class TestAppEvents: TestEventLogger,
                           _SourceApplicationTracking,
                           _AppEventsConfiguring,
                           _ApplicationActivating,
                           _ApplicationLifecycleObserving,
                           _ApplicationStateSetting {
  // swiftformat:enable indent
  var wasActivateAppCalled = false
  var wasStartObservingApplicationLifecycleNotificationsCalled = false
  var capturedApplicationState: UIApplication.State = .inactive
  var wasRegisterAutoResetSourceApplicationCalled = false
  var capturedSetSourceApplication: String?
  var capturedSetSourceApplicationURL: URL?
  var capturedCodelessIndexer: _CodelessIndexing.Type?

  func activateApp() {
    wasActivateAppCalled = true
  }

  func startObservingApplicationLifecycleNotifications() {
    wasStartObservingApplicationLifecycleNotificationsCalled = true
  }

  func setApplicationState(_ state: UIApplication.State) {
    capturedApplicationState = state
  }

  var capturedConfigureGateKeeperManager: _GateKeeperManaging.Type?
  var capturedConfigureAppEventsConfigurationProvider: _AppEventsConfigurationProviding?
  var capturedConfigureServerConfigurationProvider: _ServerConfigurationProviding?
  var capturedConfigureGraphRequestFactory: GraphRequestFactoryProtocol?
  var capturedConfigureFeatureChecker: FeatureChecking?
  var capturedConfigurePrimaryDataStore: DataPersisting?
  var capturedConfigureLogger: Logging.Type?
  var capturedConfigureSettings: SettingsProtocol?
  var capturedConfigurePaymentObserver: _PaymentObserving?
  var capturedConfigureTimeSpentRecorder: (_SourceApplicationTracking & _TimeSpentRecording)?
  var capturedConfigureAppEventsStateStore: _AppEventsStatePersisting?
  var capturedConfigureEventDeactivationParameterProcessor: _AppEventsParameterProcessing?
  var capturedConfigureProtectedModeManager: _AppEventsParameterProcessing?
  var capturedConfigureMACARuleMatchingManager: MACARuleMatching?
  var capturedConfigureRestrictiveDataFilterParameterProcessor: _AppEventsParameterProcessing?
  var capturedConfigureATEPublisherFactory: _ATEPublisherCreating?
  var capturedConfigureAppEventsStateProvider: _AppEventsStateProviding?
  var capturedConfigureSwizzler: _Swizzling.Type?
  var capturedAdvertiserIDProvider: _AdvertiserIDProviding?
  var capturedOnDeviceMLModelManager: _EventProcessing?
  var capturedMetadataIndexer: _MetadataIndexing?
  var capturedSKAdNetworkReporter: _AppEventsReporter?
  var capturedUserDataStore: _UserDataPersisting?
  var capturedAEMReporter: _AEMReporterProtocol.Type?
  // swiftlint:disable:next line_length
  var capturedAppEventsUtility: (_AppEventDropDetermining & _AppEventParametersExtracting & _AppEventsUtilityProtocol & _LoggingNotifying)?
  var capturedInternalUtility: InternalUtilityProtocol?
  var capturedCAPIReporter: CAPIReporter?

  // swiftlint:disable:next function_parameter_count
  func configure(
    gateKeeperManager: _GateKeeperManaging.Type,
    appEventsConfigurationProvider: _AppEventsConfigurationProviding,
    serverConfigurationProvider: _ServerConfigurationProviding,
    graphRequestFactory: GraphRequestFactoryProtocol,
    featureChecker: FeatureChecking,
    primaryDataStore: DataPersisting,
    logger: Logging.Type,
    settings: SettingsProtocol,
    paymentObserver: _PaymentObserving,
    timeSpentRecorder: _SourceApplicationTracking & _TimeSpentRecording,
    appEventsStateStore: _AppEventsStatePersisting,
    eventDeactivationParameterProcessor: _AppEventsParameterProcessing,
    restrictiveDataFilterParameterProcessor: _AppEventsParameterProcessing,
    atePublisherFactory: _ATEPublisherCreating,
    appEventsStateProvider: _AppEventsStateProviding,
    advertiserIDProvider: _AdvertiserIDProviding,
    userDataStore: _UserDataPersisting,
    // swiftlint:disable:next line_length
    appEventsUtility: _AppEventDropDetermining & _AppEventParametersExtracting & _AppEventsUtilityProtocol & _LoggingNotifying,
    internalUtility: InternalUtilityProtocol,
    capiReporter: CAPIReporter,
    protectedModeManager: _AppEventsParameterProcessing,
    macaRuleMatchingManager: MACARuleMatching
  ) {
    capturedConfigureGateKeeperManager = gateKeeperManager
    capturedConfigureAppEventsConfigurationProvider = appEventsConfigurationProvider
    capturedConfigureServerConfigurationProvider = serverConfigurationProvider
    capturedConfigureGraphRequestFactory = graphRequestFactory
    capturedConfigureFeatureChecker = featureChecker
    capturedConfigurePrimaryDataStore = primaryDataStore
    capturedConfigureLogger = logger
    capturedConfigureSettings = settings
    capturedConfigurePaymentObserver = paymentObserver
    capturedConfigureTimeSpentRecorder = timeSpentRecorder
    capturedConfigureAppEventsStateStore = appEventsStateStore
    capturedConfigureEventDeactivationParameterProcessor = eventDeactivationParameterProcessor
    capturedConfigureRestrictiveDataFilterParameterProcessor = restrictiveDataFilterParameterProcessor
    capturedConfigureATEPublisherFactory = atePublisherFactory
    capturedConfigureAppEventsStateProvider = appEventsStateProvider
    capturedAdvertiserIDProvider = advertiserIDProvider
    capturedUserDataStore = userDataStore
    capturedAppEventsUtility = appEventsUtility
    capturedInternalUtility = internalUtility
    capturedCAPIReporter = capiReporter
    capturedConfigureProtectedModeManager = protectedModeManager
    capturedConfigureMACARuleMatchingManager = macaRuleMatchingManager
  }

  // swiftlint:disable:next function_parameter_count
  func configureNonTVComponents(
    onDeviceMLModelManager modelManager: _EventProcessing,
    metadataIndexer: _MetadataIndexing,
    skAdNetworkReporter: _AppEventsReporter?,
    codelessIndexer: _CodelessIndexing.Type,
    swizzler: _Swizzling.Type,
    aemReporter: _AEMReporterProtocol.Type
  ) {
    capturedOnDeviceMLModelManager = modelManager
    capturedMetadataIndexer = metadataIndexer
    capturedSKAdNetworkReporter = skAdNetworkReporter
    capturedCodelessIndexer = codelessIndexer
    capturedConfigureSwizzler = swizzler
    capturedAEMReporter = aemReporter
  }

  // MARK: - Source Application Tracking

  func setSourceApplication(_ sourceApplication: String?, open url: URL?) {
    capturedSetSourceApplication = sourceApplication
    capturedSetSourceApplicationURL = url
  }

  func setSourceApplication(_ sourceApplication: String?, isFromAppLink: Bool) {
    // TODO: Implement when we add coverage for MeasurementEventListener
  }

  func registerAutoResetSourceApplication() {
    wasRegisterAutoResetSourceApplicationCalled = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestAppEventsConfiguration: NSObject, _AppEventsConfigurationProtocol {
  static var stubbedDefaultConfiguration: TestAppEventsConfiguration?

  var defaultATEStatus: AdvertisingTrackingStatus = .unspecified
  var advertiserIDCollectionEnabled = false
  var eventCollectionEnabled = false

  init(
    defaultATEStatus: AdvertisingTrackingStatus = .unspecified,
    advertiserIDCollectionEnabled: Bool = false,
    eventCollectionEnabled: Bool = false
  ) {
    self.defaultATEStatus = defaultATEStatus
    self.advertiserIDCollectionEnabled = advertiserIDCollectionEnabled
    self.eventCollectionEnabled = eventCollectionEnabled
  }

  required init(json dict: [String: Any]?) {}

  static func `default`() -> Self {
    guard let stubbed = stubbedDefaultConfiguration as? Self else {
      fatalError("Must have a default configuration")
    }
    return stubbed
  }

  static func reset() {
    stubbedDefaultConfiguration = nil
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestAppEventsConfigurationProvider: NSObject, _AppEventsConfigurationProviding {
  var stubbedConfiguration: _AppEventsConfigurationProtocol?
  var didRetrieveCachedConfiguration = false
  var firstCapturedBlock: _AppEventsConfigurationProvidingBlock?
  var lastCapturedBlock: _AppEventsConfigurationProvidingBlock?

  var cachedAppEventsConfiguration: _AppEventsConfigurationProtocol {
    guard let configuration = stubbedConfiguration else {
      fatalError("A cached configuration is required")
    }
    didRetrieveCachedConfiguration = true
    return configuration
  }

  func loadAppEventsConfiguration(_ block: @escaping _AppEventsConfigurationProvidingBlock) {
    if firstCapturedBlock == nil {
      firstCapturedBlock = block
    }
    lastCapturedBlock = block
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit

final class TestAppEventsDropDeterminer: _AppEventDropDetermining {
  var shouldDropAppEvents = false
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
final class TestAppEventsParameterProcessor: NSObject, _AppEventsParameterProcessing, _EventsProcessing {
  var enableWasCalled = false
  var capturedParameters: [AppEvents.ParameterName: Any]?
  var capturedEventName: AppEvents.Name?
  var capturedEvents: [[String: Any]]?

  func enable() {
    enableWasCalled = true
  }

  func processParameters(
    _ parameters: [AppEvents.ParameterName: Any]?,
    eventName: AppEvents.Name?
  ) -> [AppEvents.ParameterName: Any]? {
    capturedParameters = parameters
    capturedEventName = eventName
    return parameters
  }

  func processEvents(_ events: NSMutableArray) {
    capturedEvents = events.copy() as? [[String: Any]]
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestAppEventsReporter: NSObject, _AppEventsReporter {
  var enableWasCalled = false
  var capturedEvent: String?
  var capturedCurrency: String?
  var capturedValue: NSNumber?
  var capturedParameters: [String: Any]?

  func enable() {
    enableWasCalled = true
  }

  func recordAndUpdate(event: String, currency: String?, value: NSNumber?, parameters: [String: Any]?) {
    capturedEvent = event
    capturedCurrency = currency
    capturedValue = value
    capturedParameters = parameters
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestAppEventsState: _AppEventsState {
  var capturedEventDictionary: [String: Any]?
  var capturedIsImplicit = false
  var isAddEventCalled = false

  override init(token: String?, appID: String?) {
    super.init(token: token, appID: appID)
  }

  required init?(coder: NSCoder) {
    super.init(coder: coder)
  }

  override func addEvent(_ eventDictionary: [String: Any], isImplicit: Bool) {
    capturedEventDictionary = eventDictionary
    capturedIsImplicit = isImplicit
    isAddEventCalled = true

    super.addEvent(eventDictionary, isImplicit: isImplicit)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestAppEventsStateProvider: NSObject, _AppEventsStateProviding {
  var state: TestAppEventsState?
  var capturedTokenString: String?
  var capturedAppID: String?
  var isCreateStateCalled = false

  func createState(tokenString: String, appID: String) -> _AppEventsState {
    isCreateStateCalled = true
    capturedTokenString = tokenString
    capturedAppID = appID
    state = TestAppEventsState(token: tokenString, appID: appID)
    return state! // swiftlint:disable:this force_unwrapping
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestAppEventsStateStore: NSObject, _AppEventsStatePersisting {
  var capturedPersistedState: [Any] = []
  var retrievePersistedAppEventStatesWasCalled = false
  var clearPersistedAppEventsWasCalled = false
  var persistedStatesToBeRetrieved: [Any] = []

  func clearPersistedAppEventsStates() {
    clearPersistedAppEventsWasCalled = true
    capturedPersistedState = []
  }

  func persistAppEventsData(_ appEventsState: _AppEventsState) {
    capturedPersistedState.append(appEventsState)
  }

  func retrievePersistedAppEventsStates() -> [Any] {
    retrievePersistedAppEventStatesWasCalled = true
    return Array(persistedStatesToBeRetrieved)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

@testable import FBSDKCoreKit
import XCTest

@objcMembers
// swiftlint:disable:next line_length
final class TestAppEventsUtility: NSObject, _AppEventDropDetermining, _AppEventParametersExtracting, _AppEventsUtilityProtocol, _LoggingNotifying {

  var shouldDropAppEvents = false
  var unixTimeNow = TimeInterval(0)
  var stubbedIsIdentifierValid = false
  var stubbedTokenStringToUse: String?

  func activityParametersDictionary(
    forEvent eventCategory: String,
    shouldAccessAdvertisingID: Bool,
    userID: String?,
    userData: String?
  ) -> NSMutableDictionary {
    ["event": eventCategory]
  }

  func ensure(onMainThread methodName: String, className: String) {}

  func convert(toUnixTime date: Date?) -> TimeInterval {
    0
  }

  func validateIdentifier(_ identifier: String?) -> Bool {
    stubbedIsIdentifierValid
  }

  func tokenStringToUse(for token: AccessToken?, loggingOverrideAppID: String?) -> String? {
    stubbedTokenStringToUse
  }

  func flushReason(toString flushReason: AppEvents.FlushReason) -> String {
    ""
  }

  func logAndNotify(_ message: String) {}

  func logAndNotify(_ message: String, allowLogAsDeveloperError: Bool) {}

  func saveCampaignIDs(_ url: URL) {}

  func getCampaignIDs() -> String? {
    nil
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation
import UIKit

final class TestApplicationDelegate: NSObject, UIApplicationDelegate {

  var applicationOpenURLCallCount = 0

  dynamic func application(
    _ app: UIApplication,
    open url: URL,
    options: [UIApplication.OpenURLOptionsKey: Any] = [:]
  ) -> Bool {
    applicationOpenURLCallCount += 1
    return true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import UIKit

@objcMembers
final class TestApplicationDelegateObserver: NSObject, FBSDKApplicationObserving {
  var didFinishLaunchingCallCount = 0
  var capturedLaunchOptions: [UIApplication.LaunchOptionsKey: Any]?
  var wasWillResignActiveCalled = false

  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
  ) -> Bool {
    didFinishLaunchingCallCount += 1
    capturedLaunchOptions = launchOptions
    return true
  }

  func applicationWillResignActive(_ application: UIApplication?) {
    wasWillResignActiveCalled = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestAppLink: _AppLinkProtocol {
  var sourceURL: URL?
  var targets = [AppLinkTargetProtocol]()
  var webURL: URL?
  var isBackToReferrer = false
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit

final class TestAppLinkEventPoster: _AppLinkEventPosting {
  func postNotification(eventName name: String, arguments args: [String: Any]) {}
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestAppLinkFactory: _AppLinkCreating {
  func createAppLink(
    sourceURL: URL?,
    targets: [AppLinkTargetProtocol],
    webURL: URL?,
    isBackToReferrer: Bool
  ) -> _AppLinkProtocol {
    TestAppLink()
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestAppLinkResolver: NSObject, AppLinkResolving {
  var capturedURL: URL?
  var capturedCompletion: AppLinkBlock?

  func appLink(from url: URL, handler: @escaping AppLinkBlock) {
    capturedURL = url
    capturedCompletion = handler
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import TestTools

final class TestAppLinkResolverRequestBuilder: _AppLinkResolverRequestBuilding {

  var stubbedGraphRequest = TestGraphRequest()
  var stubbedIdiomSpecificField: String?

  func request(for urls: [URL]) -> GraphRequestProtocol {
    stubbedGraphRequest
  }

  func getIdiomSpecificField() -> String? {
    stubbedIdiomSpecificField
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestAppLinkTarget: AppLinkTargetProtocol {

  var url: URL?
  var appStoreId: String?
  var appName: String

  init(
    url: URL?,
    appStoreId: String?,
    appName: String
  ) {
    self.url = url
    self.appStoreId = appStoreId
    self.appName = appName
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestAppLinkTargetFactory: _AppLinkTargetCreating {
  func createAppLinkTarget(
    url: URL?,
    appStoreId: String?,
    appName: String
  ) -> AppLinkTargetProtocol {
    TestAppLinkTarget(
      url: url,
      appStoreId: appStoreId,
      appName: appName
    )
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestAppLinkURL: _AppLinkURLProtocol {
  var appLinkExtras: [String: Any]?

  init(appLinkExtras: [String: Any] = [:]) {
    self.appLinkExtras = appLinkExtras
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit

final class TestAppLinkURLFactory: _AppLinkURLCreating {
  var stubbedAppLinkURL: TestAppLinkURL?

  func createAppLinkURL(with url: URL) -> _AppLinkURLProtocol {
    stubbedAppLinkURL ?? TestAppLinkURL()
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestAppStoreReceiptProvider: _AppStoreReceiptProviding {
  var wasAppStoreReceiptURLRead = false
  var stubbedURL: URL?

  var appStoreReceiptURL: URL? {
    wasAppStoreReceiptURLRead = true
    return stubbedURL
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestASIdentifierManager: ASIdentifierManager {
  var stubbedAdvertisingIdentifier: UUID

  init(stubbedAdvertisingIdentifier: UUID) {
    self.stubbedAdvertisingIdentifier = stubbedAdvertisingIdentifier
  }

  override var advertisingIdentifier: UUID {
    stubbedAdvertisingIdentifier
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestATEPublisher: NSObject, ATEPublishing {
  var publishATEWasCalled = false

  func publishATE() {
    publishATEWasCalled = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestATEPublisherFactory: NSObject, _ATEPublisherCreating {
  var stubbedPublisher: ATEPublishing? = TestATEPublisher()
  var capturedAppID: String?

  func createPublisher(appID: String) -> ATEPublishing? {
    capturedAppID = appID
    return stubbedPublisher
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

@testable import FBSDKCoreKit

final class TestBackgroundEventLogger: BackgroundEventLogging {

  var logBackgroundRefresStatusCallCount = 0

  func logBackgroundRefreshStatus(_ status: UIBackgroundRefreshStatus) {
    logBackgroundRefresStatusCallCount += 1
  }
}

extension TestBackgroundEventLogger: DependentAsType {
  struct TypeDependencies {
    var infoDictionaryProvider: InfoDictionaryProviding
    var eventLogger: EventLogging
  }

  static var configuredDependencies: TypeDependencies?

  static var defaultDependencies: TypeDependencies? = TypeDependencies(
    infoDictionaryProvider: TestBundle(),
    eventLogger: TestEventLogger()
  )
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import TestTools

final class TestBridgeAPIProtocol: NSObject, BridgeAPIProtocol {
  var stubbedRequestURL = SampleURLs.valid
  var stubbedRequestURLError: Error?
  var stubbedResponseParameters = [String: Any]()
  var capturedRequestUrlActionID: String?
  var capturedRequestUrlScheme: String?
  var capturedRequestUrlMethodName: String?
  var capturedRequestUrlParameters: [String: Any]?
  var capturedResponseActionID: String?
  var capturedResponseQueryParameters: [String: Any]?
  var capturedResponseCancelledRef: UnsafeMutablePointer<ObjCBool>?

  func requestURL(
    actionID: String,
    scheme: String,
    methodName: String,
    parameters: [String: Any]
  ) throws -> URL {
    capturedRequestUrlActionID = actionID
    capturedRequestUrlScheme = scheme
    capturedRequestUrlMethodName = methodName
    capturedRequestUrlParameters = parameters

    if let error = stubbedRequestURLError {
      throw error
    }

    return stubbedRequestURL
  }

  func responseParameters(
    actionID: String,
    queryParameters: [String: Any],
    cancelled cancelledRef: UnsafeMutablePointer<ObjCBool>?
  ) throws -> [String: Any] {
    capturedResponseActionID = actionID
    capturedResponseQueryParameters = queryParameters
    capturedResponseCancelledRef = cancelledRef

    return stubbedResponseParameters
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

@testable import FBSDKCoreKit

final class TestBridgeAPIResponseFactory: BridgeAPIResponseCreating {

  var capturedResponseURL: URL?
  var capturedSourceApplication: String?
  var stubbedResponse: BridgeAPIResponse?
  var shouldFailCreation = false

  func createResponseCancelled(request: BridgeAPIRequestProtocol) -> BridgeAPIResponse {
    stubbedResponse ?? createResponse(withRequest: request, cancelled: true)
  }

  func createResponse(
    request: BridgeAPIRequestProtocol,
    error: Error
  ) -> BridgeAPIResponse {
    stubbedResponse ?? createResponse(withRequest: request, error: error)
  }

  func createResponse(
    request: BridgeAPIRequestProtocol,
    responseURL: URL,
    sourceApplication: String?
  ) throws -> BridgeAPIResponse {
    capturedResponseURL = responseURL
    capturedSourceApplication = sourceApplication

    guard !shouldFailCreation else {
      throw CoreError(.errorBridgeAPIResponse)
    }

    return stubbedResponse ?? createResponse(withRequest: request)
  }

  private func createResponse(
    withRequest request: BridgeAPIRequestProtocol,
    error: Error? = nil,
    cancelled: Bool = false
  ) -> BridgeAPIResponse {
    BridgeAPIResponse(
      request: request,
      responseParameters: [:],
      cancelled: cancelled,
      error: error
    )
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

final class TestCAPIReporter: CAPIReporter {

  var enabledWasCalled = false
  var capturedFactory: GraphRequestFactoryProtocol?
  var capturedSettings: SettingsProtocol?
  var capturedEvent: [String: Any]?

  func enable() {
    enabledWasCalled = true
  }

  func configure(factory: GraphRequestFactoryProtocol, settings: SettingsProtocol) {
    capturedFactory = factory
    capturedSettings = settings
  }

  func recordEvent(_ parameters: [String: Any]) {
    capturedEvent = parameters
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
final class TestClientTokenProvider: NSObject, _ClientTokenProviding {
  var clientToken: String?

  init(clientToken: String? = nil) {
    self.clientToken = clientToken
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestCodelessEvents: NSObject, _CodelessIndexing {

  static var wasEnabledCalled = false

  static func enable() {
    wasEnabledCalled = true
  }

  static func reset() {
    wasEnabledCalled = false
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

final class TestCollectionView: UICollectionView {
  var stubbedWindow: UIWindow?
  var stubbedCellMap = [IndexPath: UICollectionViewCell]()

  func stub(cell: UICollectionViewCell, forIndexPath indexPath: IndexPath) {
    stubbedCellMap[indexPath] = cell
  }

  override func cellForItem(at indexPath: IndexPath) -> UICollectionViewCell? {
    stubbedCellMap[indexPath]
  }

  override var window: UIWindow? {
    stubbedWindow
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestControl: UIControl {
  var capturedAction: Selector?
  var stubbedWindow: UIWindow?

  override var window: UIWindow? {
    stubbedWindow
  }

  override func addTarget(_ target: Any?, action: Selector, for controlEvents: UIControl.Event) {
    capturedAction = action
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import XCTest

@objcMembers
final class TestConversionValueUpdating: NSObject, _ConversionValueUpdating {

  static var wasUpdateVersionValueCalled = false

  static func updateConversionValue(_ conversionValue: Int) {
    wasUpdateVersionValueCalled = true
  }

  static func reset() {
    wasUpdateVersionValueCalled = false
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import XCTest

@objcMembers
final class TestCrashHandler: NSObject, CrashHandlerProtocol {

  var wasAddObserverCalled = false
  var observer: CrashObserving?
  var wasClearCrashReportFilesCalled = false
  var wasSaveExceptionCalled = false

  func addObserver(_ observer: CrashObserving) {
    wasAddObserverCalled = true
    self.observer = observer
  }

  func clearCrashReportFiles() {
    wasClearCrashReportFilesCalled = true
  }

  func save(_ exception: NSException) {
    wasSaveExceptionCalled = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestCrashObserver: CrashObserving {
  var wasEnableCalled = false
  var prefixes = [String]()
  var frameworks: [String]?

  func enable() {
    wasEnableCalled = true
  }

  func didReceiveCrashLogs(_ crashLogs: [[String: Any]]) {}
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestDataStore: DataPersisting {
  func fb_setInteger(_ value: Int, forKey defaultName: String) {}
  func fb_setObject(_ value: Any, forKey defaultName: String) {}
  func fb_data(forKey defaultName: String) -> Data? { nil }
  func fb_integer(forKey defaultName: String) -> Int { Int.min }
  func fb_string(forKey defaultName: String) -> String? { nil }
  func fb_object(forKey defaultName: String) -> Any? { nil }
  func fb_removeObject(forKey defaultName: String) {}
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestDeviceInformationProvider: _DeviceInformationProviding {
  var carrierName: String? = "NoCarrier"

  var timeZoneAbbrev: String? = ""

  var remainingDiskSpaceGB: UInt64 = 0

  var timeZoneName: String? = ""

  var bundleIdentifier: String? = ""

  var longVersion: String? = "1.0.1"

  var shortVersion: String? = "1.0.1"

  var sysVersion: String? = "16.0.1"

  var machine: String? = "iphone12"

  var language: String? = "en_US"

  var totalDiskSpaceGB: UInt64 = 0

  var coreCount: UInt64 = 0

  var width: CGFloat = 0.0

  var height: CGFloat = 0.0

  var density: CGFloat = 0.0

  var storageKey = "storageKey"
  var stubbedEncodedDeviceInfo: String?
  var encodedDeviceInfoWasCalled = false

  init(stubbedEncodedDeviceInfo: String? = nil) {
    self.stubbedEncodedDeviceInfo = stubbedEncodedDeviceInfo
  }

  var encodedDeviceInfo: String? {
    encodedDeviceInfoWasCalled = true

    return stubbedEncodedDeviceInfo
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestDialogConfigurationMapBuilder: _DialogConfigurationMapBuilding {

  var capturedRawConfigurations: [[String: Any]]?

  func buildDialogConfigurationMap(
    from rawConfigurations: [[String: Any]]
  ) -> [String: _DialogConfiguration] {
    capturedRawConfigurations = rawConfigurations
    return [:]
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestDylibResolver: NSObject, FBSDKDynamicFrameworkResolving {
  var stubSafariViewControllerClass: AnyClass?
  var stubbedASIdentifierManagerClass: AnyClass?
  var didLoadIdentifierManagerClass = false
  var didLoadSafariViewControllerClass = false

  func safariViewControllerClass() -> AnyClass? {
    didLoadSafariViewControllerClass = true
    return stubSafariViewControllerClass
  }

  func asIdentifierManagerClass() -> AnyClass? {
    didLoadIdentifierManagerClass = true
    return stubbedASIdentifierManagerClass
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
final class TestErrorConfiguration: NSObject, _ErrorConfigurationProtocol {
  var capturedRecoveryConfigurationCode: String?
  var capturedRecoveryConfigurationSubcode: String?
  var capturedGraphRequest: GraphRequestProtocol?
  var stubbedRecoveryConfiguration: _ErrorRecoveryConfiguration?

  func recoveryConfiguration(
    forCode code: String?,
    subcode: String?,
    request: GraphRequestProtocol
  ) -> _ErrorRecoveryConfiguration? {
    capturedRecoveryConfigurationCode = code
    capturedRecoveryConfigurationSubcode = subcode
    capturedGraphRequest = request

    guard let recoveryConfiguration = stubbedRecoveryConfiguration else {
      fatalError("Must have a recovery configuration stubbed")
    }
    return recoveryConfiguration
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestErrorConfigurationProvider: NSObject, _ErrorConfigurationProviding {
  var configuration: _ErrorConfigurationProtocol?

  init(configuration: _ErrorConfigurationProtocol? = nil) {
    self.configuration = configuration
  }

  func errorConfiguration() -> _ErrorConfigurationProtocol? {
    configuration
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit

final class TestErrorRecoveryAttempter: ErrorRecoveryAttempting {
  var capturedError: Error?
  var capturedCompletion: ((Bool) -> Void)?

  func attemptRecovery(
    from error: Error,
    completion: @escaping (Bool) -> Void
  ) {
    capturedError = error
    capturedCompletion = completion
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestErrorReporter: ErrorReporting {
  var wasEnableCalled = false
  var capturedErrorCode: Int?
  var capturedErrorDomain: String?
  var capturedMessage: String?

  func enable() {
    wasEnableCalled = true
  }

  func saveError(
    _ errorCode: Int,
    errorDomain: String,
    message: String?
  ) {
    capturedErrorCode = errorCode
    capturedErrorDomain = errorDomain
    capturedMessage = message
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestEventBinding: EventBinding {
  var trackEventWasCalled = false
  var stubbedPath = [Any]()
  let stubbedEventLogger = TestEventLogger()

  init(view potentialView: UIView? = nil) {
    super.init(json: [:], eventLogger: stubbedEventLogger)

    if let view = potentialView,
       let path = ViewHierarchy.getPath(view) {
      stubbedPath = path
    }
  }

  override var path: [Any] {
    stubbedPath
  }

  override func trackEvent(_ sender: Any?) {
    trackEventWasCalled = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

@testable import FBSDKCoreKit
import Foundation

@objcMembers
class TestEventLogger: NSObject, EventLogging { // swiftlint:disable:this prefer_final_classes
  var flushCallCount = 0
  var flushBehavior: AppEvents.FlushBehavior = .auto
  var capturedEventName: AppEvents.Name?
  var capturedParameters: [AppEvents.ParameterName: Any]?
  var capturedIsImplicitlyLogged = false
  var capturedAccessToken: AccessToken?
  var capturedValueToSum: Double?
  var capturedFlushReason: AppEvents.FlushReason?

  func flush(for flushReason: AppEvents.FlushReason) {
    flushCallCount += 1
    capturedFlushReason = flushReason
  }

  func logEvent(_ eventName: AppEvents.Name, parameters: [AppEvents.ParameterName: Any]?) {
    capturedEventName = eventName
    capturedParameters = parameters
  }

  func logEvent(
    _ eventName: AppEvents.Name,
    valueToSum: Double,
    parameters: [AppEvents.ParameterName: Any]?
  ) {
    capturedEventName = eventName
    capturedValueToSum = valueToSum
    capturedParameters = parameters
  }

  func logInternalEvent(_ eventName: AppEvents.Name, isImplicitlyLogged: Bool) {
    capturedEventName = eventName
    capturedIsImplicitlyLogged = isImplicitlyLogged
  }

  func logInternalEvent(
    _ eventName: AppEvents.Name,
    parameters: [AppEvents.ParameterName: Any]?,
    isImplicitlyLogged: Bool
  ) {
    capturedEventName = eventName
    capturedParameters = parameters
    capturedIsImplicitlyLogged = isImplicitlyLogged
  }

  func logInternalEvent(
    _ eventName: AppEvents.Name,
    parameters: [AppEvents.ParameterName: Any]?,
    isImplicitlyLogged: Bool,
    accessToken: AccessToken?
  ) {
    capturedEventName = eventName
    capturedParameters = parameters
    capturedIsImplicitlyLogged = isImplicitlyLogged
    capturedAccessToken = accessToken
  }

  func logInternalEvent(
    _ eventName: AppEvents.Name,
    valueToSum: Double,
    isImplicitlyLogged: Bool
  ) {
    capturedEventName = eventName
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import XCTest

final class TestFeatureExtractor: _FeatureExtracting {

  static var stubbedDenseFeatures: UnsafeMutablePointer<Float>?
  static var capturedGetTextFeatureText: String?
  static var capturedGetTextFeatureScreenName: String?
  static var loadRulesForKeyWasCalled = false
  static var capturedUseCaseKeys = [String]()

  static func stub(denseFeatures: UnsafeMutablePointer<Float>) {
    stubbedDenseFeatures = denseFeatures
  }

  static func getDenseFeatures(_ viewHierarchy: [String: Any]) -> UnsafeMutablePointer<Float>? {
    stubbedDenseFeatures
  }

  static func getTextFeature(_ text: String, withScreenName screenName: String) -> String {
    capturedGetTextFeatureText = text
    capturedGetTextFeatureScreenName = screenName
    return ""
  }

  static func loadRules(forKey useCaseKey: String) {
    XCTFail("Test is not checking that rules were loaded")
    loadRulesForKeyWasCalled = true
    capturedUseCaseKeys.append(useCaseKey)
  }

  static func reset() {
    stubbedDenseFeatures = nil
    capturedGetTextFeatureText = nil
    capturedGetTextFeatureScreenName = nil
    loadRulesForKeyWasCalled = false
    capturedUseCaseKeys = []
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import XCTest

@objcMembers
final class TestFeatureManager: NSObject, FeatureChecking, _FeatureDisabling {

  var disabledFeatures = [SDKFeature]()
  var capturedFeatures = [SDKFeature]()
  var capturedCompletionBlocks: [SDKFeature: FBSDKFeatureManagerBlock] = [:]
  private var stubbedEnabledFeatures = [SDKFeature: Bool]()

  func check(_ feature: SDKFeature, completionBlock: @escaping FBSDKFeatureManagerBlock) {
    capturedFeatures.append(feature)
    capturedCompletionBlocks[feature] = completionBlock
  }

  func capturedFeaturesContains(_ feature: SDKFeature) -> Bool {
    capturedFeatures.contains(feature)
  }

  func disableFeature(_ feature: SDKFeature) {
    disabledFeatures.append(feature)
  }

  func disabledFeaturesContains(_ feature: SDKFeature) -> Bool {
    disabledFeatures.contains(feature)
  }

  /// Stub enabling features so that they pass the `isEnabled` check
  func enable(feature: SDKFeature) {
    stubbedEnabledFeatures[feature] = true
  }

  func isEnabled(_ feature: SDKFeature) -> Bool {
    stubbedEnabledFeatures[feature] ?? false
  }

  func completeCheck(
    forFeature feature: SDKFeature,
    with isEnabled: Bool
  ) {
    guard let completion = capturedCompletionBlocks[feature] else {
      return
    }
    completion(isEnabled)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import TestTools
import XCTest

import Foundation

final class TestFileDataExtractor: _FileDataExtracting {
  static var stubbedData: Data?
  static var capturedFileNames = [String]()

  static func fb_data(
    withContentsOfFile path: String,
    options readOptionsMask: NSData.ReadingOptions = []
  ) throws -> Data {
    capturedFileNames.append(path)
    guard let data = stubbedData else {
      throw SampleError()
    }
    return data
  }

  static func reset() {
    capturedFileNames = []
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import TestTools
import XCTest

import Foundation

final class TestFileManager: _FileManaging {
  var removeItemAtPathWasCalled = false
  var contentsOfDirectoryAtPathWasCalled = false
  var capturedFileExistsAtPath: String?
  var capturedCreateDirectoryPath: String?
  var stubbedContentsOfDirectory = [String]()
  var stubbedFileExists = true
  var stubbedCreateDirectoryShouldSucceed = true

  var tempDirectoryURL: URL?

  init(tempDirectoryURL: URL? = nil) {
    self.tempDirectoryURL = tempDirectoryURL
  }

  func fb_createDirectory(
    atPath path: String,
    withIntermediateDirectories createIntermediates: Bool,
    attributes: [FileAttributeKey: Any]? = [:]
  ) throws {
    capturedCreateDirectoryPath = path
    if !stubbedCreateDirectoryShouldSucceed {
      throw SampleError()
    }
  }

  func fb_fileExists(atPath path: String) -> Bool {
    capturedFileExistsAtPath = path
    return stubbedFileExists
  }

  func fb_contentsOfDirectory(atPath path: String) throws -> [String] {
    contentsOfDirectoryAtPathWasCalled = true

    return stubbedContentsOfDirectory
  }

  func fb_removeItem(atPath path: String) throws {
    removeItemAtPathWasCalled = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestGateKeeperManager: NSObject, _GateKeeperManaging {
  static var gateKeepers = [String?: Bool]()
  static var loadGateKeepersWasCalled = false
  static var capturedLoadGateKeepersCompletion: _GKManagerBlock?
  static var capturedBoolForGateKeeperKeys = [String]()

  static func setGateKeeperValue(key: String, value: Bool) {
    gateKeepers[key] = value
  }

  static func bool(forKey key: String, defaultValue: Bool) -> Bool {
    capturedBoolForGateKeeperKeys.append(key)
    if let value = gateKeepers[key] {
      return value
    } else {
      return defaultValue
    }
  }

  static func loadGateKeepers(_ completionBlock: @escaping _GKManagerBlock) {
    loadGateKeepersWasCalled = true
    capturedLoadGateKeepersCompletion = completionBlock
  }

  static func reset() {
    gateKeepers = [:]
    loadGateKeepersWasCalled = false
    capturedLoadGateKeepersCompletion = nil
    capturedBoolForGateKeeperKeys = []
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit

final class TestGraphErrorRecoveryProcessorDelegate: NSObject, GraphErrorRecoveryProcessorDelegate {

  var wasRecoveryAttempted = false
  var capturedProcessor: GraphErrorRecoveryProcessor?
  var capturedDidRecover = false
  var capturedError: NSError?

  func processorDidAttemptRecovery(
    _ processor: GraphErrorRecoveryProcessor,
    didRecover: Bool,
    error: Error?
  ) {
    wasRecoveryAttempted = true
    capturedProcessor = processor
    capturedDidRecover = didRecover
    capturedError = error as NSError?
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestGraphRequestBody: GraphRequestBody {
  var capturedKey: String?
  var capturedFormValue: String?
  var capturedImage: UIImage?
  var capturedData: Data?
  var capturedAttachment: GraphRequestDataAttachment?

  override func append(withKey key: String, formValue value: String, logger: _Logger?) {
    capturedKey = key
    capturedFormValue = value
  }

  override func append(withKey key: String, imageValue image: UIImage, logger: _Logger?) {
    capturedImage = image
  }

  override func append(withKey key: String, dataValue data: Data, logger: _Logger?) {
    capturedData = data
  }

  override func append(
    withKey key: String,
    dataAttachmentValue dataAttachment: GraphRequestDataAttachment,
    logger: _Logger?
  ) {
    capturedAttachment = dataAttachment
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
final class TestGraphRequestPiggybackManager: NSObject, _GraphRequestPiggybackManaging {

  var capturedConnection: GraphRequestConnecting?
  var addRefreshPiggybackWasCalled = false

  func addPiggybackRequests(_ connection: GraphRequestConnecting) {
    capturedConnection = connection
  }

  func addRefreshPiggyback(
    _ connection: GraphRequestConnecting,
    permissionHandler: GraphRequestCompletion? = nil
  ) {
    addRefreshPiggybackWasCalled = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import TestTools
import XCTest

import Foundation

final class TestImpressionButton: ImpressionLoggingButton, FBButtonImpressionLogging {
  var analyticsParameters: [AppEvents.ParameterName: Any]? = [.init("foo"): "bar"]
  var impressionTrackingEventName = AppEvents.Name("testImpressionTrackingEventName")
  var impressionTrackingIdentifier = "testImpressionTrackingIdentifier"
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit

final class TestImpressionLogger: ImpressionLogging {

  var capturedIdentifier: String?
  var capturedParameters: [AppEvents.ParameterName: Any]?

  func logImpression(
    withIdentifier identifier: String,
    parameters: [AppEvents.ParameterName: Any]?
  ) {
    capturedIdentifier = identifier
    capturedParameters = parameters
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit

final class TestImpressionLoggerFactory: _ImpressionLoggerFactoryProtocol {
  let impressionLogger = TestImpressionLogger()
  var capturedEventName: AppEvents.Name?

  func makeImpressionLogger(withEventName eventName: AppEvents.Name) -> ImpressionLogging {
    capturedEventName = eventName

    return impressionLogger
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestIntegrityProcessor: IntegrityProcessing {
  var stubbedParameters = [String: Bool]()

  func processIntegrity(_ potentialParameter: String?) -> Bool {
    guard let parameter = potentialParameter else {
      return false
    }

    return stubbedParameters[parameter] ?? false
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestInternalURLOpener: NSObject, _InternalURLOpener {
  var capturedOpenURL: URL?
  var capturedCanOpenURL: URL?
  var canOpenURL: Bool
  var capturedOpenURLCompletion: ((Bool) -> Void)?

  init(canOpenURL: Bool = false) {
    self.canOpenURL = canOpenURL
  }

  public func canOpen(_ url: URL) -> Bool {
    capturedCanOpenURL = url
    return canOpenURL
  }

  public func open(_ url: URL) -> Bool {
    capturedOpenURL = url
    return true
  }

  public func open(
    _ url: URL,
    options: [UIApplication.OpenExternalURLOptionsKey: Any],
    completionHandler completion: ((Bool) -> Void)?
  ) {
    capturedOpenURL = url
    capturedOpenURLCompletion = completion
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestLogger: _Logger {
  static var capturedLoggingBehavior: LoggingBehavior?
  /// The most recent log entry
  static var capturedLogEntry: String?
  /// All log entries captured between resetting the fixture
  static var capturedLogEntries = [String]()

  let stubbedLoggingBehavior: LoggingBehavior

  override var contents: String {
    capturedContents ?? ""
  }

  var capturedAppendedKeys = [String]()
  var capturedAppendedValues = [String]()
  var stubbedIsActive = false
  var capturedContents: String?
  var logEntryCallCount = 0

  var capturedLoggingBehavior: LoggingBehavior?

  required init(loggingBehavior: LoggingBehavior) {
    stubbedLoggingBehavior = loggingBehavior

    super.init(loggingBehavior: loggingBehavior)
  }

  override class func singleShotLogEntry(_ loggingBehavior: LoggingBehavior, logEntry: String) {
    capturedLoggingBehavior = loggingBehavior
    capturedLogEntry = logEntry
    capturedLogEntries.append(logEntry)
  }

  override func logEntry(_ logEntry: String) {
    capturedContents = logEntry
    logEntryCallCount += 1
  }

  override var isActive: Bool {
    stubbedIsActive
  }

  override func appendKey(_ key: String, value: String) {
    capturedAppendedKeys.append(key)
    capturedAppendedValues.append(value)
  }

  class func reset() {
    capturedLoggingBehavior = nil
    capturedLogEntry = nil
    capturedLogEntries = []
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestLoggerFactory: NSObject, _LoggerCreating {
  var capturedLoggingBehavior: LoggingBehavior?
  var logger = TestLogger(loggingBehavior: .developerErrors)

  func createLogger(withLoggingBehavior loggingBehavior: LoggingBehavior) -> Logging {
    capturedLoggingBehavior = loggingBehavior
    return logger
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import XCTest

final class TestLoggingNotifier: _LoggingNotifying {
  var capturedMessage: String?

  func logAndNotify(_ message: String) {
    capturedMessage = message
  }

  func logAndNotify(_ message: String, allowLogAsDeveloperError: Bool) {
    XCTFail("Message should be captured and asserted against")
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

final class TestMACARuleMatchingManager: MACARuleMatching {

  var enabledWasCalled = false

  func enable() {
    enabledWasCalled = true
  }

  func processParameters(_ params: NSDictionary?, event: String?) -> NSDictionary? { params }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
final class TestMacCatalystDeterminator: _MacCatalystDetermining {
  var stubbedIsMacCatalystApp = false

  var fb_isMacCatalystApp: Bool { // swiftlint:disable:this identifier_name
    stubbedIsMacCatalystApp
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
final class TestMeasurementEvent: NSObject, _AppLinkEventPosting {
  var capturedEventName: String?
  var capturedArgs = [String: String]()

  func postNotification(eventName name: String, arguments args: [String: Any]) {
    capturedEventName = name
    capturedArgs = args as? [String: String] ?? [:]
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestMetadataIndexer: NSObject, _MetadataIndexing {
  var enableWasCalled = false

  func enable() {
    enableWasCalled = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

import FBSDKCoreKit_Basics

extension TestNotificationCenter: _NotificationPosting {

  // MARK: Posting

  public func fb_post(
    name: Notification.Name,
    object: Any?,
    userInfo: [String: Any]? = nil
  ) {
    capturedPostNames.append(name)
    capturedPostObjects.append(object as Any)
    capturedPostUserInfos.append(userInfo ?? [:])
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

// swiftformat:disable indent
@objcMembers
final class TestOnDeviceMLModelManager: NSObject,
                                        _EventProcessing,
                                        _IntegrityParametersProcessorProvider,
                                        _RulesFromKeyProvider {
  // swiftformat:enable indent

  var stubbedRules: [String: Any] = [:]
  var processSuggestedEventsCallCount = 0
  var stubbedProcessedEvents: String?
  var isEnabled = false
  var integrityParametersProcessor: _AppEventsParameterProcessing?
  var rulesForKey: [String: Any] {
    get {
      stubbedRules
    }
    set {
      stubbedRules = newValue
    }
  }

  func processSuggestedEvents(
    _ textFeature: String,
    denseData: UnsafeMutablePointer<Float>?
  ) -> String {
    processSuggestedEventsCallCount += 1

    return stubbedProcessedEvents ?? ""
  }

  func enable() {
    isEnabled = true
  }

  func getRulesForKey(_ useCase: String) -> [String: Any]? {
    stubbedRules
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestOperationQueue: OperationQueue {

  var addOperationWithBlockWasCalled = false
  var capturedOperationBlock: (() -> Void)?

  override func addOperation(_ block: @escaping () -> Void) {
    addOperationWithBlockWasCalled = true
    capturedOperationBlock = block
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
final class TestPasteboard: NSObject, _Pasteboard {
  var name = "pasteboard"
  var stubbedData: Data?
  var capturedData: Data?
  var capturedPasteboardType: String?
  var _isGeneralPasteboard = false // swiftlint:disable:this identifier_name

  func data(forPasteboardType pasteboardType: String) -> Data? {
    stubbedData
  }

  func setData(_ data: Data, forPasteboardType pasteboardType: String) {
    capturedData = data
    capturedPasteboardType = pasteboardType
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

@available(iOS 12.2, *)
final class TestPayment: SKPayment {
  let stubbedProductIdentifier: String
  let stubbedQuantity: Int
  let stubbedPaymentDiscount: SKPaymentDiscount?

  init(
    productIdentifier: String,
    quantity: Int = 0,
    discount: SKPaymentDiscount? = nil
  ) {
    stubbedProductIdentifier = productIdentifier
    stubbedQuantity = quantity
    stubbedPaymentDiscount = discount
  }

  override var productIdentifier: String {
    stubbedProductIdentifier
  }

  override var quantity: Int {
    stubbedQuantity
  }

  @available(iOS 12.2, *)
  override var paymentDiscount: SKPaymentDiscount? {
    stubbedPaymentDiscount
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestPaymentObserver: NSObject, _PaymentObserving {
  var didStartObservingTransactions = false
  var didStopObservingTransactions = false

  func startObservingTransactions() {
    didStartObservingTransactions = true
  }

  func stopObservingTransactions() {
    didStopObservingTransactions = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestPaymentProductRequestor: PaymentProductRequestor {
  var wasResolveProductsCalled = false

  override func resolveProducts() {
    wasResolveProductsCalled = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import TestTools

@available(iOS 12.2, *)
final class TestPaymentProductRequestorFactory: _PaymentProductRequestorCreating {
  struct Evidence {
    let requestor: TestPaymentProductRequestor
    let transaction: SKPaymentTransaction
  }

  // Dummy class to avoid polluting the shared test gatekeeper manager
  final class PaymentGateKeeperManager: _GateKeeperManaging {
    static func bool(forKey key: String, defaultValue: Bool) -> Bool {
      false
    }

    static func loadGateKeepers(_ completionBlock: @escaping _GKManagerBlock) {
      // noop
    }
  }

  let transaction = TestPaymentTransaction(state: .deferred)
  let settings = TestSettings()
  let eventLogger = TestEventLogger()
  let store = UserDefaultsSpy()
  let loggerFactory = TestLoggerFactory()
  let graphRequestFactory = TestProductsRequestFactory()
  let receiptProvider = TestAppStoreReceiptProvider()

  var evidence = [Evidence]()

  func createRequestor(transaction: SKPaymentTransaction) -> PaymentProductRequestor {
    let requestor = TestPaymentProductRequestor(
      transaction: transaction,
      settings: settings,
      eventLogger: eventLogger,
      gateKeeperManager: PaymentGateKeeperManager.self,
      store: store,
      loggerFactory: loggerFactory,
      productsRequestFactory: graphRequestFactory,
      appStoreReceiptProvider: receiptProvider
    )
    evidence.append(Evidence(requestor: requestor, transaction: transaction))

    return requestor
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestPaymentQueue: SKPaymentQueue {

  var addTransactionObserverWasCalled = false
  var removeTransactionObserverWasCalled = false

  override func add(_ observer: SKPaymentTransactionObserver) {
    addTransactionObserverWasCalled = true
  }

  override func remove(_ observer: SKPaymentTransactionObserver) {
    removeTransactionObserverWasCalled = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

@available(iOS 12.2, *)
final class TestPaymentTransaction: SKPaymentTransaction {
  private let stubbedTransactionIdentifier: String?
  private let stubbedTransactionState: SKPaymentTransactionState
  private let stubbedTransactionDate: Date?
  private let stubbedPayment: TestPayment
  private let stubbedOriginalTransaction: TestPaymentTransaction?

  init(
    identifier: String? = nil,
    state: SKPaymentTransactionState,
    date: Date? = nil,
    payment: TestPayment = TestPayment(productIdentifier: UUID().uuidString),
    originalTransaction: TestPaymentTransaction? = nil
  ) {
    stubbedTransactionIdentifier = identifier
    stubbedTransactionState = state
    stubbedTransactionDate = date
    stubbedPayment = payment
    stubbedOriginalTransaction = originalTransaction

    super.init()
  }

  override var original: SKPaymentTransaction? {
    stubbedOriginalTransaction
  }

  override var transactionIdentifier: String? {
    stubbedTransactionIdentifier
  }

  override var transactionState: SKPaymentTransactionState {
    stubbedTransactionState
  }

  override var transactionDate: Date? {
    stubbedTransactionDate
  }

  override var payment: SKPayment {
    stubbedPayment
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
final class TestProcessInfo: _OperatingSystemVersionComparing {
  var stubbedOperatingSystemCheckResult: Bool

  init(stubbedOperatingSystemCheckResult: Bool = true) {
    self.stubbedOperatingSystemCheckResult = stubbedOperatingSystemCheckResult
  }

  func fb_isOperatingSystemAtLeast(_ version: OperatingSystemVersion) -> Bool {
    stubbedOperatingSystemCheckResult
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestProduct: SKProduct {
  static let title = "Product title"
  static let productDescription = "Some description"

  let stubbedSubscriptionPeriod: TestProductSubscriptionPeriod?
  let stubbedDiscount: SKProductDiscount?

  init(
    subscriptionPeriod: TestProductSubscriptionPeriod? = nil,
    discount: TestProductDiscount? = nil
  ) {
    stubbedSubscriptionPeriod = subscriptionPeriod
    stubbedDiscount = discount
  }

  override var subscriptionPeriod: SKProductSubscriptionPeriod? {
    stubbedSubscriptionPeriod
  }

  override var priceLocale: Locale {
    let localeIdentifier = NSLocale.localeIdentifier(fromComponents: [NSLocale.Key.currencyCode.rawValue: "USD"])
    return NSLocale(localeIdentifier: localeIdentifier) as Locale
  }

  override var localizedTitle: String {
    TestProduct.title
  }

  override var localizedDescription: String {
    TestProduct.productDescription
  }

  override var introductoryPrice: SKProductDiscount? {
    stubbedDiscount
  }

  override var discounts: [SKProductDiscount] {
    [stubbedDiscount].compactMap { $0 }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestProductDiscount: SKProductDiscount {
  let stubbedIdentifier: String
  let stubbedPaymentMode: PaymentMode
  let stubbedPrice: NSDecimalNumber
  let stubbedSubscriptionPeriod: TestProductSubscriptionPeriod

  init(
    identifier: String = "identifier",
    paymentMode: PaymentMode,
    price: NSDecimalNumber,
    subscriptionPeriod: TestProductSubscriptionPeriod
  ) {
    stubbedIdentifier = identifier
    stubbedPaymentMode = paymentMode
    stubbedPrice = price
    stubbedSubscriptionPeriod = subscriptionPeriod
  }

  override var identifier: String? {
    stubbedIdentifier
  }

  override var paymentMode: SKProductDiscount.PaymentMode {
    stubbedPaymentMode
  }

  override var price: NSDecimalNumber {
    stubbedPrice
  }

  override var subscriptionPeriod: SKProductSubscriptionPeriod {
    stubbedSubscriptionPeriod
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestProductsRequest: _ProductsRequest {
  var cancelCallCount = 0
  var startCallCount = 0

  weak var delegate: SKProductsRequestDelegate?

  func cancel() {
    cancelCallCount += 1
  }

  func start() {
    startCallCount += 1
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestProductsRequestFactory: _ProductsRequestCreating {
  let request = TestProductsRequest()
  var capturedProductIdentifiers = Set<String>()

  func create(withProductIdentifiers identifiers: Set<String>) -> _ProductsRequest {
    capturedProductIdentifiers.formUnion(identifiers)
    return request
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestProductsResponse: SKProductsResponse {
  private let stubbedProducts: [SKProduct]
  private let stubbedInvalidProductIdentifiers: [String]

  init(
    products: [SKProduct],
    invalidProductIdentifiers: [String]
  ) {
    stubbedProducts = products
    stubbedInvalidProductIdentifiers = invalidProductIdentifiers
  }

  override var products: [SKProduct] {
    stubbedProducts
  }

  override var invalidProductIdentifiers: [String] {
    stubbedInvalidProductIdentifiers
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestProductSubscriptionPeriod: SKProductSubscriptionPeriod {
  let stubbedNumberOfUnits: Int

  init(numberOfUnits: Int) {
    stubbedNumberOfUnits = numberOfUnits
  }

  override var numberOfUnits: Int {
    stubbedNumberOfUnits
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation
import UIKit

final class TestReactNativeView: UIView {
  @objc var reactTag = NSNumber(value: 5)
  var capturedAction: Selector?
  var stubbedWindow: UIWindow?

  override var window: UIWindow? {
    stubbedWindow
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

// Hacky subclassing to get around init not being available.
// Future work should update ServerConfigurationProvider to return
// a true abstraction instead of a concrete ServerConfiguration and this
// type should simply conform to that abstraction.
final class TestServerConfiguration: _ServerConfiguration {
  var capturedUseNativeDialogName: String?
  var capturedUseSafariControllerName: String?
  var stubbedDefaultShareMode: String?
  @objc var stubbedIsCodelessEventsEnabled = false

  @objc
  convenience init(
    appID: String = "123"
  ) {
    self.init(
      appID: appID,
      appName: nil,
      loginTooltipEnabled: true,
      loginTooltipText: nil,
      defaultShareMode: nil,
      advertisingIDEnabled: false,
      implicitLoggingEnabled: false,
      implicitPurchaseLoggingEnabled: false,
      codelessEventsEnabled: false,
      uninstallTrackingEnabled: false,
      dialogConfigurations: [:],
      dialogFlows: [:],
      timestamp: Date(),
      errorConfiguration: nil,
      sessionTimeoutInterval: 1,
      defaults: false,
      loggingToken: nil,
      smartLoginOptions: .enabled,
      smartLoginBookmarkIconURL: nil,
      smartLoginMenuIconURL: nil,
      updateMessage: nil,
      eventBindings: nil,
      restrictiveParams: nil,
      aamRules: nil,
      suggestedEventsSetting: nil,
      protectedModeRules: nil
    )
  }

  override var isCodelessEventsEnabled: Bool {
    stubbedIsCodelessEventsEnabled
  }

  override var defaultShareMode: String? {
    stubbedDefaultShareMode
  }

  override func useNativeDialog(
    forDialogName dialogName: String?
  ) -> Bool {
    capturedUseNativeDialogName = dialogName
    return true
  }

  override func useSafariViewController(
    forDialogName dialogName: String?
  ) -> Bool {
    capturedUseSafariControllerName = dialogName
    return true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation
import TestTools

@objcMembers
final class TestServerConfigurationProvider: NSObject, _ServerConfigurationProviding {

  var capturedCompletionBlock: _ServerConfigurationBlock?
  var secondCapturedCompletionBlock: _ServerConfigurationBlock?
  var loadServerConfigurationWasCalled = false
  var stubbedRequestToLoadServerConfiguration: GraphRequest?
  var stubbedServerConfiguration: _ServerConfiguration
  var requestToLoadConfigurationCallWasCalled = false
  var didRetrieveCachedServerConfiguration = false

  init(configuration: _ServerConfiguration = ServerConfigurationFixtures.defaultConfiguration) {
    stubbedServerConfiguration = configuration
  }

  func cachedServerConfiguration() -> _ServerConfiguration {
    didRetrieveCachedServerConfiguration = true
    return stubbedServerConfiguration
  }

  func loadServerConfiguration(completionBlock: _ServerConfigurationBlock?) {
    loadServerConfigurationWasCalled = true
    guard capturedCompletionBlock == nil else {
      secondCapturedCompletionBlock = completionBlock
      return
    }

    capturedCompletionBlock = completionBlock
  }

  func reset() {
    requestToLoadConfigurationCallWasCalled = false
    loadServerConfigurationWasCalled = false
    capturedCompletionBlock = nil
    secondCapturedCompletionBlock = nil
  }

  func processLoadRequestResponse(_ result: Any, error: Error?, appID: String) {}

  func request(toLoadServerConfiguration appID: String) -> GraphRequest? {
    requestToLoadConfigurationCallWasCalled = true
    return stubbedRequestToLoadServerConfiguration
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import TestTools

extension TestSKAdNetworkReporter: _AppEventsReporter {
  public func enable() {}

  public func recordAndUpdate(
    event: String,
    currency: String?,
    value: NSNumber?,
    parameters: [String: Any]?
  ) {}
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestSuggestedEventsIndexer: _SuggestedEventsIndexerProtocol {

  var wasEnableCalled = false

  func enable() {
    wasEnableCalled = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

struct SwizzleEvidence: Equatable {
  let selector: Selector
  let `class`: AnyClass

  init(
    selector: Selector,
    class: AnyClass
  ) {
    self.selector = selector
    self.class = `class`
  }

  static func == (lhs: SwizzleEvidence, rhs: SwizzleEvidence) -> Bool {
    lhs.selector == rhs.selector && lhs.class == rhs.class
  }
}

@objcMembers
final class TestSwizzler: NSObject, _Swizzling {
  static var evidence = [SwizzleEvidence]()

  static func swizzleSelector(
    _ aSelector: Selector,
    on aClass: AnyClass,
    with block: @escaping _swizzleBlock,
    named aName: String
  ) {
    evidence.append(.init(selector: aSelector, class: aClass))
  }

  static func reset() {
    evidence = []
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

final class TestTableView: UITableView {
  var stubbedWindow: UIWindow?
  var stubbedCellMap = [IndexPath: UITableViewCell]()

  func stub(cell: UITableViewCell, forIndexPath indexPath: IndexPath) {
    stubbedCellMap[indexPath] = cell
  }

  override func cellForRow(at indexPath: IndexPath) -> UITableViewCell? {
    stubbedCellMap[indexPath]
  }

  override var window: UIWindow? {
    stubbedWindow
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestTimeSpentRecorder: NSObject, _SourceApplicationTracking, _TimeSpentRecording {

  var restoreWasCalled = false
  var suspendWasCalled = false
  var capturedCalledFromActivateApp = false
  var capturedSetSourceApplication: String?
  var capturedSetSourceApplicationURL: URL?
  var capturedSetSourceApplicationFromAppLink: String?
  var capturedIsFromAppLink = false
  var wasRegisterAutoResetSourceApplicationCalled = false

  func suspend() {
    suspendWasCalled = true
  }

  func restore(_ calledFromActivateApp: Bool) {
    restoreWasCalled = true
    capturedCalledFromActivateApp = calledFromActivateApp
  }

  func setSourceApplication(_ sourceApplication: String?, open url: URL?) {
    capturedSetSourceApplication = sourceApplication
    capturedSetSourceApplicationURL = url
  }

  func setSourceApplication(_ sourceApplication: String?, isFromAppLink: Bool) {
    capturedSetSourceApplicationFromAppLink = sourceApplication
    capturedIsFromAppLink = isFromAppLink
  }

  func registerAutoResetSourceApplication() {
    wasRegisterAutoResetSourceApplicationCalled = true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
final class TestTokenCache: NSObject, TokenCaching {
  var accessToken: AccessToken?
  var authenticationToken: AuthenticationToken?

  init(
    accessToken: AccessToken? = nil,
    authenticationToken: AuthenticationToken? = nil
  ) {
    self.accessToken = accessToken
    self.authenticationToken = authenticationToken
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestTouch: UITouch {
  var stubbedView: UIView?

  override var view: UIView? {
    stubbedView
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestURLSessionProxy: NSObject, _URLSessionProxying {
  var delegateQueue: OperationQueue?
  /// The most recent captured completion
  var capturedCompletion: UrlSessionTaskBlock?
  /// The most recent captured request
  var capturedRequest: URLRequest?
  /// All captured requests for this networker instance
  var capturedRequests = [URLRequest]()
  var invalidateAndCancelCallCount = 0

  func execute(_ request: URLRequest, completionHandler handler: @escaping UrlSessionTaskBlock) {
    capturedRequest = request
    capturedRequests.append(request)
    capturedCompletion = handler
  }

  func invalidateAndCancel() {
    invalidateAndCancelCallCount += 1
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestURLSessionProxyFactory: NSObject, _URLSessionProxyProviding {
  private var stubbedSessions: [TestURLSessionProxy]

  init(sessions: [TestURLSessionProxy] = []) {
    stubbedSessions = sessions
  }

  /// Creates a new provider stubbed with the `FakeURLSessionProxy`
  ///
  /// If you provide a single session, all calls to `createSessionProxy` will return the same
  /// session instance
  static func create(with session: TestURLSessionProxy) -> TestURLSessionProxyFactory {
    TestURLSessionProxyFactory(sessions: [session])
  }

  /// Creates a new provider stubbed with the `FakeURLSessionProxy`
  ///
  /// If you provide multiple sessions, they will be provided in the order they are requested
  static func create(withSessions sessions: [TestURLSessionProxy]) -> TestURLSessionProxyFactory {
    TestURLSessionProxyFactory(sessions: sessions)
  }

  // MARK: - URLSessionProxyProviding

  func createSessionProxy(with delegate: URLSessionDataDelegate?, queue: OperationQueue?) -> _URLSessionProxying {
    stubbedSessions.count > 1 ? stubbedSessions.removeFirst() : stubbedSessions[0]
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import XCTest

@objcMembers
final class TestUserDataStore: NSObject, _UserDataPersisting {

  var wasGetUserDataCalled = false
  var wasClearUserDataCalled = false
  var capturedEmail: String?
  var capturedFirstName: String?
  var capturedLastName: String?
  var capturedPhone: String?
  var capturedDateOfBirth: String?
  var capturedGender: String?
  var capturedCity: String?
  var capturedState: String?
  var capturedZip: String?
  var capturedCountry: String?
  var capturedExternalId: String?
  var capturedSetUserDataForTypeData: String?
  var capturedSetUserDataForTypeType: FBSDKAppEventUserDataType?
  var capturedClearUserDataForTypeType: FBSDKAppEventUserDataType?
  var getInternalHashedDataForTypeCallCount = 0
  var capturedInternalHashedDataForTypeData: String?
  var capturedInternalHashedDataForTypeType: FBSDKAppEventUserDataType?
  var capturedEnableRules: [String]?

  func setUser( // swiftlint:disable:this function_parameter_count
    email: String?,
    firstName: String?,
    lastName: String?,
    phone: String?,
    dateOfBirth: String?,
    gender: String?,
    city: String?,
    state: String?,
    zip: String?,
    country: String?,
    externalId: String?
  ) {
    capturedEmail = email
    capturedFirstName = firstName
    capturedLastName = lastName
    capturedPhone = phone
    capturedDateOfBirth = dateOfBirth
    capturedGender = gender
    capturedCity = city
    capturedState = state
    capturedZip = zip
    capturedCountry = country
    capturedExternalId = externalId
  }

  func getUserData() -> String? {
    wasGetUserDataCalled = true
    return nil
  }

  func clearUserData() {
    wasClearUserDataCalled = true
  }

  func setUserData(_ data: String?, forType type: FBSDKAppEventUserDataType) {
    capturedSetUserDataForTypeData = data
    capturedSetUserDataForTypeType = type
  }

  func clearUserData(forType type: FBSDKAppEventUserDataType) {
    capturedClearUserDataForTypeType = type
  }

  func setEnabledRules(_ rules: [String]) {
    capturedEnableRules = rules
  }

  func getInternalHashedData(forType type: FBSDKAppEventUserDataType) -> String? {
    getInternalHashedDataForTypeCallCount += 1
    return nil
  }

  func setInternalHashData(_ hashData: String?, forType type: FBSDKAppEventUserDataType) {
    capturedInternalHashedDataForTypeData = hashData
    capturedInternalHashedDataForTypeType = type
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
final class TestUserIDProvider: NSObject, _UserIDProviding {
  var userID: String?
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestView: UIView {
  var stubbedWindow: UIWindow?

  override var window: UIWindow? {
    stubbedWindow
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation
import UIKit

@objcMembers
final class TestViewControllerTransitionCoordinator: NSObject, UIViewControllerTransitionCoordinator {
  var isAnimated = false
  var presentationStyle = UIModalPresentationStyle.none
  var initiallyInteractive = false
  var isInterruptible = false
  var isInteractive = false
  var isCancelled = false
  var transitionDuration: TimeInterval = 0
  var percentComplete: CGFloat = 0
  var completionVelocity: CGFloat = 0
  var completionCurve = UIView.AnimationCurve.easeInOut
  var containerView: UIView = TestView()
  var targetTransform = CGAffineTransform.identity

  func animate(
    alongsideTransition animation: ((UIViewControllerTransitionCoordinatorContext) -> Void)?,
    completion: ((UIViewControllerTransitionCoordinatorContext) -> Void)? = nil
  ) -> Bool {
    capturedAnimateAlongsideTransitionCompletion = completion

    return true
  }

  var capturedAnimateAlongsideTransitionCompletion: ((UIViewControllerTransitionCoordinatorContext) -> Void)?

  func animateAlongsideTransition(
    in view: UIView?,
    animation: ((UIViewControllerTransitionCoordinatorContext) -> Void)?,
    completion: ((UIViewControllerTransitionCoordinatorContext) -> Void)? = nil
  ) -> Bool {
    true
  }

  func notifyWhenInteractionEnds(
    _ handler: @escaping (UIViewControllerTransitionCoordinatorContext) -> Void
  ) {}

  func notifyWhenInteractionChanges(_ handler: @escaping (UIViewControllerTransitionCoordinatorContext) -> Void) {}

  func viewController(forKey key: UITransitionContextViewControllerKey) -> UIViewController? {
    nil
  }

  func view(forKey key: UITransitionContextViewKey) -> UIView? {
    nil
  }
}

@objcMembers
final class TestViewControllerTransitionCoordinatorContext: NSObject, // swiftlint:disable:this type_name
UIViewControllerTransitionCoordinatorContext {
  var isAnimated = false
  var presentationStyle = UIModalPresentationStyle.fullScreen
  var initiallyInteractive = false
  var isInterruptible = false
  var isInteractive = false
  var isCancelled = false
  var transitionDuration: TimeInterval = 0
  var percentComplete: CGFloat = 0
  var completionVelocity: CGFloat = 0
  var completionCurve = UIView.AnimationCurve.easeInOut
  var containerView: UIView = TestView()
  var targetTransform = CGAffineTransform.identity

  func viewController(
    forKey key: UITransitionContextViewControllerKey
  ) -> UIViewController? {
    nil
  }

  func view(
    forKey key: UITransitionContextViewKey
  ) -> UIView? {
    nil
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import WebKit

final class TestWebKitNavigationAction: WKNavigationAction {
  let stubbedRequest: URLRequest
  let stubbedNavigationType: WKNavigationType

  init(
    stubbedRequest: URLRequest,
    navigationType: WKNavigationType = .other
  ) {
    self.stubbedRequest = stubbedRequest
    stubbedNavigationType = navigationType

    super.init()
  }

  override var request: URLRequest {
    stubbedRequest
  }

  override var navigationType: WKNavigationType {
    stubbedNavigationType
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestWebView: UIView, WebView {
  weak var navigationDelegate: WKNavigationDelegate?
  var capturedRequest: URLRequest?
  var stopLoadingCallCount = 0

  func load(_ request: URLRequest) -> WKNavigation? {
    capturedRequest = request
    return nil
  }

  func stopLoading() {
    stopLoadingCallCount += 1
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

final class TestWebViewFactory: _WebViewProviding {
  var capturedFrame: CGRect?
  let webView = TestWebView()

  func createWebView(frame: CGRect) -> WebView {
    capturedFrame = frame
    return webView
  }
}