#import "ModuleLoaderModule.h"
#import <React/RCTBridge+Private.h>
#import <React/RCTBridge.h>
#import <React/RCTUtils.h>
#import <React/RCTLog.h>
#import <objc/runtime.h>
#import <jsi/jsi.h>

using namespace facebook;

@implementation ModuleLoaderModule

RCT_EXPORT_MODULE(ModuleLoader);

// 合成 bridge 属性（RCTBridgeModule 协议要求）
@synthesize bridge = _bridge;

// Bundle manifest file name
static NSString *const BundleManifestFileName = @"bundle-manifest.json";

// CodePush 相关常量
static NSString *const CodePushFolderPrefix = @"CodePush";
static NSString *const StatusFileName = @"codepush.json";
static NSString *const CurrentPackageKey = @"currentPackage";

#pragma mark - Bundle Path Resolution

/**
 * 获取 bundle 文件的完整路径
 */
- (NSString *)getFullBundlePath:(NSString *)bundlePath {
    NSString *fileName = [bundlePath lastPathComponent];
    NSString *relativePath = bundlePath;

    if ([bundlePath containsString:@"modules/"]) {
        fileName = [bundlePath lastPathComponent];
        relativePath = [NSString stringWithFormat:@"modules/%@", fileName];
    }

    NSMutableArray<NSString *> *searchPaths = [NSMutableArray array];

    // CodePush 路径
    NSString *codePushPath = [self getCodePushBundlePath:bundlePath];
    if (codePushPath) {
        [searchPaths addObject:codePushPath];
    }

    // MainBundle/Bundles/modules/xxx.jsbundle
    NSString *path1 = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:[@"Bundles/" stringByAppendingString:relativePath]];
    if (path1) [searchPaths addObject:path1];

    // MainBundle/Bundles/xxx.jsbundle
    NSString *path2 = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:[@"Bundles/" stringByAppendingString:fileName]];
    if (path2) [searchPaths addObject:path2];

    // MainBundle 根目录
    NSString *path3 = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:bundlePath];
    if (path3) [searchPaths addObject:path3];

    NSString *path4 = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:fileName];
    if (path4) [searchPaths addObject:path4];

    // resourcePath
    NSString *path5 = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:bundlePath];
    if (path5) [searchPaths addObject:path5];

    NSString *path6 = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:fileName];
    if (path6) [searchPaths addObject:path6];

    // Documents 目录
    NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    if (documentsPath) {
        NSString *path7 = [documentsPath stringByAppendingPathComponent:bundlePath];
        if (path7) [searchPaths addObject:path7];
    }

    for (NSString *fullPath in searchPaths) {
        if (fullPath && [[NSFileManager defaultManager] fileExistsAtPath:fullPath]) {
            RCTLogInfo(@"[ModuleLoader] Found bundle at: %@", fullPath);
            return fullPath;
        }
    }

    RCTLogWarn(@"[ModuleLoader] Bundle not found: %@", bundlePath);
    for (NSString *path in searchPaths) {
        if (path) RCTLogWarn(@"[ModuleLoader]   - %@", path);
    }

    return nil;
}

#pragma mark - CodePush Bundle Path Resolution

/**
 * 获取 CodePush 基础目录
 * 路径: <ApplicationSupport>/CodePush/ 或 <Documents>/CodePush/
 */
- (NSString *)getCodePushPath {
    // 优先使用 Application Support 目录
    NSString *appSupportPath = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) firstObject];
    NSString *codePushPath = [appSupportPath stringByAppendingPathComponent:CodePushFolderPrefix];

    if ([[NSFileManager defaultManager] fileExistsAtPath:codePushPath]) {
        return codePushPath;
    }

    // 回退到 Documents 目录
    NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    codePushPath = [documentsPath stringByAppendingPathComponent:CodePushFolderPrefix];

    if ([[NSFileManager defaultManager] fileExistsAtPath:codePushPath]) {
        return codePushPath;
    }

    return nil;
}

/**
 * 获取当前 CodePush 包的 hash
 * 从 <CodePushPath>/codepush.json 读取 currentPackage 字段
 */
