//
//  CKNotification.h

//  CloudKit
//
//  Copyright (c) 2014 Apple Inc. All rights reserved.
//

#import <Foundation/Foundation.h>

#import <CloudKit/CKDatabase.h>
#import <CloudKit/CKRecord.h>

@class CKRecordID, CKRecordZoneID;

NS_HEADER_AUDIT_BEGIN(nullability, sendability)

API_AVAILABLE(macos(10.10), ios(8.0), watchos(3.0))
CK_SUBCLASSING_DEPRECATED // should not be subclassed, or Sendable may no longer apply
// NS_SWIFT_SENDABLE on swift(4.2)
@interface CKNotificationID : NSObject <NSCopying, NSSecureCoding>
@end

typedef NS_ENUM(NSInteger, CKNotificationType) {
    /// Generated by ``CKQuerySubscription``s
    CKNotificationTypeQuery            = 1,

    /// Generated by ``CKRecordZoneSubscription``s
    CKNotificationTypeRecordZone       = 2,

    /// Indicates a notification that a client had previously marked as read
    CKNotificationTypeReadNotification = 3,

    /// Generated by ``CKDatabaseSubscription``s
    CKNotificationTypeDatabase         API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)) = 4,
} API_AVAILABLE(macos(10.10), ios(8.0), watchos(3.0));

/// Pushes from CloudKit servers contain both CloudKit-specific and APS-specific information.
/// APS-specific information includes elements like alerts, badges, sounds, categories, etc.
/// When receiving a push from CloudKit servers, the push may be delivered via multiple API flows.
/// The flow(s) chosen will depend on the type of push requested (e.g. via the ``CKSubscription``
/// that triggered it and its configured `notificationInfo`).
///
/// Pushes with UI elements (alerts, badges, sounds):
/// These pushes are delivered via the `UserNotifications` framework, in the form of a `UNNotification`
/// Applications should use the `UserNotifications` framework to interact with the UI elements of this push.
/// Applications may create a ``CKNotification`` from a `UNNotification` in their `UNUserNotificationCenterDelegate`:
///
///     func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
///         let ckNotification = CKNotification(fromRemoteNotificationDictionary: notification.request.content.userInfo)
///     }
///
/// Pushes with `content-available`:
/// These pushes are delivered via an application delegate, in the form of a remote notification.
/// For example: `UIApplicationDelegate.application(_:didReceiveRemoteNotification:) async`
/// Applications do not need to interact with any UI element in the push payload argument, that's intended to be handled via the `UserNotifications` flow
/// (a push with both UI elements and `content-available` will be delivered via both API flows)
/// Applications may create a ``CKNotification`` from the remote notification in their `UIApplicationDelegate`:
///
///     func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult {
///         let ckNotification = CKNotification(fromRemoteNotificationDictionary: userInfo)
///     }
API_AVAILABLE(macos(10.10), ios(8.0), watchos(3.0))
// This class should not be subclassed. If it is, Sendable may no longer apply.
NS_SWIFT_SENDABLE
@interface CKNotification : NSObject

- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

+ (nullable instancetype)notificationFromRemoteNotificationDictionary:(NSDictionary *)notificationDictionary;

/// When you instantiate a ``CKNotification`` from a remote notification dictionary, you will get back a concrete
/// subclass defined below.  Use `notificationType` to avoid `as?` or `-isKindOfClass:` checks.
@property (readonly, assign, nonatomic) CKNotificationType notificationType;

@property (nullable, readonly, copy, nonatomic) CKNotificationID *notificationID;

@property (nullable, readonly, copy, nonatomic) NSString *containerIdentifier;

/// The user `recordID` of the owner of the subscription for which this notification was generated
@property (nullable, readonly, copy, nonatomic) CKRecordID *subscriptionOwnerUserRecordID API_AVAILABLE(macos(10.15), ios(13.0), tvos(13.0), watchos(6.0));

/// Whether or not the notification fully represents what the server wanted to send.
///
/// Push notifications have a limited size.  In some cases, CloudKit servers may not be able to send you a full ``CKNotification``'s worth of info in one push.
/// In those cases, `isPruned` returns `true`.
/// The order in which properties are dropped from a push notification is defined in each ``CKNotification`` subclass below.
@property (readonly, assign, nonatomic) BOOL isPruned;

/// The ID of the subscription that caused this notification to fire.
@property (nullable, readonly, copy, nonatomic) CKSubscriptionID subscriptionID API_AVAILABLE(macos(10.11), ios(9.0), watchos(3.0));

@end

