#pragma once
#include <v8.h>
#include <uv.h>

#include <memory>

#include "transferable.h"
#include "context_handle.h"
#include "transferable_handle.h"

namespace catbox {

class NativeModuleHandle : public TransferableHandle {
	public:
		class NativeModule {
			private:
				using init_t = void(*)(v8::Isolate *, v8::Local<v8::Context>, v8::Local<v8::Object>);
				uv_lib_t lib {};
				init_t init;

			public:
				explicit NativeModule(const std::string& filename);
				NativeModule(const NativeModule&) = delete;
				NativeModule& operator= (const NativeModule&) = delete;
				~NativeModule();
				void InitForContext(v8::Isolate* isolate, v8::Local<v8::Context> context, v8::Local<v8::Object> target);
		};

	private:
		class NativeModuleTransferable : public Transferable {
			private:
				std::shared_ptr<NativeModule> module;
			public:
				explicit NativeModuleTransferable(std::shared_ptr<NativeModule> module);
				v8::Local<v8::Value> TransferIn() final;
		};

		std::shared_ptr<NativeModule> module;

		template <int async>
		v8::Local<v8::Value> Create(ContextHandle* context_handle);

	public:
		explicit NativeModuleHandle(std::shared_ptr<NativeModule> module);
		static v8::Local<v8::FunctionTemplate> Definition();
		static std::unique_ptr<NativeModuleHandle> New(v8::Local<v8::String> value);
		std::unique_ptr<Transferable> TransferOut() final;
};

} // namespace catbox
