#if OCTAGON
@class CKKSKeychainView;
#import "keychain/ckks/CKKSGroupOperation.h"
-#import "keychain/ckks/CKKSZoneChangeFetcher.h"
+#import "keychain/ckks/CloudKitDependencies.h"
NS_ASSUME_NONNULL_BEGIN
+/* Fetch Reasons */
+@protocol CKKSFetchBecauseProtocol <NSObject>
+@end
+typedef NSString<CKKSFetchBecauseProtocol> CKKSFetchBecause;
+extern CKKSFetchBecause* const CKKSFetchBecauseAPNS;
+extern CKKSFetchBecause* const CKKSFetchBecauseAPIFetchRequest;
+extern CKKSFetchBecause* const CKKSFetchBecauseCurrentItemFetchRequest;
+extern CKKSFetchBecause* const CKKSFetchBecauseInitialStart;
+extern CKKSFetchBecause* const CKKSFetchBecauseSecuritydRestart;
+extern CKKSFetchBecause* const CKKSFetchBecausePreviousFetchFailed;
+extern CKKSFetchBecause* const CKKSFetchBecauseKeyHierarchy;
+extern CKKSFetchBecause* const CKKSFetchBecauseTesting;
+extern CKKSFetchBecause* const CKKSFetchBecauseResync;
+
+/* Clients that register to use fetches */
+@interface CKKSCloudKitFetchRequest : NSObject
+@property bool participateInFetch;
+
+// If true, you will receive YES in the resync parameter to your callback.
+// You may also receive YES to your callback if a resync has been triggered for you.
+// It does nothing else. Use as you see fit.
+// Note: you will receive exactly one callback with moreComing=0 and resync=1 for each
+// resync fetch. You may then receive further callbacks with resync=0 during the same fetch,
+// if other clients keep needing fetches.
+@property BOOL resync;
+
+@property (nullable) CKServerChangeToken* changeToken;
+@end
+
+@class CKKSCloudKitDeletion;
+
+@protocol CKKSChangeFetcherClient <NSObject>
+- (CKRecordZoneID*)zoneID;
+- (BOOL)zoneIsReadyForFetching;
+- (CKKSCloudKitFetchRequest*)participateInFetch;
+
+// Return false if this is a 'fatal' error and you don't want another fetch to be tried
+- (bool)shouldRetryAfterFetchError:(NSError*)error;
+
+- (void)changesFetched:(NSArray<CKRecord*>*)changedRecords
+ deletedRecordIDs:(NSArray<CKKSCloudKitDeletion*>*)deleted
+ newChangeToken:(CKServerChangeToken*)changeToken
+ moreComing:(BOOL)moreComing
+ resync:(BOOL)resync;
+@end
+
+// I don't understand why recordType isn't part of record ID, but deletions come in as both things
+@interface CKKSCloudKitDeletion : NSObject
+@property CKRecordID* recordID;
+@property NSString* recordType;
+- (instancetype)initWithRecordID:(CKRecordID*)recordID recordType:(NSString*)recordType;
+@end
+
+
@interface CKKSFetchAllRecordZoneChangesOperation : CKKSGroupOperation
+@property (readonly) Class<CKKSFetchRecordZoneChangesOperation> fetchRecordZoneChangesOperationClass;
+@property (readonly) CKContainer* container;
// Set this to true before starting this operation if you'd like resync behavior:
// Fetching everything currently in CloudKit and comparing to local copy
@property bool resync;
-@property (nullable, weak) CKKSKeychainView* ckks;
-@property CKRecordZoneID* zoneID;
+@property (nullable) NSMutableArray<CKRecordZoneID*>* fetchedZoneIDs;
@property NSSet<CKKSFetchBecause*>* fetchReasons;
+@property NSSet<CKRecordZoneNotification*>* apnsPushes;
@property NSMutableDictionary<CKRecordID*, CKRecord*>* modifications;
-@property NSMutableDictionary<CKRecordID*, NSString*>* deletions;
-
-@property (nullable) CKServerChangeToken* serverChangeToken;
+@property NSMutableDictionary<CKRecordID*, CKKSCloudKitDeletion*>* deletions;
+@property NSMutableDictionary<CKRecordZoneID*, CKServerChangeToken*>* changeTokens;
- (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks
- fetchReasons:(NSSet<CKKSFetchBecause*>*)fetchReasons
- ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
+- (instancetype)initWithContainer:(CKContainer*)container
+ fetchClass:(Class<CKKSFetchRecordZoneChangesOperation>)fetchRecordZoneChangesOperationClass
+ clients:(NSArray<id<CKKSChangeFetcherClient>>*)clients
+ fetchReasons:(NSSet<CKKSFetchBecause*>*)fetchReasons
+ apnsPushes:(NSSet<CKRecordZoneNotification*>* _Nullable)apnsPushes
+ forceResync:(bool)forceResync
+ ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
@end