- (NSString *)getCurrentPackageHash {
    NSString *codePushPath = [self getCodePushPath];
    if (!codePushPath) {
        return nil;
    }

    NSString *statusFilePath = [codePushPath stringByAppendingPathComponent:StatusFileName];

    if (![[NSFileManager defaultManager] fileExistsAtPath:statusFilePath]) {
        RCTLogInfo(@"[ModuleLoader] CodePush status file not found: %@", statusFilePath);
        return nil;
    }

    @try {
        NSData *data = [NSData dataWithContentsOfFile:statusFilePath];
        if (!data) {
            return nil;
        }

        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSString *packageHash = json[CurrentPackageKey];

        if (packageHash && packageHash.length > 0) {
            RCTLogInfo(@"[ModuleLoader] Current CodePush package hash: %@", packageHash);
            return packageHash;
        }
    } @catch (NSException *exception) {
        RCTLogWarn(@"[ModuleLoader] Error reading CodePush status: %@", exception.reason);
    }

    return nil;
}

/**
 * 获取 CodePush 包目录路径
 * 路径: <CodePushPath>/<packageHash>/
 */
- (NSString *)getPackageFolderPath:(NSString *)packageHash {
    NSString *codePushPath = [self getCodePushPath];
    if (!codePushPath) {
        return nil;
    }
    return [codePushPath stringByAppendingPathComponent:packageHash];
}

/**
 * 在指定文件夹中查找 bundle 文件
 *
 * 查找顺序：
 * 1. <folder>/modules/<bundleFileName>
 * 2. <folder>/<bundlePath>
 * 3. <folder>/<bundleFileName>
 */
- (NSString *)findBundleInFolder:(NSString *)folderPath
                      bundlePath:(NSString *)bundlePath
                  bundleFileName:(NSString *)bundleFileName {
    NSFileManager *fileManager = [NSFileManager defaultManager];

    BOOL isDirectory;
    if (![fileManager fileExistsAtPath:folderPath isDirectory:&isDirectory] || !isDirectory) {
        return nil;
    }

    NSArray<NSString *> *searchPaths = @[
        [folderPath stringByAppendingPathComponent:[@"modules/" stringByAppendingString:bundleFileName]],
        [folderPath stringByAppendingPathComponent:bundlePath],
        [folderPath stringByAppendingPathComponent:bundleFileName]
    ];

    for (NSString *path in searchPaths) {
        if ([fileManager fileExistsAtPath:path]) {
            return path;
        }
    }

    return nil;
}

/**
 * 获取所有 package 目录，按修改时间从新到旧排序
 * 排除当前 package 和非 package 目录/文件
 */
- (NSArray<NSString *> *)getPackageFoldersSortedByTime:(NSString *)codePushDir
                                    currentPackageHash:(NSString *)currentPackageHash {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSSet *excludedNames = [NSSet setWithArray:@[StatusFileName, @"download", @"unzipped"]];

    NSError *error;
    NSArray<NSString *> *contents = [fileManager contentsOfDirectoryAtPath:codePushDir error:&error];
    if (error || !contents) {
        return @[];
    }

    NSMutableArray<NSDictionary *> *packageFolders = [NSMutableArray array];

    for (NSString *name in contents) {
        // 排除非 package 目录
        if ([excludedNames containsObject:name]) {
            continue;
        }
        if (currentPackageHash && [name isEqualToString:currentPackageHash]) {
            continue;
        }

        NSString *fullPath = [codePushDir stringByAppendingPathComponent:name];
        BOOL isDirectory;
        if ([fileManager fileExistsAtPath:fullPath isDirectory:&isDirectory] && isDirectory) {
            NSDictionary *attrs = [fileManager attributesOfItemAtPath:fullPath error:nil];
            NSDate *modDate = attrs[NSFileModificationDate] ?: [NSDate distantPast];
            [packageFolders addObject:@{@"path": fullPath, @"date": modDate}];
        }
    }

    // 按修改时间从新到旧排序
    [packageFolders sortUsingComparator:^NSComparisonResult(NSDictionary *a, NSDictionary *b) {
        return [b[@"date"] compare:a[@"date"]];
    }];

    NSMutableArray<NSString *> *sortedPaths = [NSMutableArray array];
    for (NSDictionary *folder in packageFolders) {
        [sortedPaths addObject:folder[@"path"]];
    }

    return sortedPaths;
}

