/*******************************************************
 * Copyright (C) 2018 XMind Ltd. - All Rights Reserved
 *******************************************************/

#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>
#import <napi.h>
#import "./handoff.h"

// 辅助函数：将 N-API 字符串转换为 NSString
NSString* ToNSString(const std::string& value) {
  return [[NSString alloc] initWithUTF8String:value.c_str()];
}

// 缓存用户活动的字典
static NSMutableDictionary* _documentCache = nil;
static NSMutableDictionary* getDocumentCache() {
  if (_documentCache == nil) {
    _documentCache = [[NSMutableDictionary alloc] init];
  }
  return _documentCache;
}

// N-API 实现：激活文件以便 Handoff 使用
Napi::Value HoActivateFile(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();

  // 参数验证
  if (info.Length() < 2 || !info[0].IsString() || !info[1].IsString()) {
    Napi::TypeError::New(env, "Invalid arguments").ThrowAsJavaScriptException();
    return env.Undefined();
  }

  try {
    @autoreleasepool {
      std::string pathStr = info[0].As<Napi::String>().Utf8Value();
      std::string typeStr = info[1].As<Napi::String>().Utf8Value();

      NSString* path = ToNSString(pathStr);
      NSString* type = ToNSString(typeStr);

      NSMutableDictionary* cache = getDocumentCache();
      NSUserActivity* doc = [cache valueForKey:path];

      if (doc == nil) {
        NSUserActivity* activity = [[NSUserActivity alloc] initWithActivityType:type];
        activity.userInfo = @{@"NSUserActivityDocumentURL": [NSURL fileURLWithPath:path]};
        [cache setObject:activity forKey:path];
        [activity becomeCurrent];
      } else {
        [doc becomeCurrent];
      }

      return env.Undefined();
    }
  } catch (const std::exception& e) {
    Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
    return env.Undefined();
  }
}

// N-API 实现：停用文件的 Handoff
Napi::Value HoDeactivateFile(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();

  // 参数验证
  if (info.Length() < 1 || !info[0].IsString()) {
    Napi::TypeError::New(env, "Invalid arguments").ThrowAsJavaScriptException();
    return env.Undefined();
  }

  try {
    @autoreleasepool {
      std::string pathStr = info[0].As<Napi::String>().Utf8Value();
      NSString* path = ToNSString(pathStr);

      NSMutableDictionary* cache = getDocumentCache();
      [[cache valueForKey:path] invalidate];
      [cache removeObjectForKey:path];

      return env.Undefined();
    }
  } catch (const std::exception& e) {
    Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
    return env.Undefined();
  }
}

// N-API 实现：确保 iCloud 容器存在
Napi::Value HoEnsureUbiquityContainer(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();

  // 参数验证
  if (info.Length() < 1 || !info[0].IsString()) {
    Napi::TypeError::New(env, "Invalid arguments").ThrowAsJavaScriptException();
    return env.Undefined();
  }

  try {
    @autoreleasepool {
      std::string identifierStr = info[0].As<Napi::String>().Utf8Value();
      NSString* identifier = ToNSString(identifierStr);

      NSURL* url = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:identifier];
      if (url == nil) {
        return Napi::Boolean::New(env, false);
      }

      NSError* error = nil;
      BOOL success = [[NSFileManager defaultManager] createDirectoryAtURL:url
                                          withIntermediateDirectories:YES
                                                           attributes:nil
                                                                error:&error];

      if (!success && error != nil) {
        Napi::Error::New(env, error.localizedDescription.UTF8String).ThrowAsJavaScriptException();
        return env.Undefined();
      }

      return Napi::Boolean::New(env, true);
    }
  } catch (const std::exception& e) {
    Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
    return env.Undefined();
  }
}

// N-API 实现：下载 iCloud 文件
Napi::Value HoDownloadICloudFile(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();

  // 参数验证
  if (info.Length() < 1 || !info[0].IsString()) {
    Napi::TypeError::New(env, "Invalid arguments").ThrowAsJavaScriptException();
    return env.Undefined();
  }

  try {
    @autoreleasepool {
      std::string pathStr = info[0].As<Napi::String>().Utf8Value();
      NSString* path = ToNSString(pathStr);
      NSURL* url = [NSURL fileURLWithPath:path];

      NSNumber* isInICloud = nil;
      NSError* error = nil;

      if (![url getResourceValue:&isInICloud forKey:NSURLIsUbiquitousItemKey error:&error]) {
        if (error != nil) {
          Napi::Error::New(env, error.localizedDescription.UTF8String).ThrowAsJavaScriptException();
        }
        return env.Undefined();
      }

      if (![isInICloud boolValue]) {
        return Napi::Boolean::New(env, false);
      }

      NSString* downloadStatus = nil;
      error = nil;
      if ([url getResourceValue:&downloadStatus forKey:NSURLUbiquitousItemDownloadingStatusKey error:&error]) {
        if ([downloadStatus isEqualToString:NSURLUbiquitousItemDownloadingStatusDownloaded]) {
          return Napi::Boolean::New(env, false);
        }
      }

      if (error != nil) {
        Napi::Error::New(env, error.localizedDescription.UTF8String).ThrowAsJavaScriptException();
        return env.Undefined();
      }

      error = nil;
      if (![[NSFileManager defaultManager] startDownloadingUbiquitousItemAtURL:url error:&error]) {
        if (error != nil) {
          Napi::Error::New(env, error.localizedDescription.UTF8String).ThrowAsJavaScriptException();
        }
        return env.Undefined();
      }

      return Napi::Boolean::New(env, true);
    }
  } catch (const std::exception& e) {
    Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
    return env.Undefined();
  }
}

// N-API 实现：获取 iCloud 项目下载状态
Napi::Value HoGetUbiquitousItemDownloadingStatus(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();

  // 参数验证
  if (info.Length() < 1 || !info[0].IsString()) {
    Napi::TypeError::New(env, "Invalid arguments").ThrowAsJavaScriptException();
    return env.Undefined();
  }

  try {
    @autoreleasepool {
      std::string pathStr = info[0].As<Napi::String>().Utf8Value();
      NSString* path = ToNSString(pathStr);
      NSURL* url = [NSURL fileURLWithPath:path];

      NSError* error = nil;
      NSString* downloadStatus = nil;

      if ([url getResourceValue:&downloadStatus forKey:NSURLUbiquitousItemDownloadingStatusKey error:&error]) {
        return Napi::String::New(env, downloadStatus.UTF8String);
      }

      if (error != nil) {
        Napi::Error::New(env, error.localizedDescription.UTF8String).ThrowAsJavaScriptException();
      }

      return env.Undefined();
    }
  } catch (const std::exception& e) {
    Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
    return env.Undefined();
  }
}