API_DEPRECATED_BEGIN("Interact with UI elements of a CloudKit-server-generated push message via UserNotifications.framework", macos(10.10, 14.0), ios(8.0, 17.0), tvos(9.0, 17.0), watchos(3.0, 10.0))
@interface CKNotification (DeprecatedAPSProperties)
@property (nullable, readonly, copy, nonatomic) NSString *alertBody __TVOS_PROHIBITED;
@property (nullable, readonly, copy, nonatomic) NSString *alertLocalizationKey __TVOS_PROHIBITED;
@property (nullable, readonly, copy, nonatomic) NSArray<NSString *> *alertLocalizationArgs __TVOS_PROHIBITED;
@property (nullable, readonly, copy, nonatomic) NSString *title __TVOS_PROHIBITED API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0));
@property (nullable, readonly, copy, nonatomic) NSString *titleLocalizationKey __TVOS_PROHIBITED API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0));
@property (nullable, readonly, copy, nonatomic) NSArray<NSString *> *titleLocalizationArgs __TVOS_PROHIBITED API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0));
@property (nullable, readonly, copy, nonatomic) NSString *subtitle __TVOS_PROHIBITED API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0));
@property (nullable, readonly, copy, nonatomic) NSString *subtitleLocalizationKey __TVOS_PROHIBITED API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0));
@property (nullable, readonly, copy, nonatomic) NSArray<NSString *> *subtitleLocalizationArgs __TVOS_PROHIBITED API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0));
@property (nullable, readonly, copy, nonatomic) NSString *alertActionLocalizationKey __TVOS_PROHIBITED;
@property (nullable, readonly, copy, nonatomic) NSString *alertLaunchImage __TVOS_PROHIBITED;
@property (nullable, readonly, copy, nonatomic) NSNumber *badge API_AVAILABLE(tvos(10.0));
@property (nullable, readonly, copy, nonatomic) NSString *soundName __TVOS_PROHIBITED;
@property (nullable, readonly, copy, nonatomic) NSString *category __TVOS_PROHIBITED API_AVAILABLE(macos(10.11), ios(9.0), watchos(3.0));
@end
API_DEPRECATED_END // macos(10.10, 14.0), ios(8.0, 17.0), tvos(9.0, 17.0), watchos(3.0, 10.0))

typedef NS_ENUM(NSInteger, CKQueryNotificationReason) {
    CKQueryNotificationReasonRecordCreated = 1,
    CKQueryNotificationReasonRecordUpdated,
    CKQueryNotificationReasonRecordDeleted,
} API_AVAILABLE(macos(10.10), ios(8.0), watchos(3.0));

/// A notification generated by a ``CKQuerySubscription``
///
/// `notificationType` == `.query`
/// When properties must be dropped (see @c isPruned), here's the order of importance.  The most important properties are first, they'll be the last ones to be dropped.
/// - notificationID
/// - badge
/// - alertLocalizationKey
/// - alertLocalizationArgs
/// - alertBody
/// - alertActionLocalizationKey
/// - alertLaunchImage
/// - soundName
/// - content-available
/// - desiredKeys
/// - queryNotificationReason
/// - recordID
/// - containerIdentifier
/// - subscriptionOwnerUserRecordID
/// - titleLocalizationKey
/// - titleLocalizationArgs
/// - title
/// - subtitleLocalizationKey
/// - subtitleLocalizationArgs
/// - subtitle
API_AVAILABLE(macos(10.10), ios(8.0), watchos(3.0))
CK_SUBCLASSING_DEPRECATED // should not be subclassed, or Sendable may no longer apply
NS_SWIFT_SENDABLE
@interface CKQueryNotification : CKNotification

@property (readonly, assign, nonatomic) CKQueryNotificationReason queryNotificationReason;

/// A set of key->value pairs for creates and updates.
///
/// You request the server fill out this property via the `desiredKeys` property of `CKSubscription.NotificationInfo`
@property (nullable, readonly, copy, nonatomic) NSDictionary<NSString *, id> *recordFields;

@property (nullable, readonly, copy, nonatomic) CKRecordID *recordID;

@property (readonly, assign, nonatomic) CKDatabaseScope databaseScope API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0));

@end


/// A notification generated by a ``CKRecordZoneSubscription``
///
/// `notificationType` == `.recordZone`
/// When properties must be dropped (see @c isPruned), here's the order of importance.  The most important properties are first, they'll be the last ones to be dropped.
/// - notificationID
/// - badge
/// - alertLocalizationKey
/// - alertLocalizationArgs
/// - alertBody
/// - alertActionLocalizationKey
/// - alertLaunchImage
/// - soundName
/// - content-available
/// - recordZoneID
/// - containerIdentifier
/// - subscriptionOwnerUserRecordID
/// - titleLocalizationKey
/// - titleLocalizationArgs
/// - title
/// - subtitleLocalizationKey
/// - subtitleLocalizationArgs
/// - subtitle
API_AVAILABLE(macos(10.10), ios(8.0), watchos(3.0))
CK_SUBCLASSING_DEPRECATED // should not be subclassed, or Sendable may no longer apply
NS_SWIFT_SENDABLE
@interface CKRecordZoneNotification : CKNotification

@property (nullable, readonly, copy, nonatomic) CKRecordZoneID *recordZoneID;

@property (readonly, assign, nonatomic) CKDatabaseScope databaseScope API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0));

@end


/// A notification generated by a ``CKDatabaseSubscription``
///
/// `notificationType` == `.database`
/// When properties must be dropped (see @c isPruned), here's the order of importance.  The most important properties are first, they'll be the last ones to be dropped.
/// - notificationID
/// - badge
/// - alertLocalizationKey
/// - alertLocalizationArgs
/// - alertBody
/// - alertActionLocalizationKey
/// - alertLaunchImage
/// - soundName
/// - content-available
/// - containerIdentifier
/// - subscriptionOwnerUserRecordID
/// - titleLocalizationKey
/// - titleLocalizationArgs
/// - title
/// - subtitleLocalizationKey
/// - subtitleLocalizationArgs
/// - subtitle
API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0))
CK_SUBCLASSING_DEPRECATED // should not be subclassed, or Sendable may no longer apply
NS_SWIFT_SENDABLE
@interface CKDatabaseNotification : CKNotification

@property (readonly, assign, nonatomic) CKDatabaseScope databaseScope;

@end

NS_HEADER_AUDIT_END(nullability, sendability)
