// OfflineSyncManager.mm
#import "OfflineSyncManager.h"
#import "LocalStorage.h"
#import "NetworkManager.h"
#import "APIClient.h"

static NSString * const kOfflineQueueKey = @"OFFLINE_SYNC_QUEUE";

static NSString * const kSelectedOfflineUnitsKey = @"SELECTED_OFFLINE_UNITS";

@implementation OfflineSyncManager

#pragma mark - Singleton

+ (instancetype)shared {
    static OfflineSyncManager *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[OfflineSyncManager alloc] init];
    });
    return instance;
}

#pragma mark - Queue Helpers (CRITICAL)

- (NSMutableArray *)safeLoadQueue {
    id stored = [LocalStorage loadArrayForKey:kOfflineQueueKey];

    NSLog(@"📦 [OfflineSync] Raw stored queue: %@", stored);

    if (![stored isKindOfClass:[NSArray class]]) {
        NSLog(@"🧹 [OfflineSync] Queue corrupted — resetting");
        [LocalStorage removeObjectForKey:kOfflineQueueKey];
        return [NSMutableArray array];
    }

    NSMutableArray *validItems = [NSMutableArray array];
    for (id obj in stored) {
        if ([obj isKindOfClass:[NSDictionary class]]) {
            [validItems addObject:obj];
        }
    }

    NSLog(@"📦 [OfflineSync] Valid queue items: %@", validItems);

    return validItems;
}

- (void)saveQueue:(NSArray *)queue {
    [LocalStorage saveArray:queue forKey:kOfflineQueueKey];
}

#pragma mark - Public Queue APIs

- (void)queueAddIssue:(NSDictionary *)payload
              display:(NSDictionary *)display
               images:(NSArray<UIImage *> *)images {

    [self enqueueAction:@"ADD_ISSUE"
                payload:payload
                 images:images
            displayInfo:display];
}

- (void)queueUpdateIssue:(NSDictionary *)payload
                 display:(NSDictionary *)display
                  images:(NSArray<UIImage *> *)images {

    [self enqueueAction:@"UPDATE_ISSUE"
                payload:payload
                 images:images
            displayInfo:display];
}

- (void)queueAddInfo:(NSString *)issueID
             remarks:(NSString *)remarks
         displayInfo:(NSDictionary *)displayInfo
              images:(NSArray<UIImage *> *)images
            mediaURL:(NSURL * _Nullable)mediaURL
           mediaType:(NSString * _Nullable)mediaType {

    NSMutableArray *queue = [self safeLoadQueue];

    NSArray *imagePaths = [self saveImagesToDisk:images];
    NSString *mediaPath = [self saveMediaToDisk:mediaURL];

    NSMutableDictionary *item = [NSMutableDictionary dictionary];
    item[@"id"] = NSUUID.UUID.UUIDString;
    item[@"type"] = @"ADD_INFO";

    // 🔥 API payload
    item[@"issue_id"] = issueID ?: @"";
    item[@"remarks"] = remarks ?: @"";

    // 🔥 Files
    item[@"imagePaths"] = imagePaths ?: @[];
    item[@"timestamp"] = @((NSInteger)[NSDate date].timeIntervalSince1970);

    if (mediaPath) item[@"mediaPath"] = mediaPath;
    if (mediaType) item[@"mediaType"] = mediaType;

    // 🔥 UI display fields (CRITICAL)
    item[@"projectName"] = displayInfo[@"projectName"] ?: @"Unknown Project";
    item[@"unitName"] = displayInfo[@"unitName"] ?: @"-";
    item[@"createdBy"] = displayInfo[@"createdBy"] ?: @"-";
    item[@"issueDisplay"] = displayInfo[@"issueDisplay"] ?: @"Add Info";
    item[@"createdAt"] = displayInfo[@"createdAt"] ?: [self todayDateString];

    [queue addObject:item];
    [self saveQueue:queue];

    NSLog(@"📥 [OfflineSync] Queued ADD_INFO (%lu)", (unsigned long)queue.count);
}

