#import <React/RCTBridge+Private.h>
#import <ReactCommon/CallInvoker.h>
#import "DittoRNSDK.h"
#import "main.h"

#ifdef RCT_NEW_ARCH_ENABLED
#import "DittoRNSDKSpec.h"
#endif

using namespace facebook::jsi;

@interface RCTBridge (BridgeWithCallInvoker)
- (std::shared_ptr<facebook::react::CallInvoker>)jsCallInvoker;
@end

@implementation DittoRNSDK

using namespace facebook::jsi;

RCT_EXPORT_MODULE()

+ (BOOL)requiresMainQueueSetup
{
  return YES;
}

#ifdef RCT_NEW_ARCH_ENABLED
// Turbo Module setup for New Architecture
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
    (const facebook::react::ObjCTurboModule::InitParams &)params
{
  return std::make_shared<facebook::react::NativeDittoRNSDKSpecJSI>(params);
}

// Export constants for New Architecture - both methods required by protocol
- (facebook::react::ModuleConstants<JS::NativeDittoRNSDK::Constants::Builder>)constantsToExport
{
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
  NSString *defaultDirectory = [paths firstObject];

  return facebook::react::typedConstants<JS::NativeDittoRNSDK::Constants::Builder>({
    .DEFAULT_DIRECTORY = RCTRequired<NSString *>(defaultDirectory)
  });
}

- (facebook::react::ModuleConstants<JS::NativeDittoRNSDK::Constants::Builder>)getConstants
{
  return [self constantsToExport];
}
#endif

// This method works for both old and new architecture
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install)
{
  RCTBridge* bridge = [RCTBridge currentBridge];
  RCTCxxBridge* cxxBridge = (RCTCxxBridge*)bridge;
  Runtime &jsiRuntime = *((Runtime *) cxxBridge.runtime);

  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
  NSString *defaultDirectory = [paths firstObject];
  Object parameters(jsiRuntime);
  parameters.setProperty(jsiRuntime, "defaultDirectory", String::createFromUtf8(jsiRuntime, [defaultDirectory UTF8String]));

  auto callInvoker = cxxBridge.jsCallInvoker;

  // Install all JSI bindings - same code as before!
  sharedjsi::install(jsiRuntime, callInvoker, parameters);
  install(jsiRuntime);

  return @true;
}

// iOS-specific JSI functions - no changes!
static void install(Runtime &jsiRuntime) {
  auto defaultDeviceName = Function::createFromHostFunction(jsiRuntime,
                                                            PropNameID::forAscii(jsiRuntime,
                                                                                 "defaultDeviceName"),
                                                            0,
                                                            [](Runtime &runtime,
                                                               const Value &thisValue,
                                                               const Value *arguments,
                                                               size_t count) -> Value {

#if TARGET_OS_OSX
    NSString *deviceName = [[NSHost currentHost] localizedName];
#else
    NSString *deviceName = [[UIDevice currentDevice] name];
#endif
    return String::createFromUtf8(runtime, [deviceName UTF8String]);
  });

  jsiRuntime.global().setProperty(jsiRuntime, "defaultDeviceName", std::move(defaultDeviceName));
}

@end