/**
 * 从 CodePush 目录查找子 bundle 文件
 *
 * 查找优先级（解决增量更新只包含变化 bundle 的问题）：
 * 1. 当前 package hash 目录
 * 2. 按时间从新到旧遍历其他 package hash 目录
 * 3. 如果都找不到，返回 nil，由调用方从内置目录加载
 *
 * @param bundlePath 原始 bundle 路径，如 "modules/home.jsbundle"
 * @return 完整的文件路径，如果不存在返回 nil
 */
- (NSString *)getCodePushBundlePath:(NSString *)bundlePath {
    NSString *codePushDir = [self getCodePushPath];

    // CodePush 目录不存在，直接返回 nil
    if (!codePushDir) {
        RCTLogInfo(@"[ModuleLoader] CodePush directory not found, will load from MainBundle");
        return nil;
    }

    NSString *bundleFileName = [bundlePath lastPathComponent];
    NSString *currentPackageHash = [self getCurrentPackageHash];

    // 1️⃣ 优先从当前 package hash 目录查找
    if (currentPackageHash) {
        NSString *currentPackageFolder = [self getPackageFolderPath:currentPackageHash];
        NSString *foundPath = [self findBundleInFolder:currentPackageFolder
                                            bundlePath:bundlePath
                                        bundleFileName:bundleFileName];
        if (foundPath) {
            RCTLogInfo(@"[ModuleLoader] Found bundle in current package: %@", foundPath);
            return foundPath;
        }
        RCTLogInfo(@"[ModuleLoader] Bundle not found in current package (%@), searching other packages...", currentPackageHash);
    }

    // 2️⃣ 按时间从新到旧遍历其他 package hash 目录
    NSArray<NSString *> *otherPackageFolders = [self getPackageFoldersSortedByTime:codePushDir
                                                                currentPackageHash:currentPackageHash];
    for (NSString *packageFolder in otherPackageFolders) {
        NSString *foundPath = [self findBundleInFolder:packageFolder
                                            bundlePath:bundlePath
                                        bundleFileName:bundleFileName];
        if (foundPath) {
            RCTLogInfo(@"[ModuleLoader] Found bundle in previous package (%@): %@", [packageFolder lastPathComponent], foundPath);
            return foundPath;
        }
    }

    RCTLogInfo(@"[ModuleLoader] Bundle not found in CodePush directories, will load from MainBundle: %@", bundlePath);
    return nil;
}

#pragma mark - Bridge Access

/**
 * 获取当前的 RCTBridge（类似 Android 的 ReactContext）
 */
- (RCTBridge *)getCurrentBridge {
    // 方法 1: 使用模块自带的 bridge（最可靠）
    if (self.bridge) {
        RCTLogInfo(@"[ModuleLoader] Using self.bridge: %@", NSStringFromClass([self.bridge class]));
        return self.bridge;
    }

    // 方法 2: 使用静态方法获取当前 bridge
    RCTBridge *currentBridge = [RCTBridge currentBridge];
    if (currentBridge) {
        RCTLogInfo(@"[ModuleLoader] Using [RCTBridge currentBridge]: %@", NSStringFromClass([currentBridge class]));
        return currentBridge;
    }

    // 方法 3: 从 AppDelegate 获取
    UIApplication *app = [UIApplication sharedApplication];
    id delegate = app.delegate;

    if ([delegate respondsToSelector:@selector(bridge)]) {
        RCTBridge *bridge = [delegate performSelector:@selector(bridge)];
        if (bridge) {
            RCTLogInfo(@"[ModuleLoader] Using AppDelegate.bridge: %@", NSStringFromClass([bridge class]));
            return bridge;
        }
    }

    // 方法 4: 通过 rootViewFactory
    if ([delegate respondsToSelector:@selector(rootViewFactory)]) {
        id factory = [delegate performSelector:@selector(rootViewFactory)];
        if (factory && [factory respondsToSelector:@selector(bridge)]) {
            RCTBridge *bridge = [factory performSelector:@selector(bridge)];
            if (bridge) {
                RCTLogInfo(@"[ModuleLoader] Using rootViewFactory.bridge: %@", NSStringFromClass([bridge class]));
                return bridge;
            }
        }
    }

    RCTLogWarn(@"[ModuleLoader] Could not get bridge from any source");
    return nil;
}