#pragma mark - Core Queue Add

- (void)enqueueAction:(NSString *)type
              payload:(NSDictionary *)payload
               images:(NSArray<UIImage *> *)images
          displayInfo:(NSDictionary *)displayInfo {
    
    NSMutableArray *queue = [self safeLoadQueue];
    NSArray *imagePaths = [self saveImagesToDisk:images];

    NSMutableDictionary *item = [NSMutableDictionary dictionary];
    item[@"id"] = NSUUID.UUID.UUIDString;
    item[@"type"] = type;
    item[@"payload"] = payload ?: @{};
    item[@"imagePaths"] = imagePaths ?: @[];
    item[@"timestamp"] = @((NSInteger)[NSDate date].timeIntervalSince1970);

    // 🔥 UI fields (OG-style)
    item[@"projectName"] = displayInfo[@"projectName"] ?: @"Unknown Project";
    item[@"unitName"] = displayInfo[@"unitName"] ?: @"-";
    item[@"createdBy"] = displayInfo[@"createdBy"] ?: @"-";
    item[@"issueDisplay"] = displayInfo[@"issueDisplay"] ?: type;
    item[@"createdAt"] = displayInfo[@"createdAt"] ?: [self todayDateString];

    [queue addObject:item];
    [self saveQueue:queue];

    NSLog(@"📥 [OfflineSync] Queued %@ (%lu)", type, (unsigned long)queue.count);
}


#pragma mark - Processing Queue

- (void)startManualSync {

    if (![NetworkManager.sharedManager isConnected]) {
        NSLog(@"🚫 [OfflineSync] No internet — aborting manual sync");
        return;
    }

    [self processNextItem];
}

