#import <Foundation/Foundation.h>
#import <jsi/jsi.h>
#import <React/RCTBridgeModule.h>

using namespace facebook;

namespace pluggerUtils {
namespace jsi = facebook::jsi;
/**
 Source: https://github.com/mrousavy/react-native-mmkv/blob/master/ios/JSIUtils.mm
 Util file to convert native objects to js objects or vice versa. renaming it with our app's prefix name and using under d11 namespace, because this can give duplicate symbol errors if any another turbo module library will use same util.
 */
/**
 * All static helper functions are ObjC++ specific.
 */
jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime &runtime, NSNumber *value);
jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *value);
jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value);
jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value);;
jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value);
jsi::Array convertNSArrayToJSIArray(jsi::Runtime &runtime, NSArray *value);
std::vector<jsi::Value> convertNSArrayToStdVector(jsi::Runtime &runtime, NSArray *value);
jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value);
id convertJSIValueToObjCObject(
															 jsi::Runtime &runtime,
															 const jsi::Value &value);
NSString* convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &value);
NSArray* convertJSIArrayToNSArray(
																	jsi::Runtime &runtime,
																	const jsi::Array &value);
NSDictionary *convertJSIObjectToNSDictionary(
																						 jsi::Runtime &runtime,
																						 const jsi::Object &value);
RCTResponseSenderBlock convertJSIFunctionToCallback(
																										jsi::Runtime &runtime,
																										const jsi::Function &value);
id convertJSIValueToObjCObject(
															 jsi::Runtime &runtime,
															 const jsi::Value &value);
RCTResponseSenderBlock convertJSIFunctionToCallback(
																										jsi::Runtime &runtime,
																										const jsi::Function &value);

struct Promise {
	Promise(jsi::Runtime &rt, jsi::Function resolve, jsi::Function reject);
	void resolve(const jsi::Value &result);
	void reject(const std::string &error);
	jsi::Runtime &runtime_;
	jsi::Function resolve_;
	jsi::Function reject_;
};

using PromiseSetupFunctionType =
std::function<void(jsi::Runtime &rt, std::shared_ptr<Promise>)>;
jsi::Value createPromiseAsJSIValue(
																	 jsi::Runtime &rt,
																	 const PromiseSetupFunctionType func);

inline void registerCxxFunction(
    jsi::Runtime &runtime, jsi::Object &object, const char *name, unsigned int argc, jsi::HostFunctionType function)
{
    auto jsiFunction =
        jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forAscii(runtime, name), argc, function);
    object.setProperty(runtime, name, std::move(jsiFunction));
}

}