#pragma mark - Bundle Loading (JSI)

/**
 * 通过 JSI Runtime 加载 bundle
 * 这是 RN 新架构 (RCTBridgeProxy) 下加载子 bundle 的唯一方式
 */
- (BOOL)loadScriptViaJSI:(NSString *)filePath
               sourceURL:(NSURL *)sourceURL
                  bridge:(id)bridge
                   error:(NSError **)outError {

    RCTLogInfo(@"[ModuleLoader] Loading script via JSI Runtime");

    // 读取 bundle 数据
    NSError *readError = nil;
    NSData *bundleData = [NSData dataWithContentsOfFile:filePath options:0 error:&readError];
    if (readError || !bundleData) {
        if (outError) {
            *outError = readError ?: [NSError errorWithDomain:@"ModuleLoader"
                                                         code:1001
                                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to read bundle file"}];
        }
        return NO;
    }

    RCTLogInfo(@"[ModuleLoader] Bundle data loaded: %lu bytes", (unsigned long)bundleData.length);

    // 获取 JSI runtime
    void *runtimePtr = nil;

    // 方法 1: 使用 runtime 方法
    SEL runtimeSel = NSSelectorFromString(@"runtime");
    if ([bridge respondsToSelector:runtimeSel]) {
        NSMethodSignature *sig = [bridge methodSignatureForSelector:runtimeSel];
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
        [invocation setTarget:bridge];
        [invocation setSelector:runtimeSel];
        [invocation invoke];
        [invocation getReturnValue:&runtimePtr];
        RCTLogInfo(@"[ModuleLoader] Got runtime via runtime method: %p", runtimePtr);
    }

    // 方法 2: 直接访问 _runtime ivar
    if (!runtimePtr) {
        Ivar runtimeIvar = class_getInstanceVariable([bridge class], "_runtime");
        if (runtimeIvar) {
            runtimePtr = (__bridge void *)object_getIvar(bridge, runtimeIvar);
            RCTLogInfo(@"[ModuleLoader] Got runtime via _runtime ivar: %p", runtimePtr);
        }
    }

    if (!runtimePtr) {
        if (outError) {
            *outError = [NSError errorWithDomain:@"ModuleLoader"
                                            code:1003
                                        userInfo:@{NSLocalizedDescriptionKey: @"Could not get JSI runtime from bridge"}];
        }
        return NO;
    }

    // 转换为 jsi::Runtime
    jsi::Runtime *runtime = static_cast<jsi::Runtime *>(runtimePtr);

    // 转换 NSData 为字符串
    NSString *scriptString = [[NSString alloc] initWithData:bundleData encoding:NSUTF8StringEncoding];
    if (!scriptString) {
        if (outError) {
            *outError = [NSError errorWithDomain:@"ModuleLoader"
                                            code:1004
                                        userInfo:@{NSLocalizedDescriptionKey: @"Failed to convert bundle data to string"}];
        }
        return NO;
    }

    std::string script = std::string([scriptString UTF8String]);
    std::string sourceURLStr = std::string([[sourceURL absoluteString] UTF8String]);

    // 尝试获取 dispatchToJSThread 或使用 invokeAsync
    __block BOOL success = NO;
    __block NSError *evalError = nil;

    // 创建执行 block
    void (^executeBlock)(void) = ^{
        @try {
            auto buffer = std::make_shared<jsi::StringBuffer>(script);
            runtime->evaluateJavaScript(buffer, sourceURLStr);
            RCTLogInfo(@"[ModuleLoader] ✅ Bundle executed via JSI evaluateJavaScript");
            success = YES;
        } @catch (NSException *e) {
            RCTLogError(@"[ModuleLoader] JSI evaluateJavaScript failed: %@", e.reason);
            evalError = [NSError errorWithDomain:@"ModuleLoader"
                                            code:1005
                                        userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"JSI evaluation failed: %@", e.reason]}];
        }
    };

    // 方法 1: 使用 invokeAsync (RCTBridge 的标准方法)
    SEL invokeAsyncSel = NSSelectorFromString(@"invokeAsync:");
    if ([bridge respondsToSelector:invokeAsyncSel]) {
        RCTLogInfo(@"[ModuleLoader] Using invokeAsync: to dispatch to JS thread");

        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

        void (^wrappedBlock)(void) = ^{
            executeBlock();
            dispatch_semaphore_signal(semaphore);
        };

        #pragma clang diagnostic push
        #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [bridge performSelector:invokeAsyncSel withObject:wrappedBlock];
        #pragma clang diagnostic pop

        // 等待执行完成 (最多 10 秒)
        dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC));

        if (success) {
            return YES;
        }
    }

    // 方法 2: 直接执行 (如果已经在 JS 线程或可以同步执行)
    if (!success) {
        RCTLogInfo(@"[ModuleLoader] Executing directly on current thread");

        @try {
            auto buffer = std::make_shared<jsi::StringBuffer>(script);
            runtime->evaluateJavaScript(buffer, sourceURLStr);
            RCTLogInfo(@"[ModuleLoader] ✅ Bundle executed via direct JSI evaluateJavaScript");
            return YES;
        } @catch (NSException *e) {
            RCTLogError(@"[ModuleLoader] Direct JSI evaluateJavaScript failed: %@", e.reason);
            if (outError) {
                *outError = [NSError errorWithDomain:@"ModuleLoader"
                                                code:1005
                                            userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"JSI evaluation failed: %@", e.reason]}];
            }
            return NO;
        }
    }

    if (evalError && outError) {
        *outError = evalError;
    }
    return success;
}

