//
//  RCTRnUpdate.m
//
//  Created by edy on 2026/1/4.
//

#import "RCTRnUpdate.h"
#import "RCTRnUpdateResultParams.h"
#import "react/RCTConvert.h"
#import "RCTRnUpdateFileManager.h"
#import "RCTRnUpdateDownload.h"
#if __has_include("RCTReloadCommand.h")
#import "RCTReloadCommand.h"
#endif


// 信息存储key
static NSString *const keyRNUpdateInfo = @"REACTNATIVECN_RN_UPDATE_INFO_KEY";
// 版本号的key
static NSString *const paramCurrentVersion = @"currentVersion";
// 上次的版本key
static NSString *const paramLastVersion = @"lastVersion";
// PPK包名
static NSString *const PPKZipName = @"ppk-update.zip";
// bundle包名
static NSString *const BundleName = @"index.bundlejs";


@implementation RCTRnUpdate {

  RCTRnUpdateFileManager *_fileManager;

}

RCT_EXPORT_MODULE(RCTRnUpdate);


#pragma mark - imp

- (instancetype)init
{
  self = [super init];
  if(self) {
    _fileManager = [[RCTRnUpdateFileManager alloc] init];
  }
  return self;
}


RCT_EXPORT_METHOD(getConstantsInfo:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{

  NSMutableDictionary *ret = [NSMutableDictionary new];
  NSString *currentVersion = [RCTRnUpdate getCurrentVersion];

  ret[paramCurrentVersion] = currentVersion == nil ? @"" : currentVersion;

  resolve([ret copy]);
}

RCT_EXPORT_METHOD(downloadPPK:(NSDictionary *)options
                 resolve:(RCTPromiseResolveBlock)resolve
                 rejecter:(RCTPromiseRejectBlock)reject)
{
  NSString *url = [RCTConvert NSString:options[@"url"]];
  NSString *newVersion = [RCTConvert NSString:options[@"newVersion"]];

  if(url == nil || newVersion == nil) {
    resolve([RCTRnUpdateResultParams.errorParams toDictionaryWithMsg:@"参数不能为空"]);
    return;
  }

  // 文件夹路径
  NSString *dir = [RCTRnUpdate downloadVersionDir:newVersion];
  // 创建文件夹
  BOOL createDirOK = [_fileManager createDir:dir];
  if(!createDirOK) {
    resolve([RCTRnUpdateResultParams.errorRuntime toDictionaryWithMsg:@"创建文件夹失败"]);
    return;
  }

  NSString *zipFilePath = [RCTRnUpdate getPPKZipFullPath:newVersion]; // /Library/Application Support/rctrnupdate/201/ppk-update.zip
  if(zipFilePath == nil) {
    resolve([RCTRnUpdateResultParams.errorRuntime toDictionaryWithMsg:@"获取zip保存路径失败"]);
    return;
  }

  RCTLogInfo(@"[RCTRnUpdate LOG] RCTRnUpdate -- downloadPPK 下载路径: %@ ", url);
  RCTLogInfo(@"[RCTRnUpdate LOG] RCTRnUpdate -- downloadPPK zipFilePath: %@ ", zipFilePath);

  [RCTRnUpdateDownload downloadFile:url savePath:zipFilePath progressHandler:^(long currentSize, long totalSize, double progress) {
    RCTLogInfo(@"[RCTRnUpdate LOG] RCTRnUpdate -- downloadPPK progressHandler: currentSize: %ld, totalSize: %ld,  progress: %.2f%%", currentSize, totalSize, progress);
  } completionHandler:^(NSString *statusCode, NSString *msg) {
    RCTLogInfo(@"[RCTRnUpdate LOG] RCTRnUpdate -- downloadPPK completionHandler: statusCode: %@, msg: %@", statusCode, msg);

    bool downloadOk = [statusCode isEqualToString:@(RCTRnUpdateResultParams.success.code).stringValue];

    // 下载出错
    if(!downloadOk) {
      resolve([RCTRnUpdateResultParams builder:statusCode msg:msg]);
      return;
    }
    // 下载成功，需要进行解压到指定文件
    RCTLogInfo(@"[RCTRnUpdate LOG] RCTRnUpdate -- before unzip file: %@ ", zipFilePath);
    // 解压目录，就是 版本号下面
    NSString* unzipPath = [RCTRnUpdate downloadVersionDir:newVersion];

    bool exis = [self-> _fileManager checkZipFileExists:zipFilePath];

    if(!exis) {
      resolve([RCTRnUpdateResultParams.errorRuntime toDictionaryWithMsg:[NSString stringWithFormat:@"压缩包文件不存在：%@", zipFilePath]]);
      return;
    }

    [self-> _fileManager unzipFile:zipFilePath toDestination:unzipPath progressHandler:^(NSString *entry, long entryNumber, long total, double progress) {

      RCTLogInfo(@"[RCTRnUpdate LOG] RCTRnUpdate -- downloadPPK unzipFile progressHandler: entry: %@, entryNumber: %ld,  total: %ld, progress: %.2f", entry, entryNumber, total, progress);

    } completionHandler:^(NSString *path, BOOL succeeded, NSError *error) {
      if(succeeded) {

        NSError *error = nil;
        NSArray *list = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:unzipPath error:&error];
        if (!error) {
          RCTLogInfo(@"解压之后获得的文件列表：%@", [list componentsJoinedByString:@","]);
        }

        // 检测压缩包是否还在
        bool exis = [self-> _fileManager checkZipFileExists:zipFilePath];
        if(!exis) {
          RCTLogInfo(@"[RCTRnUpdate LOG] RCTRnUpdate -- downloadPPK unzipFile completionHandler: 解压完成✅ 压缩包文件已删除：%@", zipFilePath);
        }

        resolve([RCTRnUpdateResultParams.success toDictionary]);
      } else {
        RCTLogInfo(@"[RCTRnUpdate LOG] RCTRnUpdate -- downloadPPK unzipFile completionHandler: path: %@, 错误: %@", path, error.localizedDescription);

        resolve([RCTRnUpdateResultParams.errorRuntime toDictionaryWithMsg:[NSString stringWithFormat:@"解压失败，错误：%@", error.localizedDescription]]);
      }
    }];
  }];


//  NSMutableDictionary *ret = [NSMutableDictionary new];
//
//  ret[@"url"] = url;
//  ret[@"newVersion"] = newVersion;

//  resolve([ret copy]);

}