- (void)processNextItem {

    NSMutableArray *queue = [self safeLoadQueue];
    if (queue.count == 0) {
        NSLog(@"✅ [OfflineSync] Queue empty — sync complete");
        return;
    }

    NSDictionary *item = queue.firstObject;
    if (![item isKindOfClass:[NSDictionary class]]) {
        NSLog(@"⚠️ [OfflineSync] Invalid item — removing");
        [queue removeObjectAtIndex:0];
        [self saveQueue:queue];
        [self processNextItem];
        return;
    }

    NSLog(@"🔄 [OfflineSync] Processing %@", item[@"type"]);

    [self processItem:item completion:^(BOOL success) {

        if (success) {
            NSLog(@"✅ [OfflineSync] Item synced");

            // 🔥 cleanup files
            for (NSString *path in item[@"imagePaths"]) {
                [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
            }
            if (item[@"mediaPath"]) {
                [[NSFileManager defaultManager] removeItemAtPath:item[@"mediaPath"] error:nil];
            }

            // remove item and continue
            NSMutableArray *updatedQueue = [self safeLoadQueue];
            if (updatedQueue.count > 0) {
                [updatedQueue removeObjectAtIndex:0];
                [self saveQueue:updatedQueue];
            }

            [self processNextItem]; // move to next
        } else {
            NSLog(@"❌ [OfflineSync] Sync failed — stopping");
            // ❗ DO NOT remove item
            // user must tap Sync again
        }
    }];
}

- (void)processItem:(NSDictionary *)item
         completion:(void (^)(BOOL success))completion {

    NSString *type = item[@"type"] ?: @"";

    if ([type isEqualToString:@"ADD_INFO"]) {

        NSArray *images = [self loadImagesFromPaths:item[@"imagePaths"]];
        NSURL *mediaURL = item[@"mediaPath"] ? [NSURL fileURLWithPath:item[@"mediaPath"]] : nil;

        BOOL hasImages = images.count > 0;
        BOOL hasMedia = mediaURL != nil;

        if (!hasImages && !hasMedia) {
            [APIClient submitAddInfo:item[@"issue_id"]
                             remarks:item[@"remarks"]
                           completion:^(NSDictionary *r, NSError *e) {
                completion(e == nil);
            }];
        } else {
            [APIClient uploadAddInfo:item[@"issue_id"]
                             remarks:item[@"remarks"]
                              images:images
                            mediaURL:mediaURL
                           mediaType:item[@"mediaType"]
                          completion:^(NSDictionary *r, NSError *e) {
                completion(e == nil);
            }];
        }
        return;
    }

    NSLog(@"⚠️ Unknown offline type: %@", type);
    completion(NO);
}

#pragma mark - Disk Handling

- (NSArray *)saveImagesToDisk:(NSArray<UIImage *> *)images {

    NSMutableArray *paths = [NSMutableArray array];
    if (![images isKindOfClass:[NSArray class]]) return paths;

    NSString *dir = [self offlineDirectory];

    for (id obj in images) {
        if (![obj isKindOfClass:[UIImage class]]) continue;

        NSString *path = [dir stringByAppendingPathComponent:
                          [NSString stringWithFormat:@"%@.jpg", NSUUID.UUID.UUIDString]];

        NSData *data = UIImageJPEGRepresentation(obj, 0.8);
        if (data && [data writeToFile:path atomically:YES]) {
            [paths addObject:path];
        }
    }
    return paths;
}

- (NSString *)saveMediaToDisk:(NSURL *)url {

    if (!url) return nil;

    NSString *dir = [self offlineDirectory];
    NSString *path = [dir stringByAppendingPathComponent:
                      [NSString stringWithFormat:@"%@.%@",
                       NSUUID.UUID.UUIDString, url.pathExtension]];

    NSData *data = [NSData dataWithContentsOfURL:url];
    if ([data writeToFile:path atomically:YES]) {
        return path;
    }
    return nil;
}

- (NSArray *)loadImagesFromPaths:(NSArray *)paths {

    NSMutableArray *images = [NSMutableArray array];
    for (NSString *path in paths) {
        UIImage *img = [UIImage imageWithContentsOfFile:path];
        if (img) [images addObject:img];
    }
    return images;
}

- (NSString *)offlineDirectory {

    NSString *dir = NSSearchPathForDirectoriesInDomains(
        NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
    dir = [dir stringByAppendingPathComponent:@"offline_files"];

    if (![[NSFileManager defaultManager] fileExistsAtPath:dir]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:dir
                                  withIntermediateDirectories:YES
                                                   attributes:nil
                                                        error:nil];
    }
    return dir;
}

#pragma mark - Status
- (BOOL)hasPendingItems {
    return ([self safeLoadQueue].count > 0);
}

#pragma mark - Pending Screen Helper
- (NSArray *)pendingItemsForUI {

    NSArray *queue = [self safeLoadQueue];
    NSMutableDictionary *grouped = [NSMutableDictionary dictionary];

    for (NSDictionary *item in queue) {

        NSString *project = item[@"projectName"] ?: @"Unknown Project";
        NSMutableArray *items = grouped[project] ?: [NSMutableArray array];

        NSDictionary *uiItem = @{
            @"unitName": item[@"unitName"] ?: @"-",
            @"createdBy": item[@"createdBy"] ?: @"-",
            @"createdOn": item[@"createdAt"] ?: [self formatTimestamp:item[@"timestamp"]],
            @"type": item[@"issueDisplay"] ?: item[@"type"] ?: @"-",
            @"raw": item
        };

        [items addObject:uiItem];
        grouped[project] = items;
    }

    NSMutableArray *sections = [NSMutableArray array];
    for (NSString *project in grouped) {
        [sections addObject:@{
            @"project": project,
            @"items": grouped[project]
        }];
    }

    return sections;
}

- (NSString *)formatTimestamp:(NSNumber *)ts {
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:ts.doubleValue];
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"yyyy-MM-dd";
    return [fmt stringFromDate:date];
}

- (NSString *)todayDateString {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    formatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
    formatter.dateFormat = @"yyyy-MM-dd";
    return [formatter stringFromDate:[NSDate date]];
}

- (void)clearOfflineQueue {
    [LocalStorage removeObjectForKey:kOfflineQueueKey];
    NSLog(@"🧹 [OfflineSync] Offline queue cleared");
}

@end