#pragma mark - Main Load Method

/**
 * 加载子 bundle
 * 使用 JSI Runtime 直接执行 JavaScript 代码
 */
RCT_EXPORT_METHOD(loadBusinessBundle:(NSString *)bundleId
                  bundlePath:(NSString *)bundlePath
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    RCTLogInfo(@"[ModuleLoader] loadBusinessBundle: bundleId=%@, bundlePath=%@", bundleId, bundlePath);

    NSString *fullPath = [self getFullBundlePath:bundlePath];
    if (!fullPath) {
        resolve(@{@"success": @NO, @"errorMessage": @"BUNDLE_PATH_NOT_FOUND"});
        return;
    }

    dispatch_async(dispatch_get_main_queue(), ^{
        // 获取 bridge
        RCTBridge *bridge = [self getCurrentBridge];
        if (!bridge) {
            RCTLogError(@"[ModuleLoader] Bridge not available");
            resolve(@{@"success": @NO, @"errorMessage": @"BRIDGE_NOT_AVAILABLE"});
            return;
        }

        RCTLogInfo(@"[ModuleLoader] Bridge class: %@", NSStringFromClass([bridge class]));

        // 使用 JSI Runtime 加载脚本
        NSURL *sourceURL = [NSURL fileURLWithPath:fullPath];
        NSError *loadError = nil;

        BOOL success = [self loadScriptViaJSI:fullPath sourceURL:sourceURL bridge:bridge error:&loadError];

        if (success) {
            RCTLogInfo(@"[ModuleLoader] ✅ Bundle loaded successfully: %@", bundleId);
            resolve(@{@"success": @YES});
        } else {
            RCTLogError(@"[ModuleLoader] ❌ Failed to load bundle: %@", loadError.localizedDescription);
            resolve(@{@"success": @NO, @"errorMessage": loadError.localizedDescription ?: @"LOAD_FAILED"});
        }
    });
}

#pragma mark - Bundle Manifest Methods

- (NSString *)readFileContent:(NSString *)filePath {
    @try {
        NSError *error;
        NSString *content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
        if (error) {
            RCTLogWarn(@"[ModuleLoader] Failed to read file: %@ - %@", filePath, error.localizedDescription);
            return nil;
        }
        return content;
    } @catch (NSException *exception) {
        RCTLogWarn(@"[ModuleLoader] Failed to read file: %@ - %@", filePath, exception.reason);
        return nil;
    }
}