// 切换版本
RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options
                  resolve:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
  NSString *newVersion = [RCTConvert NSString:options[@"newVersion"]];

  if(newVersion == nil || [self isBlankString:newVersion]) {
    resolve([RCTRnUpdateResultParams.errorParams toDictionaryWithMsg:@"版本号不能为空"]);
    return;
  }

  if(![RCTRnUpdate verifiedVersionAvailable:newVersion]) {
    resolve([RCTRnUpdateResultParams.ppkVersionUndownload toDictionaryWithMsg:[NSString stringWithFormat:@"版本：{%@}，未下载", newVersion]]);
    return;
  }

  NSString* currentVersion = [RCTRnUpdate getCurrentVersion];
  if(currentVersion != nil && ![self isBlankString:currentVersion] && [currentVersion isEqualToString:newVersion]) {
    resolve([RCTRnUpdateResultParams.ppkVersionInstall toDictionaryWithMsg:[NSString stringWithFormat:@"该版本已经安装，当前安装版本：{%@}，需切换版本：{%@}", currentVersion, newVersion]]);
    return;
  }

  if(![RCTRnUpdate switchVersion:newVersion]) {
    resolve([RCTRnUpdateResultParams.errorRuntime toDictionaryWithMsg:[NSString stringWithFormat:@"版本：{%@}，切换失败", newVersion]]);
    return;
  }

//  resolve([RCTRnUpdateResultParams.success toDictionaryWithMsg:[NSString stringWithFormat:@"新版本：{%@}, 已准备，可重启App切换", newVersion]]);

  @try {
      dispatch_async(dispatch_get_main_queue(), ^{
          #if __has_include("RCTReloadCommand.h")
              // reload 0.62+
              RCTReloadCommandSetBundleURL([[self class] bundleURL]);
              RCTTriggerReloadCommandListeners(@"pushy restartApp");
          #else
              // 对于较老版本的RN，使用NSNotificationCenter触发重载
              // 这会强制使用AppDelegate中定义的最新bundle URL
               [self.bridge reload];
//              [[NSNotificationCenter defaultCenter] postNotificationName:@"RCTReloadNotification" object:nil];
          #endif
      });
    resolve([RCTRnUpdateResultParams.success toDictionary]);
  }
  @catch (NSException *exception) {
    resolve([RCTRnUpdateResultParams.errorRuntime toDictionaryWithMsg:[NSString stringWithFormat:@"执行报错：%@", exception.reason]]);
  }
}

