#import "FreshdeskNativeModule.h"
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

// The Swift→ObjC generated header location depends on the consumer's linkage.
// With `use_frameworks!` (dynamic) the pod builds as a framework and the header
// lives inside it (<Module/Module-Swift.h>). With static linkage it is exposed
// as a top-level/quoted header. Try each form so both setups build.
#if __has_include(<FreshdeskReactNative/FreshdeskReactNative-Swift.h>)
#import <FreshdeskReactNative/FreshdeskReactNative-Swift.h>
#elif __has_include(<FreshdeskReactNative-Swift.h>)
#import <FreshdeskReactNative-Swift.h>
#else
#import "FreshdeskReactNative-Swift.h"
#endif

// New Architecture only: conform to the @react-native/codegen-generated
// TurboModule spec. The generated protocol/JSI class names come from
// codegenConfig.name = "RNFreshdeskSpec" (see docs/superpowers/plans/codegen-symbols.md).
// The generated module self-includes the quoted "RNFreshdeskSpec.h"; consumers
// import the angled <RNFreshdeskSpec/RNFreshdeskSpec.h> form.
#ifdef RCT_NEW_ARCH_ENABLED
#if __has_include(<RNFreshdeskSpec/RNFreshdeskSpec.h>)
#import <RNFreshdeskSpec/RNFreshdeskSpec.h>
#elif __has_include("RNFreshdeskSpec.h")
#import "RNFreshdeskSpec.h"
#endif

@interface FreshdeskNativeModule () <NativeFreshdeskSpec>
@end
#endif

@implementation FreshdeskNativeModule

RCT_EXPORT_MODULE(FreshdeskReactNative)

- (instancetype)init
{
  if (self = [super init]) {
    // Register this RCTEventEmitter instance with the Swift bridge so native
    // notifications (unreadCountChanged, userStateChanged, userCreated,
    // onLinkPressed) can be forwarded to JS. Without this the Swift side holds
    // a nil emitter and every sendEvent is silently dropped.
    [FreshdeskNativeModuleBridge setEventEmitter:self];
  }
  return self;
}

+ (BOOL)requiresMainQueueSetup
{
  return YES;
}

- (NSArray<NSString *> *)supportedEvents
{
  return @[
    @"unreadCountChanged",
    @"userStateChanged",
    @"userCreated",
    @"onLinkPressed"
  ];
}

#pragma mark - SDK Methods

// The Swift bridge types the dictionary params as non-optional [String: Any].
// A nil NSDictionary from JS (e.g. an `undefined` arg on the legacy bridge)
// would trap when force-bridged, so coalesce to an empty dictionary here.
RCT_EXPORT_METHOD(initialize:(NSDictionary *)config
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge initializeWithConfig:(config ?: @{}) resolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(openSupport:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge openSupportWithResolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(openKnowledgeBase:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge openKnowledgeBaseWithResolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(openTopic:(NSString *)topicName
                  topicId:(NSString *)topicId
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge openTopicWithTopicName:topicName topicId:topicId resolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(getUnreadCount:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge getUnreadCountWithResolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(trackEvent:(NSString *)name
                  properties:(NSDictionary *)properties
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge trackEventWithName:name properties:(properties ?: @{}) resolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(setUserProperties:(NSDictionary *)properties
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge setUserPropertiesWithProperties:(properties ?: @{}) resolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(setTicketProperties:(NSDictionary *)properties
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge setTicketPropertiesWithProperties:(properties ?: @{}) resolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(authenticateAndUpdate:(NSString *)jwt
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge authenticateAndUpdateWithJwt:jwt resolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(resetUser:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge resetUserWithResolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(dismiss:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge dismissWithResolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(setLinkHandlerEnabled:(BOOL)enabled
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge setLinkHandlerEnabledWithEnabled:enabled resolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(getSDKVersion:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge getSDKVersionWithResolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(getUser:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge getUserWithResolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(setContentConfiguration:(NSString *)configJson
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge setContentConfigurationWithConfigJson:configJson resolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(enableDebugLogs:(BOOL)enabled
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge enableDebugLogsWithEnabled:enabled resolver:resolve rejecter:reject];
}

RCT_EXPORT_METHOD(runDiagnostics:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
  [FreshdeskNativeModuleBridge runDiagnosticsWithResolver:resolve rejecter:reject];
}

#pragma mark - Event Emitters

- (void)sendEventWithName:(NSString *)eventName body:(id)body
{
  [super sendEventWithName:eventName body:body];
}

// Don't compile this code when we build for the old architecture.
#ifdef RCT_NEW_ARCH_ENABLED
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
    (const facebook::react::ObjCTurboModule::InitParams &)params
{
  return std::make_shared<facebook::react::NativeFreshdeskSpecJSI>(params);
}
#endif

@end
