#import "PhotoAlbum.h"

@interface SCIPhotoAlbumWatcher : NSObject <PHPhotoLibraryChangeObserver>
@property (nonatomic, strong) PHFetchResult<PHAsset *> *baseline;
@property (nonatomic, strong) NSTimer *timeoutTimer;
@end

static SCIPhotoAlbumWatcher *sciActiveWatcher = nil;

@implementation SCIPhotoAlbum

+ (NSString *)albumName {
    return @"RyukGram";
}

+ (void)fetchOrCreateAlbumWithCompletion:(void (^)(PHAssetCollection *, NSError *))completion {
    PHFetchOptions *opts = [[PHFetchOptions alloc] init];
    opts.predicate = [NSPredicate predicateWithFormat:@"title = %@", [self albumName]];
    PHFetchResult<PHAssetCollection *> *result = [PHAssetCollection
        fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
                              subtype:PHAssetCollectionSubtypeAlbumRegular
                              options:opts];
    if (result.count > 0) {
        if (completion) completion(result.firstObject, nil);
        return;
    }

    __block NSString *placeholderId = nil;
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        PHAssetCollectionChangeRequest *req = [PHAssetCollectionChangeRequest
            creationRequestForAssetCollectionWithTitle:[self albumName]];
        placeholderId = req.placeholderForCreatedAssetCollection.localIdentifier;
    } completionHandler:^(BOOL success, NSError *error) {
        if (!success || !placeholderId) {
            if (completion) completion(nil, error);
            return;
        }
        PHFetchResult<PHAssetCollection *> *fetched = [PHAssetCollection
            fetchAssetCollectionsWithLocalIdentifiers:@[placeholderId] options:nil];
        if (completion) completion(fetched.firstObject, nil);
    }];
}

+ (void)saveFileToAlbum:(NSURL *)fileURL completion:(void (^)(BOOL, NSError *))completion {
    [self fetchOrCreateAlbumWithCompletion:^(PHAssetCollection *album, NSError *err) {
        if (!album) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (completion) completion(NO, err);
            });
            return;
        }

        __block NSString *assetId = nil;
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            NSString *ext = [[fileURL pathExtension] lowercaseString];
            BOOL isVideo = [@[@"mp4", @"mov", @"m4v"] containsObject:ext];

            PHAssetCreationRequest *req = [PHAssetCreationRequest creationRequestForAsset];
            PHAssetResourceCreationOptions *opts = [[PHAssetResourceCreationOptions alloc] init];
            opts.shouldMoveFile = YES;
            [req addResourceWithType:(isVideo ? PHAssetResourceTypeVideo : PHAssetResourceTypePhoto)
                             fileURL:fileURL options:opts];
            req.creationDate = [NSDate date];
            assetId = req.placeholderForCreatedAsset.localIdentifier;

            PHAssetCollectionChangeRequest *albumReq =
                [PHAssetCollectionChangeRequest changeRequestForAssetCollection:album];
            [albumReq addAssets:@[req.placeholderForCreatedAsset]];
        } completionHandler:^(BOOL success, NSError *changeErr) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (completion) completion(success, changeErr);
            });
        }];
    }];
}

+ (void)watchForNextSavedAsset {
    // Replace any existing watcher — only the most recent share sheet matters
    if (sciActiveWatcher) {
        [[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:sciActiveWatcher];
        [sciActiveWatcher.timeoutTimer invalidate];
        sciActiveWatcher = nil;
    }

    if ([PHPhotoLibrary authorizationStatus] != PHAuthorizationStatusAuthorized &&
        [PHPhotoLibrary authorizationStatus] != PHAuthorizationStatusLimited) {
        return;
    }

    SCIPhotoAlbumWatcher *watcher = [[SCIPhotoAlbumWatcher alloc] init];
    PHFetchOptions *opts = [[PHFetchOptions alloc] init];
    opts.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
    watcher.baseline = [PHAsset fetchAssetsWithOptions:opts];
    [[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:watcher];

    // Auto-unregister after 60s in case the user dismisses without saving
    watcher.timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:60.0
                                                           repeats:NO
                                                             block:^(NSTimer *t) {
        if (sciActiveWatcher == watcher) {
            [[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:watcher];
            sciActiveWatcher = nil;
        }
    }];
    sciActiveWatcher = watcher;
}

@end

@implementation SCIPhotoAlbumWatcher

- (void)photoLibraryDidChange:(PHChange *)changeInstance {
    PHFetchResultChangeDetails *details = [changeInstance changeDetailsForFetchResult:self.baseline];
    if (!details || details.insertedObjects.count == 0) return;

    NSArray<PHAsset *> *inserted = details.insertedObjects;
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        [SCIPhotoAlbum fetchOrCreateAlbumWithCompletion:^(PHAssetCollection *album, NSError *err) {}];
    } completionHandler:^(BOOL success, NSError *error) {
        // Add the inserted assets to the album in a separate transaction so the
        // album exists by the time we reference it.
        [SCIPhotoAlbum fetchOrCreateAlbumWithCompletion:^(PHAssetCollection *album, NSError *err) {
            if (!album) return;
            [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
                PHAssetCollectionChangeRequest *req =
                    [PHAssetCollectionChangeRequest changeRequestForAssetCollection:album];
                [req addAssets:inserted];
            } completionHandler:nil];
        }];
    }];

    // One-shot
    [[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:self];
    [self.timeoutTimer invalidate];
    self.timeoutTimer = nil;
    if (sciActiveWatcher == self) sciActiveWatcher = nil;
}

@end