// 检测版本状态
RCT_EXPORT_METHOD(checkVersionExists:(NSDictionary *)options
                  resolve:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
  NSString *newVersion = [RCTConvert NSString:options[@"versionCode"]];

  if(newVersion == nil || [self isBlankString:newVersion]) {
    resolve([RCTRnUpdateResultParams.errorParams toDictionaryWithMsg:@"版本号不能为空"]);
    return;
  }

  if(![RCTRnUpdate verifiedVersionAvailable:newVersion]) {
    resolve([RCTRnUpdateResultParams.ppkVersionUndownload toDictionaryWithMsg:[NSString stringWithFormat:@"版本：{%@}，未下载", newVersion]]);
    return;
  }

  NSString* currentVersion = [RCTRnUpdate getCurrentVersion];
  if(![self isBlankString:currentVersion] && [currentVersion isEqualToString:newVersion]) {
    resolve([RCTRnUpdateResultParams.ppkVersionInstall toDictionaryWithMsg:[NSString stringWithFormat:@"该版本已经安装，当前安装版本：{%@}，需切换版本：{%@}", currentVersion, newVersion]]);
    return;
  }

  resolve([RCTRnUpdateResultParams.ppkVersionUninstall toDictionary]);
}

#pragma mark - private

- (BOOL) isBlankString:(NSString *)string {
    if (string == nil || string == NULL) {
        return YES;
    }
    if ([string isKindOfClass:[NSNull class]]) {
        return YES;
    }
    if ([[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length]==0) {
        return YES;
    }
    return NO;
}


+ (NSString *)downloadDir
{
    NSString *directory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) firstObject];
    NSString *downloadDir = [directory stringByAppendingPathComponent:@"rctrnupdate"];

    return downloadDir;// ....省略/Library/Application Support/rctrnupdate
}

+ (NSString *)downloadVersionDir:(NSString*) versionCode
{
  NSString *versionDir = [[RCTRnUpdate downloadDir] stringByAppendingPathComponent:versionCode];
  return versionDir;// ....省略/Library/Application Support/rctrnupdate/201
}

+ (NSString *)getPPKZipFullPath:(NSString *) versionCode
{
  NSString *dir = [RCTRnUpdate downloadVersionDir:versionCode];
  NSString *zipFilePath = [dir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@", PPKZipName]];
  return zipFilePath; // ....省略/Library/Application Support/rctrnupdate/201/ppk-update.zip
}

+ (NSString *)getBundleFullPath:(NSString *) versionCode
{
  NSString *dir = [RCTRnUpdate downloadVersionDir:versionCode];
  NSString *zipFilePath = [dir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@", BundleName]];
  return zipFilePath; // ....省略/Library/Application Support/rctrnupdate/201/index.bundlejs
}

// 当前版本号
+ (NSString *)getCurrentVersion
{
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  NSDictionary *updateInfo = [defaults dictionaryForKey:keyRNUpdateInfo];
  NSString *vs = [updateInfo objectForKey:paramCurrentVersion];

  return vs;
}

// 上次版本号
+ (NSString *)getLastVersion
{
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  NSDictionary *updateInfo = [defaults dictionaryForKey:keyRNUpdateInfo];
  NSString *vs = [updateInfo objectForKey:paramLastVersion];

  return vs;
}

// 版本是否可用
+(BOOL)verifiedVersionAvailable:(NSString*) version
{
  NSString* bundlePath = [self getBundleFullPath:version];
  bool exis = [RCTRnUpdateFileManager checkFileExists:bundlePath];
  return exis;
}

+(NSString *) rollBack
{
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

  NSString* vs = [self getLastVersion];
  if(vs != nil) {
    [defaults setObject:@{paramCurrentVersion: vs} forKey:keyRNUpdateInfo];
  } else {
    [defaults setObject:nil forKey:keyRNUpdateInfo];
  }

  return vs;
}

+(BOOL)switchVersion:(NSString*) version
{
  if(![RCTRnUpdate verifiedVersionAvailable:version]) {
    return NO;
  }
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  NSString* lastVs = [self getCurrentVersion];
  if(lastVs == nil) {
    [defaults setObject:@{paramCurrentVersion: version} forKey:keyRNUpdateInfo];
  } else {
    [defaults setObject:@{paramCurrentVersion: version, paramLastVersion: lastVs} forKey:keyRNUpdateInfo];
  }
  return YES;
}

#pragma mark - public

// 获取当前可用的 bundle路径
+(NSURL *) bundleURL
{
  NSString* currentVersion = [RCTRnUpdate getCurrentVersion];

  NSString *loadVersion = currentVersion;
  while (loadVersion.length) {
    if([self verifiedVersionAvailable:loadVersion]) {
        NSString* bundlePath = [self getBundleFullPath:loadVersion];
        NSURL *bundleURL = [NSURL fileURLWithPath:bundlePath];
        return bundleURL;
      }
    loadVersion = [self rollBack];
  }

  return [RCTRnUpdate binaryBundleURL];
}


// 默认的bundle路径
+ (NSURL *)binaryBundleURL
{
#if DEBUG

  NSString *serverHost = @"localhost";
  return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@:8082/index.bundle?platform=ios&dev=true&minify=false", serverHost]];
#else
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
    return url;
  #endif
}


@end