RCT_EXPORT_METHOD(getCurrentBundleManifest:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    @try {
        NSFileManager *fileManager = [NSFileManager defaultManager];

        // 1️⃣ 优先从 CodePush 当前包目录获取
        NSString *packageHash = [self getCurrentPackageHash];
        if (packageHash) {
            NSString *packageFolder = [self getPackageFolderPath:packageHash];
            NSString *codePushManifestPath = [packageFolder stringByAppendingPathComponent:BundleManifestFileName];
            if ([fileManager fileExistsAtPath:codePushManifestPath]) {
                RCTLogInfo(@"[ModuleLoader] Found manifest in CodePush package: %@", codePushManifestPath);
                resolve(codePushManifestPath);
                return;
            }
        }

        // 2️⃣ MainBundle/Bundles 目录（内置）
        NSString *bundlesPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Bundles"];
        NSString *bundlesManifestPath = [bundlesPath stringByAppendingPathComponent:BundleManifestFileName];
        if ([fileManager fileExistsAtPath:bundlesManifestPath]) {
            RCTLogInfo(@"[ModuleLoader] Found manifest at Bundles: %@", bundlesManifestPath);
            resolve(bundlesManifestPath);
            return;
        }

        // 3️⃣ MainBundle 根目录
        NSString *mainBundleManifestPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:BundleManifestFileName];
        if ([fileManager fileExistsAtPath:mainBundleManifestPath]) {
            resolve(mainBundleManifestPath);
            return;
        }

        RCTLogWarn(@"[ModuleLoader] Bundle manifest not found");
        resolve(nil);
    } @catch (NSException *exception) {
        RCTLogError(@"[ModuleLoader] Failed to get manifest: %@", exception.reason);
        reject(@"MANIFEST_ERROR", @"Failed to get manifest path", nil);
    }
}

RCT_EXPORT_METHOD(getCurrentBundleManifestContent:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        @try {
            NSFileManager *fileManager = [NSFileManager defaultManager];
            NSString *manifestContent = nil;

            // 1️⃣ 优先从 CodePush 当前包目录读取
            NSString *packageHash = [self getCurrentPackageHash];
            if (packageHash) {
                NSString *packageFolder = [self getPackageFolderPath:packageHash];
                NSString *codePushManifestPath = [packageFolder stringByAppendingPathComponent:BundleManifestFileName];
                if ([fileManager fileExistsAtPath:codePushManifestPath]) {
                    manifestContent = [self readFileContent:codePushManifestPath];
                    if (manifestContent) {
                        RCTLogInfo(@"[ModuleLoader] ✓ Read manifest from CodePush package");
                        dispatch_async(dispatch_get_main_queue(), ^{ resolve(manifestContent); });
                        return;
                    }
                }
            }

            // 2️⃣ MainBundle/Bundles 目录（内置）
            NSString *bundlesPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Bundles"];
            NSString *bundlesManifestPath = [bundlesPath stringByAppendingPathComponent:BundleManifestFileName];
            if ([fileManager fileExistsAtPath:bundlesManifestPath]) {
                manifestContent = [self readFileContent:bundlesManifestPath];
                if (manifestContent) {
                    RCTLogInfo(@"[ModuleLoader] ✓ Read manifest from Bundles");
                    dispatch_async(dispatch_get_main_queue(), ^{ resolve(manifestContent); });
                    return;
                }
            }

            // 3️⃣ MainBundle 根目录
            NSString *mainBundleManifestPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:BundleManifestFileName];
            if ([fileManager fileExistsAtPath:mainBundleManifestPath]) {
                manifestContent = [self readFileContent:mainBundleManifestPath];
                if (manifestContent) {
                    RCTLogInfo(@"[ModuleLoader] ✓ Read manifest from MainBundle");
                    dispatch_async(dispatch_get_main_queue(), ^{ resolve(manifestContent); });
                    return;
                }
            }

            RCTLogWarn(@"[ModuleLoader] Bundle manifest content not found");
            dispatch_async(dispatch_get_main_queue(), ^{ resolve(nil); });
        } @catch (NSException *exception) {
            RCTLogError(@"[ModuleLoader] Failed to get manifest content: %@", exception.reason);
            dispatch_async(dispatch_get_main_queue(), ^{
                reject(@"MANIFEST_CONTENT_ERROR", @"Failed to read manifest content", nil);
            });
        }
    });
}

@end
